在C语言中从函数返回一个字符串

5

我有一个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);

    ...
}

可能是 返回 char 指针的函数 的重复问题。 - Lundin
可能是从函数返回C字符串的重复问题。 - underscore_d
7个回答

8
你正在返回指向本地数据的指针,该指针在函数返回后将不再有效。你需要正确分配字符串。
这可以在调用函数中完成,通过向被调用函数提供缓冲区,并将字符串复制到提供的缓冲区中。像这样:
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
这是因为你返回了一个指向本地变量的指针,这是未定义行为。 strtok返回一个指向line字符数组的指针。你把这个指针放到fileNameString中,并返回给调用者。此时line内存变得无效:任何垃圾都可以被写入其中。
为避免这个问题,你应该为返回值传递一个缓冲区/长度对,或者在要返回的字符串上使用strdup()。在后一种情况下,你应该记得释放由strdup()分配的返回字符串的内存。
另外,应该避免使用strtok,因为它不可重入,在多线程环境中会引起问题。考虑使用strtok_r

你真快,约翰尼,非常迅速。 - Tio Pepe
"用于返回值的缓冲区/长度对,在这种情况下特别直接,因为大小为 lineLength 的缓冲区足够大。当调用者事先不知道一个好的上限时,这更加棘手。" - Steve Jessop

3

您返回了一个指向在函数返回后不再存在的本地变量的指针。您必须为其分配存储空间并返回它。或者,您可以让调用者传入要填充的缓冲区。无论哪种情况,调用者都负责稍后释放内存。


并且在之后也要释放使用 malloc 分配的内存。 - Shiplu Mokaddim

2

这是因为您返回了无效指针。

    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;

之后。

解决方案是:

  • 在函数内部分配足够的空间,并将字符串复制到新的内存块中;或者

  • 让调用者提供一个缓冲区,你将数据写入其中。


2
问题在于你返回了一个栈变量,在函数返回时会丢失。一种解决方法是在函数参数中使用char*类型的参数,并保留足够的空间来存储所有信息并返回它。

0

你可以有三种方式来解决这个问题:

1)将“fileNameString”设置为静态。

static char fileNameString[100];

2) 调用函数 'getSegmentFileName' 的调用者应该向被调用者传递一个字符缓冲区 'segmentFileName'。

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

在这种情况下,您需要使用free释放由fileNameString指向的内存。

0

Line是一个局部变量,在函数结束时会被移除。

你应该使用malloc,或者将其复制到作为参数传递的字符串指针。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接