14
char * myFunction () {

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

} 

void main () {

    char *str;
    str = myFunction();

}

error:return from incompatible pointer type

thanks

friends
  • 589
  • 5
  • 10
  • 16

9 Answers9

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

Narek
  • 20
  • 6
Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87
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 ) );
    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?

Community
  • 1
  • 1
Thomas E
  • 3,808
  • 2
  • 20
  • 13
  • 1
    Instead of the `malloc` and `strcpy` for each string, you could instead use `strdup` – Joakim Jan 29 '14 at 11:14
  • 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`. – NaijaProgrammer Nov 11 '19 at 15:43
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 );
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**.

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
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.

Hamidreza Soleimani
  • 2,504
  • 16
  • 19
  • Thanks for your skeleton for how to allocate array of string and free the array of the string. It is very helpful for me. – charles.cc.hsu Mar 06 '17 at 03:43
  • this implementation will cause memory corruption due to malloc(sizeof(array_t*)); it should be malloc(sizeof(array_t)); (no star). – Serge Jun 01 '18 at 01:47
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.

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • 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". – Vovanium Nov 03 '10 at 11:51
  • @Vivanium: Dynamic pointers in C? And `strdup()` isn't even in the standard library... – DevSolar Nov 03 '10 at 12:35
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;
}
Ali
  • 1
  • 2
  • 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. – Tim Diekmann May 28 '18 at 12:31
-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

omyoo7
  • 1
  • 1
  • 1
    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". – Simon F Sep 07 '18 at 08:13
  • 1
    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 – omyoo7 Sep 07 '18 at 08:49
  • The link *is* good to have, and I did like it. Just suggesting the supporting text was also needed 8D – Simon F Sep 07 '18 at 16:53
-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.

andy.xyz
  • 2,567
  • 1
  • 13
  • 18
Sid
  • 1