初学者如何处理SEGFAULT-s ?(C)



我有一个关于SPOJ的问题,而且很快就要截止了。

我的任务是编写一个程序,计算给定行中有多少个标识符。标识符定义为'a'-'z''A'-'Z''0'-'9''_'中的字符序列,从任意字母或下划线字符('_')开始。

输入

>给定一定数量的数据集。每个数据集是由一定数量的单词序列组成的一行,由空格分隔,并以行结束字符结束(甚至是最后一行)。一个字是从33到126的任何ASCII字符的序列(详见http://www.asciitable.com),例如,aqui28$-3q_dat_第二个字是标识符,但第一个不是。

每行标识符的个数。

输入:

Dato25 has 2 c-ats and 3 _dogs
op8ax _yu _yu67 great-job ax~no identifier.

输出:

4
3

我写的代码编译,但当提交它返回SIGSEGV(分段错误)。


您的代码显示了一个令人遗憾的常见反模式:在处理之前不必要地将大块数据读入内存,而实际上可以在您处理时进行处理。

考虑一下:当你处理一个输入单词时,你需要参考同一行或任何其他行的前一个或后一个单词吗?不。那你为什么要把这些都记在记忆里?

事实上,你不需要存储任何部分,除了你刚刚读过的一个字符。您只需要
    • 在当前行和
    • 中您已经看到了多少标识符
    • 您在任何给定时间解析的内容(可能的标识符,非标识符单词或空格),
  • 为每个字符读取适当地更新,并且
  • 在每行末尾发出相应的输出(基于前面的输出)。

这可能比你的方法快。它肯定会使用更少的内存,尤其是更少的堆栈内存。而且它几乎没有为任何类型的边界溢出或无效指针使用提供任何空间,例如通常导致内存错误(如段错误)的原因。


至于为什么您的原始程序出现分段错误,我使用valgrind运行它,这是一种用于识别内存使用问题的流行工具。它可以检测内存泄漏、一些越界访问和未初始化内存的使用等。它告诉我,您从未初始化任何line[i]ident_count。非static局部变量,如line,不会自动初始化为任何特定的东西。有时候你很幸运,这并不是你的问题的原因,但培养良好的编程实践:修复它。

Valgrind没有向我指示任何其他错误,但是,您的程序也没有为我提供示例输入的段错误。尽管如此,我预计我可能会给您的程序提供超过100行和/或每行超过300个单词,和/或一个单词超过50个字符的输入,从而对程序造成各种各样的破坏。自动化判断倾向于包括探索问题空间极端的测试用例,因此您需要确保您的程序适用于所有有效输入。

或者,在注释中提出了一个有效的观点,即您在堆栈上分配了一个大对象,并且在裁判的测试环境中堆栈空间可能不足以容纳它。如果这是问题所在,那么在当前代码中解决它的一种快速简便的方法是仅分配一个struct WORDS并在每行中重用它。这将减少大约100倍的堆栈使用,而且,无论如何,将所有行同时存储在内存中有什么目的?

最新更新