【问题标题】:segmentation fault, what to do? [closed]分段错误,怎么办? [关闭]
【发布时间】:2022-01-22 09:09:57
【问题描述】:
char* scanString(FILE* fp, unsigned int size)
{
    char* str;
    int Char;
    unsigned int len = 0;
    str = (char*)realloc(NULL, size);
    if (str == NULL)
        return str;
    while (EOF != (Char = fgetc(fp)) && Char != '\n')
    {
        str[len++] = Char;
        if (len == size)
        {
            size = size + 16;
            str = (char*)realloc(str, size);
            if (!str)return str;
        }
    }
    str[len++] = '\0';
    return (char*)realloc(str, len);
}

我使用这个函数来扫描未知大小的字符串,当我在没有循环的主函数中使用它时,一切正常。 但是当我试图在另一个函数中使用它时,程序就停止了,我该怎么办?

【问题讨论】:

  • 您应该附加一个调试器以至少知道段错误发生在哪一行。此外,如果返回 null,则会泄漏:str = (char*)realloc(str, size);
  • 不要解释“当我尝试使用另一个函数时”,而是向我们展示您编写的实际代码,当您尝试运行它时会停止。
  • 提示:str = (char*)realloc(str, size); if (!str)return str;realloc 返回NULL 时会泄漏内存。
  • 你传递的size是什么?
  • 提示:size 参数的意义何在?

标签: c string pointers char realloc


【解决方案1】:

您的代码取决于size 最初至少是一个。错误可能是因为 0 被传递了。

在向缓冲区添加字符之前,您没有确保缓冲区中有可用空间,最简单的解决方案是在向缓冲区添加字符之前而不是之后扩展缓冲区。

// Type-safe version of realloc.
#define REALLOC(p, T, n) ((T*)realloc(p, sizeof(T) * n))

char* readLine(FILE* fp)
{
    char*  str  = NULL;
    size_t size = 0;
    size_t len  = 0;
    while (1)
    {
        int ch = fgetc(fp);

        if (len == size)
        {
            size += 16;
            char* tmp = REALLOC(str, char, size);
            if (!tmp)
            {
                free(str);
                return NULL;
            }

            str = tmp;
        }

        if (ch == EOF || ch == '\n')
        {
           str[len] = 0;
           return str;
        }

        str[len++] = ch;
    }
}

其他变化:

  • 消除了realloc 返回 NULL 时发生的内存泄漏。
  • 删除了无用的size参数。
  • 更好的函数名。

请注意,返回此接口并不表示 EOF 或读取错误。调用者有责任使用feof(fp)ferror(fp) 进行检查。我会使用不同的设计。


对于为什么宏更安全有些困惑,所以我会解释一下。

malloc/calloc/realloc 的一个大问题是它们返回 void*,这意味着没有类型检查来确保返回的指针与其分配的变量兼容。宏添加了这种类型检查。

这允许捕获某些原本会被忽视的错误。您可以找到一个宏捕获错误的演示,常见替代方法无法捕获here

#include <stdlib.h>

#define REALLOC(p, T, n) ((T*)realloc(p, sizeof(T) * n))

int main(void) {
    size_t n = 4;

    int    *a = NULL;
    double *b = NULL;

    b = realloc(NULL, n * sizeof(int));  // Silently accepts the error.

    b = realloc(NULL, n * sizeof *a);    // Silently accepts the error.

    b = REALLOC(NULL, int, n);           // Catches the error.

    (void)a;  // Proxy for remainder of function.
    (void)b;  // Proxy for remainder of function.
}

【讨论】:

  • 请原谅我的失明,但str 第一次测试时怎么不为NULL?
  • @kirjosieppo 错字。固定。
  • "注意返回这个接口" ...这里少了一个词吗?从,也许?
  • // Safer 不...为什么? IMO 这是相当不安全的。传递不必要的显式类型没有任何好处......类型转换也没有。更好的方法是:char* tmp = realloc(str, size * sizeof *tmp); 如果你想要“安全”
  • @ikegami 类型检查? int* tmp = REALLOC(str, char, size);char* tmp = REALLOC(str, int, size); ... 都容易出错。只需使用sizeof *tmp
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-12
  • 2014-07-01
相关资源
最近更新 更多