尝试修复C程序中的分段错误

时间:2019-05-05 06:38:32

标签: c

我是一名学生,并且得到了我已经从事了一周的课程。每当我运行该程序时,我都会遇到分段错误问题,我更改并尝试了几乎所有内容,在互联网上阅读了很多,没有任何帮助。我一直在尝试使用调试器来解决这个问题!

我认为这是我在<div class="header"> <h1>Step 1: Confucius</h1> <p>He who copies the master, honours him</p> </div> <div class="parent"> <div class="topnav"> <button class="dropbtn">Professional</button> <div class="dropdown-content"> <a href="first.php">Professional</a> </div> </div> <div class="topnav"> <button class="dropbtn">Hobbies</button> <div class="dropdown-content"> <a href="second.php">Test</a> </div> </div> <div class="topnav"> <button class="dropbtn">Tutorials</button> <div class="dropdown-content"> <a href="third.php">Test3</a> </div> </div> </div>中分配内存的方式,但是我对其进行了多次更改,没有任何效果...

这是我的程序:

eurovisionAddState()

2 个答案:

答案 0 :(得分:4)

  

我一直在尝试使用调试器来解决这个问题!

调试器是诊断这种情况的重要工具,但是您仍然必须认真考虑代码的工作方式,以便了解调试器的内容。要记住的一个有用想法是,每次崩溃都是由某些特定的指令引起的, * ,而您的工作是找到该指令,然后弄清楚如何到达那里。

  

我每次运行该程序时都会遇到分段错误问题

好,那么什么指令导致分段错误?您的调试器应该能够将您指向该行。我的问题出在这里:

while (cn->before)

它还告诉我我们如何达到目标以及问题所在:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
  * frame #0: 0x000000010000064c DeleteThis`countryGetFirst(cn=0x8b480850ff078b48) at main.c:65
    frame #1: 0x0000000100000688 DeleteThis`countryNodeExists(c=0x0000000102905f60, ID=1) at main.c:74
    frame #2: 0x0000000100000a1e DeleteThis`eurovisionAddState(eurovision=0x0000000102908750, stateId=1, stateName="malta", songName="chameleon") at main.c:182
    frame #3: 0x0000000100000b76 DeleteThis`main at main.c:212
    frame #4: 0x00007fff617253d5 libdyld.dylib`start + 1
    frame #5: 0x00007fff617253d5 libdyld.dylib`start + 1

(“ DeleteThis”只是我为该项目指定的名称-提醒我,我不需要在接下来的20分钟内保存它。此外,我删除了一些多余的空行,因此我的行数字可能与您不匹配。)

这里重要的是我们正在查看堆栈,我们可以看到countryGetFirstcountryNodeExists调用,而eurovisionAddState又由main调用了,从main调用。好的,接下来我们需要知道问题线路为何崩溃。分段错误通常意味着您正在尝试取消引用错误的指针。确实,崩溃的行确实取消了某些指针的引用,但这不好吗?让我们找出它的来源...

您的eurovision函数首先会像这样设置变量Eurovision eurovision = setupEurovision();

setupEurovision

那么eurovision->Countries的作用是什么?它只是为Eurovision结构分配了一些空间,然后分配了另一个块并使Eurovision euro=(Eurovision)malloc(sizeof(*euro)); euro->Countries=(CountryNode)malloc(sizeof(struct CountryNode_t)); return euro; 指向它:

eurovisionAddState(eurovision, 1, "malta", "chameleon");

到目前为止看起来还好吧?接下来,那件事怎么办?好,接下来您添加一个国家:

eurovisionAddState

为此,if(countryNodeExists(eurovision->Countries,stateId)) 致电:

eurovisionAddState

这很有趣,因为发生崩溃时,countryNodeExistseurovision->Countries都在调用堆栈中,并且您 just 分配了countryNodeExists,所以如果发生我们看CountryNode cn = countryGetFirst(c); ?好吧,它要做的第一件事就是调用崩溃的函数:

c

,它在此处传递的eurovision->Countries就是呼叫者中的countryGetFirst。嗯...继续前进。 while (cn->before) 中有什么?

cn

嗯。为什么会崩溃?这里的c在呼叫者中称为eurovision->Countries,在前一个呼叫者中是cn,因此我们可以将eurovision->Countries一直追溯到main来自(CountryNode)malloc(sizeof(struct CountryNode_t)); 。您认为那里有什么?记住,您是这样创建的:

malloc

(此外:您真的不应该转换malloc的结果。在SO上搜索以找出原因。)

因此,您是使用cn = cn->before; 创建的。它有什么价值?您实际上并不知道该块中的内容,您只知道该块的地址,并且尚未在该地址保存任何内容。因此,有两种可能:它要么为零,要么为非零。非零的赔率非常好,那么接下来会发生什么呢?好吧,您执行循环的主体,因此您可以这样做:

before

好,因此此CountryNode的{​​{1}}成员中的任何内容现在都在cn中。同样,我们不知道该块中的内容,但是可以肯定地假设此before值不是指向另一个CountryNode的指针,因为您尚未在其中保存任何内容。因此,cn现在是一些随机值。您到达了循环的结尾,由于是循环,所以重复:

while (cn->before)

嗯...现在您在cn中取消引用该随机值,这时出现段错误,因为不允许从任何地方读取内存。

现在,我已经引导您完成了整个过程,以说明思考过程。但是,即使您不立即了解问题,您也应该能够使用调试器执行相同的操作……您始终可以在您知道问题发生之前的某个时刻设置断点,然后逐步执行一次说明一次,直到您遇到错误。您现在应该这样做,以帮助您自己真正地了解和理解该问题。完成后,我确定您将能够找到解决方法。

祝你好运!

* 为此概念而向Scott Knaster致信。How to Write Macintosh Software: The Debugging Reference for the Macintosh

答案 1 :(得分:2)

为了在C中进行更安全的编程,这里有一些要做不要的事情:

  • 执行括号宏参数和扩展名:#define NOT_FOUND (-1)
  • 不要将指针隐藏在typedef后面,这会使代码更加混乱,更容易出错。
  • 当一个简单的int成员就足够时,
  • 不要使用指针:struct country_t { int ID; ...
  • 请勿强制转换malloc()的返回值
  • 在访问列表成员之前测试列表指针是否为空:如果countryGetFirstcn == NULL将崩溃(这是您的崩溃错误
  • 要做,学习使用调试信息进行编译并使用带有源代码显示的调试器,它会立即为您指出问题。
  • 请勿使用单链接将满足以下条件的双链接列表:您将继续扫描每个列表的第一个节点,然后扫描下一个节点。只需将eurovision->Countries指向列表开头的指针即可。
  • 当数组符号更易读时,
  • 不要使用指针符号*(name + i)name[i]
  • 执行使用strdup()分配字符串副本,如果系统上不可用,则重写它:state->SongName = strdup(songName);
  • 测试内存分配失败
  • 要做,;以及ifforwhile关键字之后,在二进制运算符周围使用空格,在{等之前
  • 执行以一致的方式缩进代码。 4个空格是常见的可读约定。
  • 请勿在代码块和函数之间插入多个空白行。
  • 执行,将编译器配置为发出其他警告:gcc -Wall -Wextra ...