Connecting Tech Pros Worldwide Forums | Help | Site Map

Concatenating strings

Big Brother
Guest
 
Posts: n/a
#1: Sep 2 '07
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);
}


Big Brother
Guest
 
Posts: n/a
#2: Sep 2 '07

re: Concatenating strings


On 2 Sep 2007 at 15:22, Big Brother wrote:
....
Quote:
/* pass 1: count arguments */
for(va_start(ap, s); va_arg(ap,char *); n++)
;
Oops,should be a va_end(ap); here, of course.
Quote:
>
/* pass 2: get lengths */
....

Malcolm McLean
Guest
 
Posts: n/a
#3: Sep 2 '07

re: Concatenating strings



"Big Brother" <anonymous@dev.nullwrote in message
news:slrnfdll9b.c2g.spamoff@nospam.invalid...
Quote:
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);
>
Here you seem to have forgotten the first string in calculating total.
This was hard to spot, because of all the fancy assignments in expressions.
Quote:
/* 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);
}
>
No terminating nul. Also, aren't you copying string t on the first pass?
That's set to NULL at this point.
Quote:
>
free(len);
return r;
}
>
int main()
{
char *s;
s=concat("hello ", "world", " and ", "everyone", " in it!", NULL);
puts(s);
free(s);
}
>
SM Ryan
Guest
 
Posts: n/a
#4: Sep 3 '07

re: Concatenating strings


Big Brother <anonymous@dev.nullwrote:
# 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().

You're free to do whatever you want, but as far as practical code,
if you realloc by a constant factor (say double the string length
every realloc) instead of by a constant amount, the running time
is linear in the the length of the strings for any malloc you're
likely to encounter.

--
SM Ryan http://www.rawbw.com/~wyrmwif/
Death is the worry of the living. The dead, like myself,
only worry about decay and necrophiliacs.
Closed Thread