tags:

views:

80

answers:

5

C is always pretty awkward with strings, but it's usually okay to just allocate a char array of size 256 for your string and be on with it.

However, what if you want the function to return a string and you don't know the size, since you will be concatenating strings together dozens or hundreds of times? Obviously something like this won't work:

char * my_function(int n, char *string){
    if (n < 20) {
        return string;
    }
    else {
        char *new_string = "abcdefghijklmnop";
        strcat(string, new_string);
        return my_function(n--, string);
    }
}

So how is this handled in c?

A: 

You would want to use something like this:

void my_function ( ..., char ** result )
{
    // decide how many bytes...

    // Allocate enough memory.
    (*result) = malloc(number_of_bytes);

    // Fill the buffer...
}
André Caron
+4  A: 

The most straightforward way to do a function that concatenates an arbitrary number of strings is to:

  1. Loop through all of the strings and add up their strlen().
  2. malloc() for the total length.
  3. Do all of the concatenation within the malloc'd string and then return it.
Reinderien
+3  A: 

Your first paragraph makes some very bad assumptions. I hope you're not really doing that.

In any case, the general solution is to use dynamic allocation everywhere and constantly reallocate. However, this is inefficient, and a better approach may be to change the assumption that you want to concatenate strings at all (much less hundreds of times) and instead construct your strings with snprintf in a single operation. Then you can compute the required size first, and you have the option of allocating it or just using a fixed-size buffer in which the output might get truncated.

R..
+1  A: 

There are a couple common ways you can handle returning strings where the ultimate size is unknown:

  • you make the caller responsible for passing in a buffer for the result that will be large enough to hold the result. I f you do this, you should require that the caller also pass in the size of the buffer so you can return an error if the result will be too large instead of overrunning the buffer (ie., follow snprintf()'s example instead of sprintf()'s).

  • you can allocate the memory for the result dynamically, and make the caller responsible for freeing the memory

A couple (untested) examples for you my_function():

#include <string.h>
#include <stdlib.h>

/*
  create new string in a dynamically allocated buffer
 */
char * my_function1(int n, char *s1)
{
    static char const new_string[] = "abcdefghijklmnop";

    int sz = strlen(s1) + (n * strlen(new_string)) + 1;

    char* result = malloc(sz);

    if (result) {
        strcpy(result, s1);

        while (n--) {
            strcat(result, new_string);
        }
    }

    return result;
}


/*
  create new string in a caller provided buffer
 */
int my_function2(int n, char *s1, char* buf, int buf_size)
{
    static char const new_string[] = "abcdefghijklmnop";

    int sz = strlen(s1) + (n * strlen(new_string)) + 1;

    if (sz > buf_size) {
        return -1; /* error */
    }

    strcpy(buf, s1);

    while (n--) {
        strcat(buf, new_string);
    }

    return sz-1; /* characters in result */
}
Michael Burr
A: 

There's a way to add on strings of any length to your original string, using realloc. You don't need to know the final length of the string here.

I assume you can safely modify your declaration / initialization of the passed argument string in the calling function to be:

char * string = calloc( 0, sizeof(char) ); 

Replace 0 by whatever size the string initially is, plus 1 for the terminating NULL.

Change your function to:

 char * my_function(int n, char *string){
    if (n < 20) {
        return string;
    }
    else 
    {
        char *new_string = "abcdefghijklmnop";
        if( (temp = realloc(string, strlen(new_string)+ strlen(string) + 1)) == NULL )
        { 
          printf("Memory allocation error"); 
          exit(1); 
        }
        strcat(string, new_string);
        return my_function(n--, string);
    }
}
Kedar Soparkar