C Challenge #1

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

Post Reply
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

C Challenge #1

Post 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.
Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
User avatar
Amarant
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 34
Joined: Wed Nov 05, 2008 9:52 am

Re: C Challenge #1

Post 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;
}
177
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: C Challenge #1

Post by Falco Girgis »

Amarant did everything exactly as I would have.
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

Re: C Challenge #1

Post 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.
Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
User avatar
Amarant
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 34
Joined: Wed Nov 05, 2008 9:52 am

Re: C Challenge #1

Post 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.
177
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

Re: C Challenge #1

Post 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;
	}

Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
User avatar
Amarant
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 34
Joined: Wed Nov 05, 2008 9:52 am

Re: C Challenge #1

Post 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.
177
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

Re: C Challenge #1

Post 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.
Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
Post Reply