B
Big Brother
I've been thinking about the seemingly simple task of writing a
va_arg-type function to concatenate arbitarily many strings.
My first thoughts violated the following principles:
1) never calculate the length of a string more than once;
2) never invoke realloc() multiple times if you can make do with a
single malloc().
As a result, I came up with the code below. This avoids the two pitfalls
above, but at the expense of needing three passes through the argument
list, which seems a bit clumsy.
Does anyone have any thoughts on the rights and wrongs of this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
/* Returns the concatenation of the strings supplied as arguments. The
* final argument must be NULL.
* Caller should free() the returned pointer when done.
* In case of allocation failure, NULL is returned.
*/
char *concat(char *s, ...)
{
va_list ap;
unsigned n=1;
size_t *len, total=0;
char *t, *r;
/* pass 1: count arguments */
for(va_start(ap, s); va_arg(ap,char *); n++)
;
/* pass 2: get lengths */
if(!(len=malloc(n * sizeof *len)))
return NULL;
va_start(ap, s);
len[n=0]=strlen(s);
while(t=va_arg(ap, char *))
total+=(len[++n]=strlen(t));
va_end(ap);
/* pass 3: copy strings */
if(r=malloc(total+1)) {
memcpy(r, s, total = *len);
n=1;
for(va_start(ap, s) ; t=va_arg(ap, char *) ; total+=len[n++])
memcpy(r+total, t, len[n]);
va_end(ap);
}
free(len);
return r;
}
int main()
{
char *s;
s=concat("hello ", "world", " and ", "everyone", " in it!", NULL);
puts(s);
free(s);
}
va_arg-type function to concatenate arbitarily many strings.
My first thoughts violated the following principles:
1) never calculate the length of a string more than once;
2) never invoke realloc() multiple times if you can make do with a
single malloc().
As a result, I came up with the code below. This avoids the two pitfalls
above, but at the expense of needing three passes through the argument
list, which seems a bit clumsy.
Does anyone have any thoughts on the rights and wrongs of this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
/* Returns the concatenation of the strings supplied as arguments. The
* final argument must be NULL.
* Caller should free() the returned pointer when done.
* In case of allocation failure, NULL is returned.
*/
char *concat(char *s, ...)
{
va_list ap;
unsigned n=1;
size_t *len, total=0;
char *t, *r;
/* pass 1: count arguments */
for(va_start(ap, s); va_arg(ap,char *); n++)
;
/* pass 2: get lengths */
if(!(len=malloc(n * sizeof *len)))
return NULL;
va_start(ap, s);
len[n=0]=strlen(s);
while(t=va_arg(ap, char *))
total+=(len[++n]=strlen(t));
va_end(ap);
/* pass 3: copy strings */
if(r=malloc(total+1)) {
memcpy(r, s, total = *len);
n=1;
for(va_start(ap, s) ; t=va_arg(ap, char *) ; total+=len[n++])
memcpy(r+total, t, len[n]);
va_end(ap);
}
free(len);
return r;
}
int main()
{
char *s;
s=concat("hello ", "world", " and ", "everyone", " in it!", NULL);
puts(s);
free(s);
}