Thread: stdarg - say function.

  1. #1
    Registered User Vber's Avatar
    Join Date
    Nov 2002
    Posts
    807

    stdarg - say function.

    Hello, I'm trying to make a function let's say, say() that will receives just strings and I'll print them.

    I have this code right now:
    Code:
    #include <stdio.h>
    #include <stdarg.h>
    #include <stdlib.h>
    
    void say (char *msg, ...) {
    	va_list ap;
    	va_start(ap,msg);
    
    	while(*msg) {
    		printf("%s\n",va_arg(ap,char *));
    		msg++;
    	}
    
    	va_end(ap);
    }
    
    int main(void) {
    	say("lala","lele","lili","lolo");
    	return 0;
    }
    But he have's a lot of problems, he don't print the first parameter (msg) and at the end he prints <null>, well....

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    You need a way to tell say() how many variable arguments there are, perhaps something like this:
    Code:
    #include <stdio.h>
    #include <stdarg.h>
    #include <stdlib.h>
    
    void say (int n_msg, ...) {
      va_list ap;
      va_start(ap,n_msg);
    
      while(n_msg-- > 0)
        printf("%s\n",va_arg(ap,char *));
    
      va_end(ap);
    }
    
    int main(void) {
      say(4,"lala","lele","lili","lolo");
    
      return 0;
    }
    -Prelude
    My best code is written with the delete key.

  3. #3
    Registered User Vber's Avatar
    Join Date
    Nov 2002
    Posts
    807
    Ok Prelude, I undestood this after reading 10 times the man, now the main idea was to "import" the function join of perl, now it works fine with unknown number of parameters.

    //You need a way to tell say() how many variable arguments there are

    Well, in my example that I'll give now, I don't need (if I understood you right), I just need to pass the first parameter, and after this those macros (va) will make the job.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    
    char *join (char ch, ...) {
    	char *buf,*s;
    	int i = 0, j = 0;
    	
    	va_list ap;
    	va_start(ap,ch);
    
    
    	//alocatte memory
    	if ((buf = (char *) malloc(1000 * sizeof(*buf))) == NULL) {
    		printf("Could not allocate memory\n");
    		exit(1);
    	}
    
    	while(s = va_arg(ap,char*)) {
    		for (j = 0; s[j]; j++)
    			buf[i++] = s[j];
    		buf[i++] = ch;
    	}
    
    	buf[--i] = '\0'; //delete the last ':' occurence and add \0
    	
    	return buf;
    }
    
    int main(void) {
    	char *test;
    
    	test = join(':',"lele","loli","loaaa","sshshsh");
    	printf("%s\n",test);
    	free(test);
    	return 0;
    }
    Thank you very much for your help. Another question, I'm allocating a lot of space, this is a little bit exagerous, maybe there is a way to allocate the correct space I need, something like, sizeof all the parameters?

  4. #4
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >I'm allocating a lot of space, this is a little bit exagerous, maybe there is a way to allocate the correct space I need, something like, sizeof all the parameters?
    Since the function doesn't know ahead of time how many parameters there are or what size they are, this is not really possible unless you also pass the total size along as a parameter as well. However, you can realloc your memory for every new parameter that va_arg returns.

    >while(s = va_arg(ap,char*)) {
    This won't work as you expect, if there's no argument to return, the result is undefined. So you must have a way to tell how many arguments there are:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdarg.h>
    
    char *join (int n_arg, char ch, ...) {
      char *buf = NULL, *hold,*s;
      int i = 0, j = 0;
      
      va_list ap;
      va_start(ap,ch);
    
      while(n_arg-- > 0) {
        s = va_arg(ap, char *);
    
        hold = realloc ( buf, i + strlen ( s ) + 2 );
    
        if ( hold == NULL )
          ; /* Handle the error */
    
        buf = hold;
    
        for (j = 0; s[j]; j++)
          buf[i++] = s[j];
    
        buf[i++] = ch;
      }
    
      buf[--i] = '\0'; //delete the last ':' occurence and add \0
      
      return buf;
    }
    
    int main(void) {
      char *test;
    
      test = join(4,':',"lele","loli","loaaa","sshshsh");
      printf("%s\n",test);
      free(test);
    
      return 0;
    }
    C isn't as flexible as Perl when it comes to strings, and the Perl string mechanism is far more complex than a simple nul terminated array, so don't expect as convenient a solution unless you're willing to define your own strings like Perl does.

    -Prelude
    My best code is written with the delete key.

  5. #5
    Registered User Vber's Avatar
    Join Date
    Nov 2002
    Posts
    807
    Thank you

  6. #6
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    Damn, two threads ? I put another method on the other thread (no need to count the args).
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Seg Fault in Compare Function
    By tytelizgal in forum C Programming
    Replies: 1
    Last Post: 10-25-2008, 03:06 PM
  2. Another syntax error
    By caldeira in forum C Programming
    Replies: 31
    Last Post: 09-05-2008, 01:01 AM
  3. In over my head
    By Shelnutt2 in forum C Programming
    Replies: 1
    Last Post: 07-08-2008, 06:54 PM
  4. Including lib in a lib
    By bibiteinfo in forum C++ Programming
    Replies: 0
    Last Post: 02-07-2006, 02:28 PM
  5. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM