【问题标题】:Segmentation fault right at the end of the program程序结束时的分段错误
【发布时间】:2015-02-05 07:55:03
【问题描述】:

我对这段代码有疑问。 它按预期工作,除了它在最后得到 Seg 错误。

代码如下:

void distribuie(int *nrP, pach *pachet, post *postas) { 

    int nrPos, k, i, j;
    nrPos = 0;
    for (k = 0; k < 18; k++)
        pos[k].nrPac = 0; 
    for (i = 0; i < *nrP; i++) {
        int distributed = 0;
        for (j = 0; j < nrPos; j++) 
            if (pac[i].idCar == pos[j].id) {
                pos[j].vec[pos[j].nrPac] = pac[i].id;
                pos[j].nrPac++;
                distributed = 1;
                break;
            }
        if (distributed == 0) {
            pos[nrPos].id = pac[i].idCar;
            pos[nrPos].vec[0] = pac[i].id;
            pos[nrPos].nrPac = 1;
            nrPos++;
        }
    }
    for (i = 0; i < nrPos; i++) {
        printf("%d %d ", pos[i].id, pos[i].nrPac);
        for (j = 0; j < pos[i].nrPac; j++)
            printf("%d ", pos[i].vec[j]);
        printf("\n");
    }

}

并在 main() 中调用此函数。

使用 gdb 运行导致此错误:

Program received signal SIGSEGV, Segmentation fault.
0x00000001 in ?? ()

【问题讨论】:

  • 您是否对该gdb 会话进行了回溯?
  • 尝试在它上面运行 valgrind...你可能会在某处弄乱内存另外,如果你从不改变它的值,为什么 nrP 是指向 int 的指针?
  • @Antzi Running with valgrind 显示相同:进程以信号 11 (SIGSEGV) 的默认操作终止 ==15484== 访问不在地址 0x0 ==15484== 0x1 的映射区域内:? ??堆摘要:==15484== 退出时使用:10 个块中的 390 个字节 ==15484== 总堆使用量:10 个分配,0 个释放,分配 390 个字节 ==15484== ==15484== 泄漏摘要:= =15484== 肯定丢失了:10 个块中的 390 个字节
  • 是 'pos' 某种全局数组还是拼写错误?
  • 另一个建议是在你的函数中添加断言,确保所有索引都在预期的大小范围内。例如assert( sizeof( pos ) / sizeof( pos[0] ) &gt;= 18 );

标签: c debugging segmentation-fault


【解决方案1】:

我缺乏可以完全帮助您的信息:我不知道 pos[] 数组的大小。 k

所以 for 循环至少应该检查边界(假设为 18):

for (i = 0; i < *nrP && i < 18; i++) {

同样,pos结构显然有一个vec数组,但它的大小是未知的,同样的推理可以是18,可以是更少,也可以是更多:

pos[j].vec[pos[j].nrPac]

如果您添加所有边界检查,它可能会运行。

【讨论】:

  • pos 数组的最大大小为 32。顺便说一句,如果我将 k 循环到 32,它有时会在达到 k = 19 时出现 Seg 错误,但并非总是如此。为什么会这样?
  • “最大尺寸为 32”(但可能更小)或“尺寸为 32”?段错误的原因并不总是内存损坏,并且每次运行程序时都可能不同。这种行为是典型的内存损坏。
【解决方案2】:

如果gdb 找不到堆栈跟踪,这意味着您的代码在堆栈上写得非常彻底,以至于普通的 C 运行时和 gdb 都无法找到有关函数应在堆栈中返回的位置的信息。

或者,换句话说,你有一个(主要的)堆栈溢出。

某处,您的代码超出了数组的范围。奇怪的是,发布的代码引用了全局变量pospac,但传递了(未使用的)变量postaspachet。它表明您显示的代码不是您正在执行的代码。但是,假设pospac 的拼写确实与postaspachet 相同,那么可能是您对distribuie() 函数的调用处理不当。 (如果正如评论所暗示的那样,pospac 真的是全局变量,那么为什么函数会通过 postaspachet?)

您是否收到任何编译警告?您是否启用了编译警告?如果你有 GCC,代码是否可以用-Wall 干净地编译? -Wall -Wextra 怎么样?如果您收到任何警告,请修复原因。请记住,在您职业生涯的这个阶段,C 编译器可能比您更了解 C。

您可以通过在进入函数时打印键值(如*nrP)来帮助自己进行调试。如果这不是一个合理的值,那么您知道从哪里开始寻找。您还可以仔细查看该行的数据:

pos[j].vec[pos[j].nrPac] = pac[i].id;

有很多空间让事情误入歧途!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多