Возвращение строки из функции в C - PullRequest
4 голосов
/ 21 февраля 2012

У меня есть функция c, которую я хочу вернуть строку.

Если я распечатаю строку до ее возвращения, я вижу croc_data_0186.idx

Если я попытаюсь напечатать возвращаемую строку, я увижу croc_data_á☼

Кто-нибудь может увидеть, что я делаю не так?

Функция задачи:

char* getSegmentFileName(FILE *file, int lineLength, int lineNumber)
{
    char* fileNameString;

    fseek(file, lineNumber * lineLength, SEEK_SET);

    char line[lineLength];
    fgets(line, lineLength, file);

    char *lineElements[3];
    lineElements[0] = strtok(line, ":");
    lineElements[1] = strtok(NULL, ":");
    lineElements[2] = strtok(NULL, ":");

    fileNameString = lineElements[2];

    printf ("getSegmentFileName fileNameString is: %s \r\n", fileNameString);

    return fileNameString;
}

Телефонный код:

int indexSearch(FILE *file, char* value, int low, int high, char* segmentFileName)
{
    ...

    segmentFileName = getSegmentFileName(file, lineLength, mid);
    printf ("indexSearch: segmentFilename3 is: %s \r\n", segmentFileName);

    ...
}

Ответы [ 7 ]

7 голосов
/ 21 февраля 2012

Вы возвращаете указатель на локальные данные, который недействителен после возврата из функции. Вы должны правильно распределить строку.

Это можно сделать в любой вызывающей функции, предоставив буфер вызываемой функции, и он скопирует строку в предоставленный буфер. Как это:

char segmentFileName[SOME_SIZE];
getSegmentFileName(file, lineLength, mid, segmentFileName);

и функция getSegmentFileName:

void getSegmentFileName(FILE *file, int lineLength, int lineNumber, char *segmentFileName)
{
    /* ... */

    strcpy(segmentFileName, fileNameString);
}

Другим решением является выделение памяти для строки в getSegmentFileName:

return strdup(fileNameString);

но тогда вы должны запомнить free строку позже.

4 голосов
/ 21 февраля 2012

Это потому, что вы возвращаете указатель на локальный.Это неопределенное поведение.

strtok возвращает указатель на массив символов line.Вы помещаете этот указатель в fileNameString и возвращаетесь к вызывающей стороне.В это время память внутри line становится недействительной: в нее может быть записан любой мусор.

Чтобы избежать этой проблемы, вы должны либо передать пару буфер / длина для возвращаемого значения, либо использовать strdup()на строке, которую вы возвращаете.В последнем случае вы должны помнить, чтобы освободить память, выделенную для возвращаемой строки, на strdup().

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

3 голосов
/ 21 февраля 2012

Вы возвращаете указатель на локальную переменную, которая больше не существует, когда функция возвращается. Вы должны malloc хранилище для него и вернуть его. Кроме того, вы можете позволить вызывающему пройти в буфер для заполнения. В любом случае, вызывающая сторона ответственна за free последующую память.

2 голосов
/ 21 февраля 2012

Проблема в том, что вы возвращаете переменную стека, потерянную при возврате функции. Один из способов сделать это - использовать char * arg в параметре функции с достаточным зарезервированным пространством и использовать его для хранения всей информации и ее возврата.

2 голосов
/ 21 февраля 2012

Это потому, что вы возвращаете неверные указатели.

    char* fileNameString;

это просто указатель.

    char line[lineLength];

живет в стеке и заполняется вызовом fgets().

    char *lineElements[3];
    lineElements[0] = strtok(line, ":");
    lineElements[1] = strtok(NULL, ":");
    lineElements[2] = strtok(NULL, ":");

Здесь вы храните указатели в этом массиве. Одним из них является

    fileNameString = lineElements[2];

который вы

    return fileNameString;

впоследствии.

Решением будет

  • либо выделите недостаточно места внутри функции и скопируйте строку в новый блок памяти, либо

  • пусть вызывающая сторона предоставит буфер, в который вы записываете данные.

0 голосов
/ 21 февраля 2012

Есть 3 способа решить эту проблему

1) Сделать 'fileNameString' статическим

static char fileNameString[100];

2) Вызывающий функцию 'getSegmentFileName' должен передать символьный буфер'gmentFileName 'вызываемому, т.е.

getSegmentFileName(file, lineLength, mid, segmentFileName);

В этом случае вам нужно изменить аргументы функции

   char* getSegmentFileName(FILE *file, int lineLength, int lineNumber, char *segmentFileName) {

    .....

    strcpy(segmentFileName, fileNameString); // copying the local variable 'fileNameString' to the function argument
                      // so that it wont be lost when the function is exited.

    return fileNameString; // there is no need to return anything and you can make this function void
                   // in order not to alter ur program I am putting the return also
    }

3) Таким образом, вы можете динамически распределять память для fileNameString. Динамическая память выделяется в куче, и она не будет потеряна при возврате функции. Таким образом, вы можете безопасно использовать его в функции indexSearch.

char* getSegmentFileName(FILE *file, int lineLength, int lineNumber)
{
    char *fileNameString = (char *)malloc(100 * sizeof(char));  // allocate memory for 100 character string

    .....
    return fileNameString;
}

В этом случае вам нужно освободить память, указанную fileNameString, используя free

0 голосов
/ 21 февраля 2012

Строка - это локальная переменная, которая удаляется в конце функции.

Вы должны использовать malloc или strcpy для указателя строки, переданного в качестве аргумента.

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