как вернуть массив строк из функции - PullRequest
8 голосов
/ 03 ноября 2010
char * myFunction () {

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

} 

void main () {

    char *str;
    str = myFunction();

}

ошибка: возврат из несовместимого типа указателя

спасибо

Ответы [ 9 ]

12 голосов
/ 03 ноября 2010

Массив строк в 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. */
6 голосов
/ 18 июля 2012

Для программистов, только начинающих, концепция «стека» или «кучи» может быть немного запутанной, особенно если вы начали программировать на языке более высокого уровня, таком как 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++;
  }
}

Просто не забудьте освободить выделенную память, когда вы закончите, потому что никто не сделает это за вас.Это касается всех указателей, а не только указателей на указатели!(я думаю).

Чтобы разобраться во всем этом, вы также можете прочитать это: Что и где находится стек и куча?

2 голосов
/ 03 ноября 2010

Причина:
тип возврата должен быть char(*)[20].Но даже в этом случае вы не хотите возвращать указатель на локальный объект из функции.
Do:
Используйте malloc для выделения sub_str и возврата char**.

1 голос
/ 26 декабря 2015

Как правильно сказали другие, вы должны использовать динамическое выделение памяти 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;
}

Обратите внимание, что это простопростая реализация без проверки ошибок.

1 голос
/ 27 октября 2014

Причина вашей ошибки компилятора проста, но не ответ на то, что вы действительно хотите сделать. Вы заявляете, что функция возвращает символ *, а возвращает символ **.

Не зная подробностей того, что вы делаете, я предполагаю, что одна из двух вещей верна:

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 );
0 голосов
/ 07 сентября 2018

в первую очередь Вы не можете вернуть строковую переменную, которая хранится в стеке, вам нужно использовать malloc для динамического распределения памяти, здесь приведены данные с примером Go https://nxtspace.blogspot.com/2018/09/return-array-of-string-and-taking-in-c.html получить правильный ответ

0 голосов
/ 28 мая 2018

я использую эту функцию для разделения строки на массив строк

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;
}
0 голосов
/ 03 ноября 2010

Как уже говорили другие, вы не можете вернуть вызывающему массиву локальный массив символов, и для этого нужно использовать кучу памяти.

Однако я бы не посоветовал бы использовать malloc() внутри функции.

Хорошей практикой является то, что, кто бы ни выделяет память, он также освобождает ее (и обрабатывает состояние ошибки, если malloc()возвращает NULL).

Так как ваш myFunction() не имеет контроля над памятью, которую он выделил после того, как он вернулся, пусть вызывающая сторона предоставит память, в которой будет сохранен результат, и передаст указатель на эту память.

Таким образом, вызывающая сторона вашей функции может отменить выделение или повторно использовать память (например, для последующих вызовов myFunction()), как считает нужным.

Будьте осторожны, чтобылибо согласитесь на фиксированный размер для таких вызовов (через глобальную константу), либо передайте максимальный размер в качестве дополнительного параметра, чтобы в итоге не перезаписать ограничения буфера.

0 голосов
/ 03 ноября 2010
char *f()
{   
    static char str[10][20];

    // ......

    return (char *)str;
}

int main()
{

    char *str;
    str = f();

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

    return 0;
}

Вы можете использовать static вместо malloc. Это твой выбор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...