【问题标题】:How to get rid of "Segmentation fault" on C?如何摆脱C上的“分段错误”?
【发布时间】:2021-06-30 21:57:42
【问题描述】:

我刚开始为 MOOC 编写 C 语言。 第一周的任务是建造马里奥楼梯(使您能够在每个级别结束时到达旗帜顶部的楼梯)。 事件虽然我的程序似乎正在运行,但我在楼梯/金字塔的尽头不断收到“分段错误”。 我想知道是否有人可以向我解释为什么这个程序会出现“分段错误”?

#include <stdio.h>
#include <cs50.h>
#include <string.h>

int main(void)
{
    //Initializing variables : 
    char str[] = "";
    int z;
    int i;
    int n = get_int("How many stairs ?");
    
    //Checking that the number of stairs is correct : 
    
    while (n > 8 || n < 1)
    {
        n = get_int("How many stairs ?");
    }
    
    //Adding each layer of stairs : 
    
    for (i = 0 ; i < n ; i = i + 1)
    {
        
        for (z = 0 ; z <= (n - i) ; z += 1)
        {
            strncat(str, " ", 1);
        }
        
        for (z = 0 ; z <= i ; z += 1)
        {
            strncat(str, "#", 1);
        }
        
        strncat(str, " ", 1);
        
        for (z = 0 ; z <= i ; z += 1)
        {
            strncat(str, "#", 1);
        }
        
        for (z = 1 ; z <= (n - i) ; z += 1)
        {
            strncat(str, " ", 1);
        }
        
        //Going to the next layer of stairs : 
        
        strncat(str, "\n", 1);
    }
    
    //Showing the drawing of the stairs made of "#": 
    
    printf("%s", str);
}

他就是这样打算做的:

$ ./mario
Height: 8
       #  #
      ##  ##
     ###  ###
    ####  ####
   #####  #####
  ######  ######
 #######  #######
########  ########

非常感谢!

【问题讨论】:

  • char str[] = "" 只有零个字符的空格和一个标记字符串结尾的空终止符;任何strncat 的尝试都会导致您覆盖有用的数据结构,从而导致崩溃或其他有问题的行为几乎不可避免。
  • 一个简单的修复方法是char str[256] = "";,但您需要检查是否没有溢出 256。您可以在知道需要多少空间后分配它,或者动态增长它根据需要。
  • 你为什么要在数组中存储字符呢?你熟悉putc吗?您可以使用构建数组所需的相同类型的循环直接输出必要的字符,一次一个。

标签: c segmentation-fault cs50


【解决方案1】:

strcat 不会更改 char 数组长度,而您的数组只有一个元素。您在 UB 的字符边界之外写入,因此是段错误。您还错误地使用了strncat 函数。无需将所有行放在一个字符串中。

根本不需要最后一个循环

这里确实需要任何字符串函数或字符串。

#include <stdio.h>
#include <cs50.h>

int main(void)
{
    int z;
    int i;
    int n = get_int("How many stairs ?");
    
    //Checking that the number of stairs is correct : 
    
    while (n > 8 || n < 1)
    {
        n = get_int("How many stairs ?");
    }
    
    //Adding each layer of stairs : 

    fputc('\n', stdout);
    
    for (i = 0 ; i < n ; i ++)
    {
        
        for (z = 0 ; z <= (n - i) ; z += 1)
        {
            fputc(' ', stdout);
        }
        
        for (z = 0 ; z <= i ; z += 1)
        {
            fputc('#', stdout);
        }
        
        fputc(' ', stdout);
        
        for (z = 0 ; z <= i ; z += 1)
        {
            fputc('#', stdout);
        }
        fputc('\n', stdout);
    }    
}

https://godbolt.org/z/v1EMn1qsf

但如果你想要字符串和 strncat,你可以使用 VLA

#include <stdio.h>
#include <cs50.h>
#include <string.h>

int main(void)
{
    //Initializing variables : 
    int z;
    int i;
    int n = get_int("How many stairs ?");
    
    //Checking that the number of stairs is correct : 
    
    while (n > 8 || n < 1)
    {
        n = get_int("How many stairs ?");
    }

    char str[n*2 + 3];

    printf("\n");
    
    //Adding each layer of stairs : 
    
    for (i = 0 ; i < n ; i = i + 1)
    {
        str[0] = 0;
        for (z = 0 ; z <= (n - i) ; z += 1)
        {
            strncat(str, " ", 2);
        }
        
        for (z = 0 ; z <= i ; z += 1)
        {
            strncat(str, "#", 2);
        }
        
        strncat(str, " ", n*2+2);
        
        for (z = 0 ; z <= i ; z += 1)
        {
            strncat(str, "#", 2);
        }
        
        
        //Going to the next layer of stairs : 
        
        strncat(str, "\n", n*2+3);
        printf("%s", str);
    }  
}

https://godbolt.org/z/hEq1oGEq6

【讨论】:

  • 在第 1 级,是 7 个空格 + 1 #,你的结果是 9 个空格 + 1 #。但是 +1 为新手提供详细答案。
  • 感谢我的错误答案,我在这里阅读了很多帖子并意识到 char str[] = "abcdef"; 确实是一种初始化语法。
【解决方案2】:

您的 str 变量没有足够的存储空间。 当 C 到达你的char str[] = ""; 时,它会为数组分配内存,刚好够你传递的文字和Null 字符,在这种情况下,空间的大小将是 1 char。因此,当您开始连接字符时,请将它们添加到您的变量不允许的空格中。 C 也会为程序分配额外的空间,因此您实际上是在编辑为程序保留的内存;这就是为什么分段错误不会更早出现的原因。 你可以保留足够的空间,它会工作的

    char str[160] = "";

【讨论】:

  • 如果我想要 1000 步怎么办?
  • 我认为 size = 2*(n+4)*n 是正确的公式,但我建议您更改方法,因为这会占用大量内存
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-28
  • 2019-06-07
  • 1970-01-01
  • 2017-04-04
  • 2011-08-07
  • 1970-01-01
相关资源
最近更新 更多