【问题标题】:fprintf segmentation fault - explain like I'm 5fprintf 分段错误 - 像我 5 岁一样解释
【发布时间】:2014-04-10 23:54:33
【问题描述】:

我正在尝试将一些字符串写入文件。编译时没有警告,但是当我运行 a.out 时,它会出现段错误。不过,它确实创建了目标文件。我对 C 很陌生,所以我为我的格式和其他缺点道歉。这是我的代码:

#include<stdio.h>

int main (void)
{
    FILE *fp_out;

    char str1[]="four score and seven years ago our";
    char str2[]="fathers broughy forth on this continent,";
    char str3[]="a new nation, concieved in Liberty and dedicated";
    char str4[]="to the proposition that all men are created equal.";

    fp_out=fopen("my_file", "w");

    if(fp_out!=NULL)
    {
        fprintf(fp_out,"%s\n", str1[100]);
        fprintf(fp_out,"%s\n", str2[100]);
        fprintf(fp_out,"%s\n", str3[100]);
        fprintf(fp_out,"%s\n", str4[100]);
        fclose(fp_out);
    }
    else
        printf("The file \"my_file\" couldn't be opened\n");

    return 0;
}

【问题讨论】:

  • str1[100]? NONE 字符串的长度接近 100 个字符,因此您正在访问尚未分配的内存。应该是fprintf(fp_out, "%s\n", str1)
  • 没有strX[100]
  • 格式说明符%s 需要一个字符串变量或字符指针。例如,您传递的单个字符 str1[100] 不是有效地址。你想通过str1
  • 另外:你正在传递一个char,其中fprintf 需要一个char *。 IE。将其更改为 strX 不带数组下标 ([100])
  • StackExchange 网络不允许 5 岁儿童。

标签: c segmentation-fault printf


【解决方案1】:

你只需传递一个指向数组的指针

if(fp_out!=NULL)
{
    fprintf(fp_out,"%s\n", str1);
    fprintf(fp_out,"%s\n", str2);
    fprintf(fp_out,"%s\n", str3);
    fprintf(fp_out,"%s\n", str4);
    fclose(fp_out);
}

在您的代码中,“str1[100]”表示从 str1 中获取第 100 个字符。这将是 0 到 255 范围内的单个字符。您的格式字符串是“%s”,这意味着“我将向您传递一个指向字符串的指针”。您传递了一个字符(实际上只是一个数字),因此您有效地给出了一个指针

在正确的代码中,'str1' 是一个指向字符串的指针,因此有效。在您的示例中 str1 没有任何接近 100 个字符的地方,因此结果可能是任何内容(包括额外的段错误)。

记住:C 经常(尤其是 printf)并不关心你传递了什么。如果你错了……麻烦。

哦...而且...当我说第 100 个时,它们从 0 开始编号(所以实际上是第 101 个)

【讨论】:

  • OP 要求像他 5 岁那样解释,所以我建议您添加一个解释,说明您的答案为何有效。
  • 如果他是 5 岁,“为什么” 的答案是:“因为我说过!而且我是这所房子里的成年人!”
  • 你应该在任何地方都用 101 替换 100(不仅仅是在最后一句!),以便清楚地表明 something[100] 所指的内容,没有歧义。
【解决方案2】:

str1[100] 没有任何角色。使用指向以空字符结尾的字符串的字符指针。

    char *str1 ="four score and seven years ago our";
    char *str2 ="fathers broughy forth on this continent,";
    char *str3 ="a new nation, concieved in Liberty and dedicated";
    char *str4 ="to the proposition that all men are created equal.";

    if(fp_out!=NULL)
    {
        fprintf(fp_out,"%s\n", str1);
        fprintf(fp_out,"%s\n", str2);
        fprintf(fp_out,"%s\n", str3);
        fprintf(fp_out,"%s\n", str4);
        fclose(fp_out);
    }

【讨论】:

    【解决方案3】:

    您应该阅读fprintf() 上的手册。

    int fprintf(FILE *stream, const char *format, ...);
    

    在您使用%s 的格式字符串中,这意味着您将传递fprintf() 一个字符串。

    这是一个字符串:

    char str1[]="four score and seven years ago our";
    

    这是打印字符串的方式:

    fprintf(fp_out,"%s\n", str1);
    

    你想在这里做什么:

    fprintf(fp_out,"%s\n", str1[100]);
    

    是打印str1 的第 101st 字符,它没有那么长,所以你试图访问超出你的数组拥有的内存......更不用说你了将一个字符重新传递给一个格式字符串,该格式字符串需要一个导致 UB 的字符串。

    【讨论】:

      【解决方案4】:

      分段错误是当您尝试访问您无权访问的内存时产生的错误。在您的代码中,您将 str1[100] 传递给 printf 以获取 %s 说明符。 %s 说明符需要一个 char*(字符指针)。 str1[100] 本质上是垃圾,因为它在您声明的字符串之外。访问 str1[100] 可能不会产生分段错误,尽管它可能会产生,这取决于最终指向的堆栈中的位置。但是 printf 会获取您给它的垃圾并尝试将其作为字符指针取消引用,这会导致分段错误。更正后的代码如下。

      #include<stdio.h>
      
      int main (void)
      {
          FILE *fp_out;
      
          char str1[]="four score and seven years ago our";
          char str2[]="fathers broughy forth on this continent,";
          char str3[]="a new nation, concieved in Liberty and dedicated";
          char str4[]="to the proposition that all men are created equal.";
      
          fp_out=fopen("my_file", "w");
      
          if(fp_out!=NULL)
          {
              fprintf(fp_out,"%s\n", str1);
              fprintf(fp_out,"%s\n", str2);
              fprintf(fp_out,"%s\n", str3);
              fprintf(fp_out,"%s\n", str4);
              fclose(fp_out);
          }
          else
              printf("The file \"my_file\" couldn't be opened\n");
      
          return 0;
      }
      

      【讨论】:

      • +1 因为你解释了为什么会发生段错误:fprintf 期望一个指向字符串的指针,地址 *(strX+100) 处的值被解释为一个指针,很可能指向一个未经处理的位置(因此是段错误)。
      • @Olivier 除了不能保证它会出现段错误。在这个特定的实例中它确实如此,但实际上程序只是调用 UB(未定义的行为),因此它可以分段错误,或打印垃圾,或做任何事情。
      猜你喜欢
      • 2019-05-26
      • 2018-12-03
      • 2014-02-16
      • 2018-03-27
      • 1970-01-01
      • 1970-01-01
      • 2020-09-24
      • 2015-04-14
      • 1970-01-01
      相关资源
      最近更新 更多