C: Dynamic string using variable number of arguments

Discussion in 'C' started by negru, Mar 14, 2015.

  1. negru

    negru New Member

    Joined:
    Feb 13, 2015
    Messages:
    4
    Likes Received:
    0
    Trophy Points:
    0
    I need to create dynamic string by given format(%d,%s,%f,%lf,%c) using variable number of arguments in function. This code gives me an error(main.exe has stopped working):

    Code:
    #include<stdio.h>
    #include<stdarg.h>
    #include<string.h>
    #include<stdlib.h>
    
    char *form(char *format,...);
    char *form(char *format,...)
    {
        char *res=(char *)calloc(1,1),val_int[12],*pos_int,*val_str,*pos_str,*val_float,*pos_float,*val_lf,*pos_lf,*val_char,*pos_char;
        va_list args;
        va_start(args,format);
        do
        {
          pos_int=strstr(format,"%d");pos_str=strstr(format,"%s");pos_float=strstr(format,"%f");pos_lf=strstr(format,"%lf");pos_char=strstr(format,"%c");
          if(pos_int && (!pos_str || pos_int < pos_str) && (!pos_float || pos_int < pos_float) &&
             (!pos_lf || pos_int < pos_lf) && (!pos_char || pos_int < pos_char))
          {
            itoa(va_arg(args,int),val_int,10);
            res=(char *)realloc(res,strlen(res)+(pos_int-format)+strlen(val_int)+1);
            strncat(res,format,pos_int-format);
            strcat(res,val_int);
            format=pos_int+2;
          }
          else if(pos_str && (!pos_int || pos_str < pos_int) && (!pos_float || pos_str < pos_float) &&
                  (!pos_lf || pos_str < pos_lf) && (!pos_char || pos_str < pos_char))
          {
             val_str=va_arg(args,char *);
             res=(char *)realloc(res,strlen(res)+(pos_str-format)+strlen(val_str)+1);
             strncat(res,format,pos_str-format);
             strcat(res,val_str);
             format=pos_str+2;
          }
    
          else if(pos_float && (!pos_int || pos_float < pos_int) && (!pos_str || pos_float < pos_str) &&
                  (!pos_lf || pos_float < pos_lf) && (!pos_char || pos_float < pos_char))
          {
             fcvt(va_arg(args,double),val_float,6,0);
             res=(char *)realloc(res,strlen(res)+(pos_float-format)+strlen(val_float)+1);
             strncat(res,format,pos_float-format);
             strcat(res,val_float);
             format=pos_float+2;
          }
    
          else if(pos_lf && (!pos_int || pos_lf < pos_int) && (!pos_str || pos_lf < pos_str) &&
                  (!pos_float || pos_lf < pos_float) && (!pos_char || pos_lf < pos_char))
          {
              ecvt(va_arg(args,double),val_lf,6,0);
              res=(char *)realloc(res,strlen(res)+(pos_lf-format)+strlen(val_lf)+1);
              strncat(res,format,pos_lf-format);
              strcat(res,val_lf);
              format=pos_lf+2;
          }
          else if(pos_char && (!pos_int || pos_char < pos_int) && (!pos_str || pos_char < pos_str) &&
                  (!pos_float || pos_char < pos_float) && (!pos_lf || pos_char < pos_lf))
          {
              val_char=va_arg(args,char *);
              res=(char *)realloc(res,strlen(res)+(pos_char-format)+strlen(val_char)+1);
              strncat(res,format,pos_char-format);
              strcat(res,val_char);
              format=pos_char+2;
          }
        }
        while(pos_int || pos_str || pos_float || pos_lf || pos_char);
        va_end(args);
        res=(char *)realloc(res,strlen(res)+strlen(format)+1);
        strcat(res,format);
        return res;
    }
    
    int main()
    {
        char *s;
        s=form("John is %d years old and has an %c in %s. He is going to school for %lf years.",9,'A',"maths",1.5);
        printf("%s",s);
        free(s);
        return 0;
    }
    I assume the error is in functions(itoa,fcvt,ecvt). Thanks for replies.
     
  2. hobbyist

    hobbyist New Member

    Joined:
    Jan 7, 2012
    Messages:
    141
    Likes Received:
    0
    Trophy Points:
    0
    I'm not familiar with va_args stuff, but I tried something like below, which *seemed* to work for your test string. I didn't post the entire code; it could probably be better optimized, but maybe it can offer an idea.

    HTH

    Code:
    char *form(char *format, ...)
    {
        size_t i = 0, j, len = strlen(format) * 2 + 1; 
        // realloc gives me bad vibes. :P
        char *ret = malloc(len), tmp[33];
        va_list args;
        va_start(args, format); 
    
        if(ret == NULL) return NULL;
    
        memset(ret, 0, len);
    
        while(*fmt)
        {
            if(i < len)
                *(ret + i) = *fmt;
            else 
                break;
    
            if(*fmt == '%')
            {
                switch(*(fmt + 1))
                {
                    case 'd' : sprintf(tmp, "%d", va_args(args, int));
                                 ++fmt;
                               
                                 if(i < len + strlen(tmp))
                                 {
                                     for(j = 0; tmp[j] != '\0'; ++j)
                                         *(ret + i++) = tmp[j];
                                 }
     
                                 --i; // remove extra space
                     break;
    
                     // similar for %c, %f, %s, etc
                    
                     case 'l' :  if(*(fmt + 2) == 'f')
                                  {
                                       sprintf(tmp, "%0.1lf", va_args(args, double));
                                       fmt += 2;
    
                                       if(i < len + strlen(tmp))
                                       {
                                            for(j = 0; tmp[j] != '\0'; ++j)
                                                *(ret + i++) = tmp[j];
                                        }
    
                                        --i;
                                    } // test for ld can be added here  
                     break;  
                 }
             }
    
             ++fmt;
             ++i;
        }
    
        va_end(args); 
        *(ret + i) = 0; 
    
        return ret;
    }
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice