【问题标题】:Segmentation Fault - C [duplicate]分段错误 - C [重复]
【发布时间】:2012-05-26 23:09:38
【问题描述】:

为什么以下代码返回分段错误?当我注释掉第 7 行时,段错误消失了。

int main(void){
      char *s;
      int ln;
      puts("Enter String");
      // scanf("%s", s);
      gets(s);
      ln = strlen(s); // remove this line to end seg fault
      char *dyn_s = (char*) malloc (strlen(s)+1); //strlen(s) is used here as well but doesn't change outcome
      dyn_s = s;
      dyn_s[strlen(s)] = '\0';
      puts(dyn_s);
      return 0;
    }

干杯!

【问题讨论】:

标签: c segmentation-fault


【解决方案1】:
char *s  does not have some memory allocated . You need to allocate it manually in your case . You can do it as follows
s = (char *)malloc(100) ;

这不会导致分段错误,因为您将不再引用未知位置

【讨论】:

    【解决方案2】:

    更好

    #include <stdio.h>
    int
    main(void)
    {
      char *line = NULL;
      size_t count;
      char *dup_line;
    
      getline(&line,&count, stdin);
      dup_line=strdup(line);
    
      puts(dup_line);
    
      free(dup_line);
      free(line);
    
      return 0;
    }
    

    【讨论】:

    • 嗨!我从未使用过 getline() 和 strdup() 函数。我想我以前也没有见过他们。谢谢你把他们介绍给我;)。嗯,不幸的是你的代码遇到了段错误!
    • 奇怪。关于隐式声明的警告,对我来说是正确的工作。 GNU/Linux 系统,gcc 4.6.3。
    • line 应该用 NULL 初始化。是的,C 可能很残酷。
    • 酷!谢谢KAction!最近有点忙。我保证我会在不久的某个时候更深入地研究你的代码的内部机制。周末愉快。干杯!
    【解决方案3】:

    您的scanf("%s", s); 已被注释掉。这意味着 s 未初始化,所以当这条线 ln = strlen(s); 执行时,你会得到一个段错误。

    初始化一个指向 NULL 的指针总是有帮助的,然后在使用指针之前测试是否为 null。

    【讨论】:

    • 谢谢!将更频繁地进行 NULL 指针初始化和测试。我不认为我得到 scanf 部分。 scanf 不应该也失败吗?毕竟,指针没有初始化为任何东西,并且可能指向某个任意且非法的位置作为字符串的起始位置,因此是段错误?我将其注释掉,因为包含它也会导致段错误。还是我没听懂?
    • 这个答案是错误的。如果你将该指针初始化为 NULL,那也将导致 UB - NULL 永远不会被取消引用,即使是 scanf...
    • 我测试我的指针,看看它们是否设置为空。如果在使用前初始化为 null,那么很有可能该指针尚未分配给有效内存。
    【解决方案4】:

    灾难性的:

    int main(void){
          char *s;
          int ln;
          puts("Enter String");
          // scanf("%s", s);
          gets(s);
          ln = strlen(s); // remove this line to end seg fault
          char *dyn_s = (char*) malloc (strlen(s)+1); //strlen(s) is used here as well but doesn't change outcome
          dyn_s = s;
          dyn_s[strlen(s)] = '\0';
          puts(dyn_s);
          return 0;
        }
    

    更好:

    #include <stdio.h>
    #define BUF_SIZE 80
    
    int 
    main(int argc, char *argv[])
    {
          char s[BUF_SIZE];
          int ln;
          puts("Enter String");
          // scanf("%s", s);
          gets(s);
          ln = strlen(s); // remove this line to end seg fault
          char *dyn_s = (char*) malloc (strlen(s)+1); //strlen(s) is used here as well but doesn't change outcome
          dyn_s = s;
          dyn_s[strlen(s)] = '\0';
          puts(dyn_s);
          return 0;
        }
    

    最佳:

    #include <stdio.h>
    #define BUF_SIZE 80
    
    int 
    main(int argc, char *argv[])
    {
          char s[BUF_SIZE];
          int ln;
          puts("Enter String");
          fgets(s, BUF_SIZE, stdin); // Use fgets (our "cin"): NEVER "gets()"
    
          int ln = strlen(s); 
          char *dyn_s = (char*) malloc (ln+1);
          strcpy (dyn_s, s);
          puts(dyn_s);
          return 0;
        }
    

    【讨论】:

    • 更好的是:char *dyn_s = malloc(ln + 1);。请注意fgets() 将终止'\n' 留在缓冲区中; gets() 丢弃它(但 gets() 仍然是灾难性的糟糕)。
    • 酷!谢谢。你有什么很棒的资源链接到常用的 IO 函数的行为吗?
    • 除了cast malloc() 结果删除之外,检查您是否没有收到NULL 值。 char *dyn_s = malloc(ln + 1); if(!dyn_s) { printf("No mem!\n"); exit(EXIT_FAILURE);} 或者你能得到另一个分段错误。
    • @resonant_fractal:签出:cplusplus.com/reference/clibrary/cstdio
    【解决方案5】:

    s 是一个未初始化的指针;您正在写入内存中的随机位置。这将调用未定义的行为

    您需要为s 分配一些内存。还有,never use gets;没有办法防止它溢出您分配的内存。请改用fgets

    【讨论】:

    • 非常感谢奥利!请原谅我是一个害虫,但是,我是否理解添加我提到的行会导致未定义的行为导致段错误。你能帮我进一步想象一下因果关系吗?
    • @resonant_fractal:很难说。根据定义,未定义的行为意味着您的程序可以做任何事情,包括以不可预知的方式失败。我可以猜测,但唯一确定的方法是查看编译器生成的机器代码。
    • 因为strlen() 函数试图访问一个不存在的空间。与strlen(NULL) 相同。内部函数有类似:size_t strlen(char *s) { char *p=s; while( *p++ )
    • @TheMask 谢谢!但是第 8 行中的 malloc 使用相同的 strlen 表达式呢?如果我只删除第 7 行,整个程序运行没有任何错误。或者你们得到了不同的东西?
    • 如果我删除第 7 行或第 8 行,我会得到同样的错误。因为实际上,错误开始于gets() 调用,而不是我之前所说的strlen()(但原因相同),对不起。如果您不了解gdb,请参阅 about,我建议使用它。它对于检测错误非常有用。例如,如果你使用 gdb a.out 运行程序,你会得到:Enter String foo Program received signal SIGSEGV, Segmentation fault. _IO_gets (buf=0x282ff4 "|M\025") at iogets.c:55.
    猜你喜欢
    • 2018-10-30
    • 2016-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-14
    • 1970-01-01
    • 2011-10-01
    相关资源
    最近更新 更多