0

可能重复:
指向局部变量的指针
可以在其范围之外访问局部变量的内存吗?

gcc 4.4.4 c89

在 main 中,我调用一个函数将一行文本传递给一个函数。我想对其进行一些操作。但是,这意味着该行没有用。所以在我的 get_string 函数中,我复制内容并返回结果。唯一的问题是,该结果的记忆会丢失并指向意想不到的东西。

我只是想知道如何将结果传回,而无需并且仍然保留序数行数据?

非常感谢您的任何建议,

主要代码片段:

    if(fgets(line_data, (size_t)STRING_SIZE, fp) == NULL) {
        fprintf(stderr, "WARNING: Text error reading file line number [ %d ]\n", i);
    }

    if(get_string(line_data) != NULL) {
        if(strcmp(get_string(line_data), "END") == 0)
            break;
    }
    else {
        fprintf(stderr, "WARNING: Cannot get name of student at line [ %d ]\n", i);
    }

    /* Fill student info */
    strncpy(stud[i].name, line_data, (size_t)STRING_SIZE);

调用这个函数

char* get_string(char *line_data)
{
    char *quote = NULL;
    char result[STRING_SIZE] = {0};

    strncpy(result, line_data, (size_t)STRING_SIZE);

    /* Find last occurance */
    if((quote = strrchr(result, '"')) == NULL) {
        fprintf(stderr, "Text file incorrectly formatted for this student\n");
        return NULL;
    }
    /* Insert nul in place of the quote */
    *quote = '\0';

    /* Overwite the first quote by shifting 1 place */
    memmove(result - 1, result, strlen(result) + 1);

    return result;
}
4

4 答案 4

2

只需返回 strdup(结果)。它将分配和复制您的字符串。但是,您必须在外部函数中使用结果后释放结果。

您还可以在输入中获取一个缓冲区(及其大小),并用您想要的内容填充它。

于 2010-08-03T16:08:45.190 回答
1

您想为结果分配内存:

char *result; result = malloc(STRING_SIZE);

正如您所拥有的那样,结果的内存存在于堆栈中,因此仅在执行期间 get_string()

您还需要在返回 NULL 之前释放结果以防止内存泄漏。

于 2010-08-03T16:06:04.817 回答
1

对于您的直接问题 - 要么使用malloc(3)并告诉函数的用户取消分配返回指针(这有点容易发生内存泄漏,因为在 C 中很容易忽略返回值),或者提供第二个参数作为接收缓冲:

char* get_string( const char* line_data, char* receive_buf, size_t buf_size );

第三个参数是让函数知道接收缓冲区有多大。

现在到您的代码 - 该行memmove(result - 1, result, strlen(result) + 1);破坏了您的堆栈。

于 2010-08-03T16:06:58.197 回答
1

根据经验,您永远不应该返回指向函数局部变量的指针。你知道为什么:一旦一个函数返回,分配给它的变量的内存就可以被其他东西重用。返回指向结果缓冲区的指针的想法本质上是不好的。

您应该考虑是否真的需要保留引用字符串的副本。如果您在调用 get_string 之前测试了“END”字符串会怎样?如果您以后需要引用和输出数据,这很容易完成。说:

printf("\"%s\"", student_record);

所以 get_string 实际上可以在缓冲区中工作并返回错误代码(0 表示成功)。由于您知道最终结果是一个较小的以 nul 结尾的字符串,因此您甚至不需要长度参数。

int get_string(char* student_record);

如果您确实需要保留引用字符串的副本,那么您需要传递另一个缓冲区。我仍然会返回一个 int 来表示成功(0)或失败(比如 -1)。

int get_string( const char* line_data, char* student_record, size_t buf_size );

我个人更喜欢让调用者分配自己的缓冲区。它给它一个使用固定长度缓冲区的机会(更简单的内存管理)。前任:

char student_record[512];
...
if (!get_string(student_record)) {
  // error
}
于 2010-08-03T17:16:30.663 回答