How to restrict variadic function data types? (using stdarg.h on linux)

This is a discussion on How to restrict variadic function data types? (using stdarg.h on linux) within the C Programming forums, part of the General Programming Boards category; I want the compiler to throw an error when strbuild()'s variadic arguments are anything except the range data type. How ...

  1. #1
    Registered User
    Join Date
    Dec 2011
    Posts
    13

    How to restrict variadic function data types? (using stdarg.h on linux)

    I want the compiler to throw an error when strbuild()'s variadic arguments are anything except the range data type. How would this be achieved?

    Code:
    char * strbuild(int num, ...){
        va_list ap;
        range tmp;
        int i = 0;
        char * str = malloc(sizeof(char));
        
        va_start(ap, num);
        for(; num > 0; num--){
            tmp = va_arg(ap, range);
            if(tmp.min >= tmp.max)
                return NULL;
            
            str = realloc(str, strlen(str) + (tmp.max - tmp.min) );
            for(; tmp.min <= tmp.max; tmp.min++, i++)
                str[i] = tmp.min;
        }
        str[i + 1] = '\0';
        
        va_end(ap);
        return str;
    }

  2. #2
    Registered Boozer
    Join Date
    Jan 2008
    Location
    Canada
    Posts
    1,724
    I don't think that's possible. If you describe what you're up to we might be able to suggest a better approach.

    Your for loop is more usually written:
    Code:
    while (num-- > 0)
    Your return NULL statement should be
    Code:
    {
        if (str) free(str);
        va_end(ap);
        return NULL;
    }
    And you should set the single char you've initially allocated to str to zero so strlen works properly.

    And don't you need to add tmp.max-tmp.min+2 bytes to the string length to hold the range plus ascii nul?

    And you actually want
    Code:
    str[i] = 0;
    not i + 1, since i will have been advanced by the i++ of the loop.

    Also, technically the name strbuild is reserved (since it starts with str and has another lowercase letter after that).
    Last edited by oogabooga; 07-18-2012 at 07:14 PM. Reason: added free(str)
    The human mind treats a new idea the way the body treats a strange protein; it rejects it. - P.B.Medawar

  3. #3
    Registered User
    Join Date
    Dec 2011
    Posts
    13
    Alright, but about the last one where you said it shouldn't be i + 1, why is that?

    I want it to be i + 1 after the last time for loops so it doesn't overwrite that character, right?

    Also, why + 2 bytes instead of just + 1?

    Next, my function is supposed to build a string that has all the ascii characters between min and max, and needs to support different ranges.
    Last edited by XenoReseller; 07-18-2012 at 07:20 PM.

  4. #4
    Registered Boozer
    Join Date
    Jan 2008
    Location
    Canada
    Posts
    1,724
    It shouldn't be + 1 because the i ++ of the loop will have already incremented i to point past the last char.

    If the range is 'a' to 'd' and you mean that to represent abcd (as opposed to abc) then you need to add 1 just for that ('d' - 'a' is 3, but you want 4), plus another 1 for the nul.


    PS to the people who run the board: THIS IS ANNOYING!!!
    Please use code tags: insert [code] before your source code and [/code] after it in order to post. See Posting Code - Read this First for more information.
    Maybe you could suppress it for people with more than 20 or so posts.
    The human mind treats a new idea the way the body treats a strange protein; it rejects it. - P.B.Medawar

  5. #5
    Registered User
    Join Date
    Dec 2011
    Posts
    13
    Okay, by switching NUL to a visible character I found that str[i] is + 1 from the last letter. So, I see that now.

    Still, without + 2 or even + 1 It lets me print all the characters + the NUL.

    For instance, I realloc with the original code, but with a visible character for NUL and the range '0' to '9' it prints 0123456789- (I substituted the NUL with '-' in this case)

    Also, when I initialized str after I malloc it the first time, it causes a segfault when it gets to realloc according to gdb.

    Thanks for the help. Here is the current code, if you run it, you'll see that even without + 2 it prints all the expected characters + a NUL.

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #include <stdlib.h>
    #include <stdarg.h>
    
    typedef struct asciirange_t {
        short min;
        short max;
    } range;
    
    char * strBuild(int num, ...){
        va_list ap;
        range tmp;
        int i = 0;
        char * str = malloc(sizeof(char));
        
        va_start(ap, num);
        
        while(num-- > 0){
            tmp = va_arg(ap, range);
            
            if(tmp.min > tmp.max){
                if(str)
                    free(str);
                va_end(ap);
                return NULL;
            }
            
            str = realloc(str, strlen(str) + (tmp.max - tmp.min) );
            
            for(; tmp.min <= tmp.max; tmp.min++, i++)
                str[i] = tmp.min;
        }
        str[i] = 0;
        
        va_end(ap);
        return str;
    }
    
    int main(){
        char * str;
    
        range a, b, c;
        a.min = '0'; a.max = '9';
        b.min = 'a'; b.max = 'z';
        c.min = 'A'; c.max = 'Z';
        str = strBuild(3, a, b, c);
        
        printf("%s\n", str);
    
        free(str);
        return 0;
    }

  6. #6
    Registered Boozer
    Join Date
    Jan 2008
    Location
    Canada
    Posts
    1,724
    Still, without + 2 or even + 1 It lets me print all the characters + the NUL
    If you don't have the +2 then you haven't allocated enough space, and the data will overrun the space you've set aside. However, it may still seem to work, until you add more to your program and an error appears SOMEWHERE ELSE! That's hard to debug.

    Also, when I initialized str after I malloc it the first time, it causes a segfault when it gets to realloc according to gdb
    Sounds like you might have set str itself to 0. I meant something like this:
    Code:
    char *str = malloc(1);
    *str = 0;
    Although, now that I think about it, doesn't realloc accept a NULL argument as its first argument (in which case it acts like malloc)? In that case, you could do this:
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdarg.h>
    
    typedef struct asciirange_t {
        int min;
        int max;
    } range;
    
    char *buildstr(int num, ...){
        va_list ap;
        range tmp;
        int i = 0;
        char *str = NULL;
        
        va_start(ap, num);
        
        while (num-- > 0){
            tmp = va_arg(ap, range);
            
            if (tmp.min > tmp.max){
                if (str)
                    free(str);
                va_end(ap);
                return NULL;
            }
            
            str = realloc(str, i + tmp.max - tmp.min + 2 );
            
            while (tmp.min <= tmp.max)
                str[i++] = tmp.min++;
        }
        str[i] = 0;
        
        va_end(ap);
        return str;
    }
    
    int main(){
        range a={'0','9'}, b={'a','z'}, c={'A','Z'};
        char *str = buildstr(3, a, b, c);
        if (!str)
            printf("Bad argument!\n");
        else {
            printf("%s\n", str);
            free(str);
        }
        return 0;
    }
    The human mind treats a new idea the way the body treats a strange protein; it rejects it. - P.B.Medawar

  7. #7
    Registered User
    Join Date
    Dec 2011
    Posts
    13
    Yeah, you're right. Also my friend reminded me of granularity...So I get it now, he also mentioned it's probably too costly to keep mallocing and he said that realloc should only be used to shrink. Anyways, thanks very much.

  8. #8
    Registered Boozer
    Join Date
    Jan 2008
    Location
    Canada
    Posts
    1,724
    I disagree that realloc should only be used to shrink allocated memory!

    However, in your case you could pre-calculate your memory needs.
    Code:
    va_start(...);
    // go through ranges and add up the needed memory
    va_end();
    
    va_start(...);
    // allocate and write to the memory
    va_end();
    The human mind treats a new idea the way the body treats a strange protein; it rejects it. - P.B.Medawar

  9. #9
    Registered User
    Join Date
    Dec 2011
    Posts
    13
    Oh, I had considered that idea, but for some reason I thought it didn't work like that. Anyways, I don't know his grounds for saying that, but he's always led me in the right direction.<br><br>Here is the new code, based on your help. Thank you.<br>[CODE]<br>#include &lt;stdio.h&gt;<br>#include &lt;string.h&gt;<br>#include &lt;stdlib.h&gt;<br>#include &lt;stdarg.h&gt;<br>&nbsp;<br>typedef struct asciirange_t {<br>&nbsp;&nbsp; &nbsp;int min;<br>&nbsp;&nbsp; &nbsp;int max;<br>} range;<br>&nbsp;<br>char *buildstr(int num, ...){<br>&nbsp;&nbsp; &nbsp;va_list ap;<br>&nbsp;&nbsp; &nbsp;range tmp;<br>&nbsp;&nbsp; &nbsp;int i = num, size = 0;<br><br>&nbsp;&nbsp; &nbsp;va_start(ap, num);<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while(num-- &gt; 0){<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;tmp = va_arg(ap, range);<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;size += (tmp.max - tmp.min) + 1;<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char *str = malloc(size + 1);<br>&nbsp;&nbsp; &nbsp;va_end(ap);<br>&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp; &nbsp;num = i; i = 0;<br>&nbsp;&nbsp; &nbsp;va_start(ap, num);<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while (num-- &gt; 0){<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;tmp = va_arg(ap, range);<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; <br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (tmp.min &gt; tmp.max){<br>%2
    Last edited by XenoReseller; 07-18-2012 at 09:15 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Variadic function
    By Richardcavell in forum C Programming
    Replies: 17
    Last Post: 03-01-2011, 12:34 AM
  2. Writing own printf function without using stdarg.h
    By osfreak in forum C Programming
    Replies: 9
    Last Post: 09-05-2010, 04:16 PM
  3. How can I restrict fread()´s data?
    By Subsonics in forum C Programming
    Replies: 14
    Last Post: 01-10-2009, 05:34 AM
  4. function that takes diff data types as paramter
    By nepdude in forum C Programming
    Replies: 7
    Last Post: 07-06-2007, 01:47 PM
  5. stdarg - say function.
    By Vber in forum C Programming
    Replies: 5
    Last Post: 03-23-2003, 04:26 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21