malloc() and dinamic data question

S

Silas Silva

Hello all!

I'm learning C and I started to get into malloc() and va_* functions
of stdarg.h (va_list, va_arg, va_start, etc). So I wrote the following
program that has a funcion that concatenates strings:

/********** START ***********/
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *concat(int, ...);

int
main(void) {
printf("%s\n", concat(3, "foo ", "bar ", "mubble"));
exit(0);
}

char *
concat(int argc, ...) {
va_list list;
int i;
int size;
char *arg; /* Arguments of the list */
char *stringstart; /* Start address of the string */
char *string; /* String that will receive the values */

va_start(list, argc);
size = 0;

for(i = 0; i < argc; i++) {
arg = va_arg(list, char *);
size += strlen(arg);
}

va_end(list);
va_start(list, argc);
stringstart = string = malloc(size * sizeof(*string));

for(i = 0; i < argc; i++) {
arg = va_arg(list, char *);
strcpy(string, arg);
string += strlen(arg);
}

va_end(list);

return stringstart;
}
/********** END ***********/

My questions are:

1) I suppose it is not possible to get the number of variable
arguments that are going to the passed to the function, so I use an
argc argument. Am I right?

2) To alloc the right size, I scan all the arguments, calculates
theirs size (sizeof) and then I pass the value to the malloc()
function. Is there a smallest way to do that?

Thank you very much!
 
Q

quarkLore

Hello all!

I'm learning C and I started to get into malloc() and va_* functions
of stdarg.h (va_list, va_arg, va_start, etc). So I wrote the following
program that has a funcion that concatenates strings:

/********** START ***********/
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *concat(int, ...);

int
main(void) {
printf("%s\n", concat(3, "foo ", "bar ", "mubble"));
exit(0);

}

char *
concat(int argc, ...) {
va_list list;
int i;
int size;
char *arg; /* Arguments of the list */
char *stringstart; /* Start address of the string */
char *string; /* String that will receive the values */

va_start(list, argc);
size = 0;

for(i = 0; i < argc; i++) {
arg = va_arg(list, char *);
size += strlen(arg);
}

va_end(list);
va_start(list, argc);
stringstart = string = malloc(size * sizeof(*string));

for(i = 0; i < argc; i++) {
arg = va_arg(list, char *);
strcpy(string, arg);
string += strlen(arg);
}

va_end(list);

return stringstart;}

/********** END ***********/

My questions are:

1) I suppose it is not possible to get the number of variable
arguments that are going to the passed to the function, so I use an
argc argument. Am I right?

This creates burden the function caller to pass number of arguments to
the function. If this is supposed to be a reusable module then API
user might landup in a soup if he gives different number of arguments.
Worst the caller can make you run the first loop more than required. I
dont know about internals of va_* but it might make your code
vulnerable and messy.
2) To alloc the right size, I scan all the arguments, calculates
theirs size (sizeof) and then I pass the value to the malloc()
function. Is there a smallest way to do that?

the allocation of memory is wrong it should be: malloc (sizeof(char) *
size)
The calculation of size should have one more character i.e.: size +=
strlen(arg) + 1; as one NULL character's space is needed at the end
 
J

Jonas

quarkLore said:
Yes.



the allocation of memory is wrong it should be: malloc (sizeof(char) *
size)

Allocation is wrong, but not because of the above since
sizeof (*string) == sizeof (char).


The calculation of size should have one more character i.e.: size +=
strlen(arg) + 1; as one NULL character's space is needed at the end

Only one extra byte needs to be allocated, i.e.

stringstart = string = malloc(size * sizeof(*string) + 1);

Using memcpy should be faster than strcpy. To do this you would have to
remember the string lengths as you calculate them in the first loop, and
nul-terminate the string after copying. This will also save you one call to
strlen() for each string. The down side is of course that you need to
allocate memory dynamically to hold the string lengths.
 
A

A. Bolmarcich

Hello all!

I'm learning C and I started to get into malloc() and va_* functions
of stdarg.h (va_list, va_arg, va_start, etc). So I wrote the following
program that has a funcion that concatenates strings:

/********** START ***********/
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *concat(int, ...);

int
main(void) {
printf("%s\n", concat(3, "foo ", "bar ", "mubble"));
exit(0);
}

char *
concat(int argc, ...) {
va_list list;
int i;
int size;
char *arg; /* Arguments of the list */
char *stringstart; /* Start address of the string */
char *string; /* String that will receive the values */

va_start(list, argc);
size = 0;

for(i = 0; i < argc; i++) {
arg = va_arg(list, char *);
size += strlen(arg);
}

va_end(list);
va_start(list, argc);
stringstart = string = malloc(size * sizeof(*string));

for(i = 0; i < argc; i++) {
arg = va_arg(list, char *);
strcpy(string, arg);
string += strlen(arg);
}

va_end(list);

return stringstart;
}
/********** END ***********/

My questions are:

1) I suppose it is not possible to get the number of variable
arguments that are going to the passed to the function, so I use an
argc argument. Am I right?

Another approach is to use a special argument value to indicate that
there are no more arguments, as in

printf("%s\n", concat("foo ", "bar ", "mubble", (char *)0));

The concat function would be defined as

concat(char *arg1, ...)

and the loops over the arguments would be

va_start(list, arg1);
for(arg=arg1; arg != 0; arg=va_arg(list, char*)) {
}
va_end(list);
2) To alloc the right size, I scan all the arguments, calculates
theirs size (sizeof) and then I pass the value to the malloc()
function. Is there a smallest way to do that?

As others have mentioned, you need to add 1 to the malloc size so
there is room for the terminating NUL character.
 
C

Christopher Benson-Manica

Silas Silva said:
2) To alloc the right size, I scan all the arguments, calculates
theirs size (sizeof) and then I pass the value to the malloc()
function. Is there a smallest way to do that?

An alternative, which is easier to code but perhaps (probably?) less
efficient, is to use realloc() to grow the allocated space in steps
for each argument.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

C pipe 1
array-size/malloc limit and strlen() failure 26
Counting Arguments in C99 4
malloc 40
Concatenating strings 5
va_args Conformance 15
Command Line Arguments 0
Fibonacci 0

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top