14
char * myFunction () {

    char sub_str[10][20]; 
    return sub_str;

} 

void main () {

    char *str;
    str = myFunction();

}

error:return from incompatible pointer type

thanks

0

9 Answers 9

25

A string array in C can be used either with char** or with char*[]. However, you cannot return values stored on the stack, as in your function. If you want to return the string array, you have to reserve it dynamically:

char** myFunction() {
    char ** sub_str = malloc(10 * sizeof(char*));
    for (int i =0 ; i < 10; ++i)
        sub_str[i] = malloc(20 * sizeof(char));
    /* Fill the sub_str strings */
    return sub_str;
}

Then, main can get the string array like this:

char** str = myFunction();
printf("%s", str[0]); /* Prints the first string. */

EDIT: Since we allocated sub_str, we now return a memory address that can be accessed in the main

Sign up to request clarification or add additional context in comments.

6 Comments

so the function line have to change to char ** myFunction () { ?
Just remember to free all the elements later (on the calling function).
@DiegoSevilla Can't you malloc outside of the function and use the address of the pointer (to malloc) as argument?
@aerijman, of course, this is another possibility.
great explanation. do not forget to add free(str); after using the function to free the memory space on the heap allocated with malloc()
|
8

To programmers just starting out, the concept of a "stack" or the "heap" might be a little confusing, especially if you have started programming in a higher level language like Ruby, Java, Python, etc.

Consider:

char **get_me_some_strings() {
  char *ary[] = {"ABC", "BCD", NULL};
  return ary;
}

The compiler will rightfully issue a complaint about trying to return address of a local variable, and you will most certainly get a segmentation fault trying to use the returned pointer.

and:

char **get_me_some_strings() {
  char *ary[] = {"ABC", "BCD", NULL};
  char **strings = ary;
  return strings;
}

will shut the compiler up, while still getting the same nasty segmentation fault.

To keep everyone but the zealots happy, you would do something a little more elaborate:

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

char **get_me_some_strings() {
  char *ary[] = { "ABC", "BCD", NULL };
  char **strings = ary; // a pointer to a pointer, for easy iteration
  char **to_be_returned = malloc(sizeof(char*) * 3);
  int i = 0;
  while(*strings) {
    to_be_returned[i] = malloc( sizeof(char) * strlen( *strings ) + 1 ); // +1 for the terminating null character
    strcpy( to_be_returned[i++], *strings);
    strings++;
  }
  return to_be_returned;
}

now use it:

void i_need_me_some_strings() {
  char **strings = get_me_some_strings();
  while(*strings) {
    printf("a fine string that says: %s", *strings);
    strings++;
  }
}

Just remember to free the allocated memory when you are done, cuz nobody will do it for you. That goes for all the pointers, not just the pointer to the pointers! (i think).

To make more sense of it all, you might also want to read this: What and where are the stack and heap?

4 Comments

Instead of the malloc and strcpy for each string, you could instead use strdup
I wish I could up-vote this more than once, it just saved me from a nasty segmentation fault error after days of wondering what the problem was. I only have to add that you need to account for the terminating null character of strcpy. So, the line to_be_returned[i] = malloc( sizeof(char) * strlen( *strings ) ); should read: to_be_returned[i] = malloc( sizeof(char) * strlen( *strings ) + 1); Notice the + 1.
note: strdup only became standard in C23, so it may not be a part of your toolbox.
@NaijaProgrammer, sizeof(char) * strlen( *strings ) + 1 is conceptually wrong. Should be sizeof(char) * (strlen( *strings ) + 1), yet makes no math difference as sizeof(char) == 1.
2

Reason:
you need the return type to be char(*)[20]. But even in this case you don't want to return a pointer to a local object from the function.
Do:
Use malloc to allocate sub_str, and return char**.

Comments

2

The cause of your compiler error is simple, but not the answer to what you really want to do. You are declaring that the function returns a char *, while returning a char **.

Without knowing the details of what you're doing, I'm going to assume one of two things are true:

1) The purpose of the function is to create and return an array of strings. 2) The function performs some operation(s) on an array of strings.

If #1 is true, you need several malloc calls to make this work (It can really be done with only two, but for purposes of simplicity, I'll use several).

If you don't know how large the array is supposed to be, your function declaration should look like this:

char ** allocateStrings ( int numberOfStrings, int strLength );

The reason for this is because you're essentially returning a pointer to an array of pointers and you need to know how many strings and how long each string is.

char ** allocateStrings ( int numberOfStrings, int strLength )
{
    int i;

    //The first line is allocating an array of pointers to chars, not actually allocating any strings itself
    char ** retVal = ( char ** ) malloc ( sizeof ( char * ) * numberOfStrings );

    //For each string, we need to malloc strLength chars
    for ( i = 0; i < numberOfStrings; i ++ )
    {
        //Allocate one extra char for the null pointer at the end
        retVal [ i ] = ( char * ) malloc ( sizeof ( char ) * ( strLength + 1 ) );
    }

    return retVal;
}

As somebody else pointed out, it's best practice to have whatever does the allocating also do the deallocating. So a cleanup function is needed.

void cleanupStrings ( char ** strArray, int numberOfStrings )
{
    int i;

    for ( i = 0; i < numberOfStrings; i ++ )
    {
        //Should be checking to see if this is a null pointer.
        free ( strArray [ i ] );
    }

    //Once the strings themselves are freed, free the actual array itself.
    free ( strArray );
}

Now, keep in mind that once the cleanup function is called, you no longer have access to the array. Trying to still use it will most likely cause your application to crash.

If #2 is true, then you want to allocate the strings, process the strings, and clean them up. You should use the two functions above to allocate/deallocate your strings, then a third function to do whatever with them.

void processStrings ( char ** strArray, int numberOfStrings, int strLength );

Comments

1

As others have said, you cannot return a local char array to the caller, and have to use heap memory for this.

However, I would not advise using malloc() within the function.

Good practice is that, whoever allocates memory, also deallocates it (and handles the error condition if malloc() returns NULL).

Since your myFunction() does not have control over the memory it allocated once it returned, have the caller provide the memory in which to store the result, and pass a pointer to that memory.

That way, the caller of your function can de-allocate or re-use the memory (e.g. for subsequent calls to myFunction()) however he sees fit.

Be careful, though, to either agree on a fixed size for such calls (through a global constant), or to pass the maximum size as additional parameter, lest you end up overwriting buffer limits.

2 Comments

Returning or not returning allocated memory is a matter of convention. One convention is one you said. Another one is to use dynamic pointers whenever possible (and strdup() string literals), so last pointer "user" will always free it. Through it more complex, convention avoids many buffer overflows, overusing stack space and much more thread safe than using "static".
@Vivanium: Dynamic pointers in C? And strdup() isn't even in the standard library...
1

As others correctly said you should use dynamic memory allocation by malloc to store your array inside heap and return a pointer to its first element.

Also I find it useful to write a simple array of string implementation which has a minimal API for data manipulation.

Type and API:

typedef struct {
  char **array_ptr;
  int array_len;
  int string_len;
} array_t;

array_t* array_string_new(int array_len, int string_len);
int array_string_set(array_t *array, int index, char *string);
char* array_string_get(array_t *array, int index);
int array_string_len(array_t *array);

Usage:

It creates an array with 4 dimensions that can store strings with 4 characters length. If the string length goes beyond the specified length, just its first 4 characters will be stored.

int main()
{
  int i;
  array_t *array = array_string_new(4, 4);

  array_string_set(array, 0, "foo");
  array_string_set(array, 1, "bar");
  array_string_set(array, 2, "bat");
  array_string_set(array, 3, ".... overflowed string");

  for(i = 0; i < array_string_len(array); i++)
    printf("index: %d - value: %s\n", i, array_string_get(array, i));

  /* output:

     index: 0 - value: foo
     index: 1 - value: bar
     index: 2 - value: bat
     index: 3 - value: ...

  */

  array_string_free(array);

  return 0;
}

Implementation:

array_t*
array_string_new(int array_len, int string_len)
{
  int i;
  char **array_ptr = (char**) malloc(array_len * sizeof(char**));

  for(i = 0; i < array_len; i++) {
    array_ptr[i] = (char*) malloc(string_len * sizeof(char));
  }

  array_t *array = (array_t*) malloc(sizeof(array_t*));
  array->array_ptr = array_ptr;
  array->array_len = array_len;
  array->string_len = string_len;

  return array;
}

int
array_string_set(array_t *array, int index, char *string)
{
  strncpy(array->array_ptr[index], string, array->string_len);
  return 0;
}

char*
array_string_get(array_t *array, int index)
{
  return array->array_ptr[index];
}

int
array_string_len(array_t *array)
{
  return array->array_len;
}

int
array_string_free(array_t *array)
{
  int i;
  for(i = 0; i < array->array_len; i++) {
    free(array->array_ptr[i]);
  }
  free(array->array_ptr);
  return 0;
}

Notice that it is just a simple implementation with no error checking.

2 Comments

Thanks for your skeleton for how to allocate array of string and free the array of the string. It is very helpful for me.
this implementation will cause memory corruption due to malloc(sizeof(array_t*)); it should be malloc(sizeof(array_t)); (no star).
0

i use that function to split a string to string array

char  ** split(char *str, char *delimiter)
{
    char *temp=strtok(str,delimiter);
    char *arr[]={temp};
    int i=0;

    while(true)
    {
       elm=strtok (NULL, delimiter);

       if(!temp) break;

       arr[++i]=temp;
    }

    return arr;
}

1 Comment

Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others.
-1

first of all You can not return a string variable which is stored in stack you need use malloc to allocate memory dynamicaly here is given datails with the example Go https://nxtspace.blogspot.com/2018/09/return-array-of-string-and-taking-in-c.html get a proper answer

3 Comments

Ideally you should include a little bit of the explanation of why it is bad and then explain that a "malloc" is required, not just provide a link to another site which may disappear with "bit rot".
I appreciate but I think people need to understand with example not by word that's why I gave this link, and if you did not like, it's Ok. @SimonF
The link is good to have, and I did like it. Just suggesting the supporting text was also needed 8D
-3
char *f()
{   
    static char str[10][20];

    // ......

    return (char *)str;
}

int main()
{

    char *str;
    str = f();

    printf( "%s\n", str );

    return 0;
}

You can use static instead of malloc. It's your choice.

2 Comments

It is bad advice to cast away complaints from the compiler. Especially when there is a clean way to write the code without the cast.
Very bad advice and this line is just plain wrong: printf( str, "%s\n");

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.