Page 1 of 1

C Challenge #1

Posted: Tue Nov 04, 2008 10:30 pm
by avansc
write a funtion in C, that will take any number of strings or char* arguments, concatenate them, malloc memory and return the pointer to the new string.
this is a very useful tool, and i suggest doing this, just so you know how to.

ps: ever wonder why printf can take variable length arguments.
hint: its not a bunch of over ridden functions.

Re: C Challenge #1

Posted: Wed Nov 05, 2008 4:06 pm
by Amarant
This was a pretty interesting 'challenge', I knew how printf worked but had never created a function like this before...
I'd like to know what your approach to something like this would be, if it's any different at all.

Here's the code:

Code: Select all

#include <stdarg.h> //va_list etc..
#include <stdio.h> //printf
#include <stdlib.h> //malloc
#include <string.h> //memcpy, strlen

/*
* @param amount The amount of null terminated character arrays that
*               should be concatenated.
* @param ...    Variable length list of char * to null terminated 
*               character arrays.
*/
char * my_concat(int amount, ...)
{
    int i = 0;
    int totalSize = 0;
    int * lengths = (int*)malloc(amount);
    char * concatenate = 0;
    va_list vl;

    // First calculate the total size of the end product
    // by summing up the lengths of the individual parts
    // whilst storing these lengths for fast lookup
    va_start(vl, amount);
    for(i = 0; i < amount; i++)
    {
        lengths[i] = strlen(va_arg(vl, char*));
        totalSize += lengths[i];
    }
    va_end(vl);

    // Then create a container for the end product using
    // the size that was just calculated, +1 (for termination)
    concatenate = (char*)malloc(sizeof(char) * (totalSize+1));
 
    // Copy the individual parts into the container
    va_start(vl, amount);
    for(i = 0; i < amount; i++)
    {
        char * arg = va_arg(vl, char*);
        memcpy(concatenate, arg, lengths[i]);
        concatenate += lengths[i]; 
    }
    va_end(vl);
    free(lengths);
   
    // Append the termination character
    *concatenate = '\0';

    // Restore the pointer to its original location and return
    return concatenate - totalSize; 
}

int main(int argc, char * argv[])
{
    char * mystring = my_concat(4,"Do not ","enter ","the wrong amount", " of strings!");
    printf("%s\n", mystring);
    free(mystring);  
    return 0;
}

Re: C Challenge #1

Posted: Wed Nov 05, 2008 4:08 pm
by Falco Girgis
Amarant did everything exactly as I would have.

Re: C Challenge #1

Posted: Wed Nov 05, 2008 4:26 pm
by avansc
nide, except that you dont need the count, you just need it in this format

char *concatSTR(char *first, ....).

so there are better ways of doing it, but you are on the right track.

Re: C Challenge #1

Posted: Wed Nov 05, 2008 4:44 pm
by Amarant
Unless you're using an entirely different mechanism I don't see how that would work.
The documentation for the va_arg function states the following:
Notice also that va_arg does not determine either whether the retrieved argument is the last argument passed to the function (or even if it is an element past the end of that list). The function should be designed in such a way that the amount of parameters can be inferred in some way by the values of either the named parameters or the additional arguments already read.
An alternative I had already thought up involved terminating the call to the concat method with a 0 value, so that it would look like this:

Code: Select all

concat("a", "b", "c", 0);
It would certainly be more user friendly and less error prone, but the implementation would have gotten a little bit more complicated so I chose not to do it.
Also even printf fails to detect situations where the amount of arguments is too low, and crashes as a result of a segmentation error.

Re: C Challenge #1

Posted: Wed Nov 05, 2008 5:04 pm
by avansc
Amarant wrote:Unless you're using an entirely different mechanism I don't see how that would work.
The documentation for the va_arg function states the following:
Notice also that va_arg does not determine either whether the retrieved argument is the last argument passed to the function (or even if it is an element past the end of that list). The function should be designed in such a way that the amount of parameters can be inferred in some way by the values of either the named parameters or the additional arguments already read.
An alternative I had already thought up involved terminating the call to the concat method with a 0 value, so that it would look like this:

Code: Select all

concat("a", "b", "c", 0);
It would certainly be more user friendly and less error prone, but the implementation would have gotten a little bit more complicated so I chose not to do it.
Also even printf fails to detect situations where the amount of arguments is too low, and crashes as a result of a segmentation error.
in this function you have to add the (char*)NULL, but you can easily surpass that by just doing inside the function.

Code: Select all

#include <stdlib.h>		/* for malloc, NULL, size_t */
	#include <stdarg.h>		/* for va_ stuff */
	#include <string.h>		/* for strcat et al */

	char *vstrcat(char *first, ...)
	{
		size_t len = 0;
		char *retbuf;
		va_list argp;
		char *p;

		if(first == NULL)
			return NULL;

		len = strlen(first);

		va_start(argp, first);

		while((p = va_arg(argp, char *)) != NULL)
			len += strlen(p);

		va_end(argp);

		retbuf = malloc(len + 1);	/* +1 for trailing \0 */

		if(retbuf == NULL)
			return NULL;		/* error */

		(void)strcpy(retbuf, first);

		va_start(argp, first);

		while((p = va_arg(argp, char *)) != NULL)
			(void)strcat(retbuf, p);

		va_end(argp);

		return retbuf;
	}


Re: C Challenge #1

Posted: Wed Nov 05, 2008 5:12 pm
by Amarant
Ah yes that's pretty much what I had in mind, except for the mistake I made with passing 0 instead of (char*)NULL.

Re: C Challenge #1

Posted: Wed Nov 05, 2008 5:14 pm
by avansc
Amarant wrote:Ah yes that's pretty much what I had in mind, except for the mistake I made with passing 0 instead of (char*)NULL.
yeah you did well. i'll post a new challenge in a little bit, gotta think of a juicy one. go look and see if you can figuer the binary challege out.