如何从函数返回一个字符串数组

时间:2010-11-03 08:51:58

标签: c

char * myFunction () {

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

} 

void main () {

    char *str;
    str = myFunction();

}

错误:从不兼容的指针类型返回

感谢

9 个答案:

答案 0 :(得分:12)

C中的字符串数组可以与char**char*[]一起使用。但是,您无法返回存储在堆栈中的值,就像在函数中一样。如果要返回字符串数组,则必须动态保留它:

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;

然后,main可以像这样得到字符串数组:

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

答案 1 :(得分:6)

对于刚开始的程序员来说,&#34; stack&#34;或者#34;堆&#34;可能有点令人困惑,特别是如果你已经开始使用Ruby,Java,Python等更高级别的语言进行编程。

考虑:

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

编译器将正确地发出关于尝试返回局部变量的地址的投诉,并且您肯定会在尝试使用返回的指针时遇到分段错误。

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

会关闭编译器,同时仍然会遇到同样令人讨厌的分段错误。

为了让除了狂热者之外的所有人都感到高兴,你会做一些更精细的事情:

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

现在使用它:

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

请记住在完成后释放已分配的内存,因为没有人会为你做这件事。这适用于所有指针,而不仅仅是指向指针的指针! (我想)。

为了更好地理解这一切,您可能还想阅读:What and where are the stack and heap?

答案 2 :(得分:2)

原因:
您需要返回类型为char(*)[20]。但即使在这种情况下,您也不希望从函数返回指向本地对象的指针 这样做:
使用malloc分配sub_str,并返回char**

答案 3 :(得分:1)

编译器错误的原因很简单,但不能解决您真正想要做的事情。您声明该函数返回char *,同时返回char **。

在不知道你正在做什么的细节的情况下,我将假设以下两件事之一:

1)该函数的目的是创建并返回一个字符串数组。 2)该函数对字符串数组执行一些操作。

如果#1为真,你需要几个malloc调用才能完成这项工作(实际上只需要两个,但为了简单起见,我会使用几个)。

如果您不知道数组应该有多大,那么您的函数声明应如下所示:

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

原因是因为你实际上是在返回一个指针数组的指针,你需要知道每个字符串有多少字符串和多长时间。

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

正如其他人所指出的那样,最好的做法就是分配也可以解除分配。因此需要一个清理功能。

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

现在,请记住,一旦调用了清理函数,您就无法再访问该数组了。试图仍然使用它很可能会导致您的应用程序崩溃。

如果#2为真,那么你想分配字符串,处理字符串并清理它们。您应该使用上面的两个函数来分配/解除分配您的字符串,然后使用第三个函数来对它们做任何事情。

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

答案 4 :(得分:1)

正如其他人正确地说你应该使用malloc的动态内存分配来将你的数组存储在heap中并返回指向其第一个元素的指针。

此外,我发现编写一个简单的array of string实现很有用,它具有最小的数据操作API。

类型和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);

<强>用法:

它创建一个包含4个维度的数组,可以存储长度为4个字符的字符串。如果字符串长度超出指定的长度,则只存储其前4个字符。

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

<强>实施

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

请注意,这只是一个简单的实现,没有错误检查。

答案 5 :(得分:0)

正如其他人所说,你不能将一个本地char数组返回给调用者,并且必须使用堆内存。

但是,我建议在函数中使用malloc()

好的做法是,无论谁分配内存,解除分配(并在malloc()返回NULL时处理错误条件)。

由于myFunction()无法控制它返回时分配的内存,因此让调用者提供存储结果的内存,并将指针传递给该内存。

这样,你的函数的调用者可以解除分配或重新使用内存(例如,对myFunction()的后续调用),但他认为合适。

但要小心,要么就此类调用的固定大小达成一致(通过全局常量),要么将最大大小作为附加参数传递,以免最终覆盖缓冲区限制。

答案 6 :(得分:0)

我使用该函数将字符串拆分为字符串数组

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

答案 7 :(得分:-1)

首先,您不能返回存储在堆栈中的字符串变量,而需要使用malloc动态分配内存,此处给出了带有示例的datails 转到https://nxtspace.blogspot.com/2018/09/return-array-of-string-and-taking-in-c.html 得到正确答案

答案 8 :(得分:-3)

char *f()
{   
    static char str[10][20];

    // ......

    return (char *)str;
}

int main()
{

    char *str;
    str = f();

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

    return 0;
}

您可以使用static而不是malloc。这是你的选择。