什么原因导致C中出现分段错误(核心转储)?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么原因导致C中出现分段错误(核心转储)?相关的知识,希望对你有一定的参考价值。

我试图在C中编写汉明代码程序。但是,在编译后尝试运行./a.out时,我不断收到分段错误(Core Dumped)错误。它编译时没有错误,我理解在尝试解决释放空间或修改字符串文字时可能会发生此错误。我不相信我正在做其中任何一件事,我只是有一个简单的矩阵,我正在填写和交叉检查。任何有关该问题的见解将不胜感激,我已经离开了目前为止的代码:

这是一个家庭作业问题,涉及创建汉明代码程序来处理data.dat输入和输出到文件的排序列表1和0的

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

FILE *fp;
FILE *fpOut;

int main(int argc, char *argv[])
{
        fp = fopen(argv[1], "r");
        fpOut = fopen("sortedCodeWords.dat", "w");

        int temp;
        int numI = 0;
        int count = 0;

        char matrix1[7];

        if(fp == NULL)
                printf("File can not be opened");
        else
        {
                char ch = getc(fp);

                while(ch != EOF)
                {

                        matrix1[2] = ch;
                        ch = getc(fp);

                        matrix1[4] = ch;
                        ch = getc(fp);

                        matrix1[5] = ch;
                        ch = getc(fp);

                        matrix1[6] = ch;
                        ch = getc(fp);

                        ch = getc(fp);

                        if(ch == '
')
                        {
                                for(int i = 2; i < 7; i++)
                                {
                                        if(matrix1[i] == '1')
                                            numI++;

                                        i++;
                                }

                                if(numI % 2 == 0)
                                        matrix1[0] = 0;
                                else
                                        matrix1[0] = 1;

                                numI = 0;

                                for(int i = 1; i < 7; i++)
                                {
                                        if(matrix1[i] == '1')
                                                numI++;
                                        if(matrix1[i+1] == '1')
                                                numI++;

                                        i++;
                                        i++;
                                }

                                if(numI % 2 == 0)
                                        matrix1[1] = 0;
                                else
                                        matrix1[1] = 1;

                                numI = 0;

                                for(int i = 4; i < 7; i++)
                                {
                                        if(matrix1[i] == '1')
                                                numI++;
                                }

                                if(numI % 2 == 0)
                                        matrix1[3] = 0;
                                else
                                        matrix1[3] = 1;
                                numI = 0;

                                for (int i = 0; i < 7; i++)
                                {
                                        fprintf(fpOut, "%s", matrix1[i]);
                                }

                                fprintf(fpOut, "
");

                                ch = getc(fp);
                        }

                        count++;
                }
        }
}

我希望输出到文件。我并不总是得到这个错误,但当我从2D数组更改为1D数组时,我现在收到此错误(我改变了因为我意识到没有必要)

答案

我看到的两件事。首先,你在矩阵数组中混合使用字符的字符。其次,您使用“%s”格式将矩阵元素打印到文件中。当你传递字符和整数时,“%s”需要一个以空字符结尾的字符串。这将导致printf尝试访问超出范围的内存,从而导致错误。

另一答案

我没有编译它,但我注意到的一件事是,看起来好像你可能会在你的数组的末尾,你循环到i<7,但在一个实例中使用i+1的索引。

也许在使用AddressSanitizer的情况下进行构建,并在查看上面的潜在问题后查看运行时警告。 (这应该只是向你添加以下标志gcc命令... -g -fsanitize = address -fno-omit-frame-pointer

另一答案

您必须学习如何使用调试器。

我冒着假设你在这里使用Linux并冒险完成代码调试过程的风险。

首先我们编译启用调试信息。

james@debian:~/code$ gcc foo.c -g

现在让我们使用两个工具valgrind和gdb来实现它


特别是valgrind是一个非常棒的工具,只要你使用内存搞砸就会捕获它。它几乎是追踪内存泄漏所必需的,但可以用于很多Seg故障。最重要的是,它易于使用,无需任何交互。

james@debian:~/code$ valgrind ./a.out foo.dat
==1857== Memcheck, a memory error detector
==1857== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1857== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==1857== Command: ./a.out foo.dat
==1857==
==1857== Conditional jump or move depends on uninitialised value(s)
==1857==    at 0x109381: main (foo.c:61)
==1857==
==1857== Invalid read of size 1
==1857==    at 0x4837C38: __GI_strlen (in /usr/lib/i386-linux-gnu/valgrind/vgpreload_memcheck-x86-linux.so)
==1857==    by 0x48A4786: vfprintf (vfprintf.c:1638)
==1857==    by 0x48AAC57: fprintf (fprintf.c:32)
==1857==    by 0x109437: main (foo.c:91)
==1857==  Address 0x1 is not stack'd, malloc'd or (recently) free'd
==1857==
==1857==
==1857== Process terminating with default action of signal 11 (SIGSEGV)
==1857==  Access not within mapped region at address 0x1
==1857==    at 0x4837C38: __GI_strlen (in /usr/lib/i386-linux-gnu/valgrind/vgpreload_memcheck-x86-linux.so)
==1857==    by 0x48A4786: vfprintf (vfprintf.c:1638)
==1857==    by 0x48AAC57: fprintf (fprintf.c:32)
==1857==    by 0x109437: main (foo.c:91)
==1857==  If you believe this happened as a result of a stack
==1857==  overflow in your program's main thread (unlikely but
==1857==  possible), you can try to increase the size of the
==1857==  main thread stack using the --main-stacksize= flag.
==1857==  The main thread stack size used in this run was 8388608.
==1857==
==1857== HEAP SUMMARY:
==1857==     in use at exit: 688 bytes in 2 blocks
==1857==   total heap usage: 3 allocs, 1 frees, 4,784 bytes allocated
==1857==
==1857== LEAK SUMMARY:
==1857==    definitely lost: 0 bytes in 0 blocks
==1857==    indirectly lost: 0 bytes in 0 blocks
==1857==      possibly lost: 0 bytes in 0 blocks
==1857==    still reachable: 688 bytes in 2 blocks
==1857==         suppressed: 0 bytes in 0 blocks
==1857== Rerun with --leak-check=full to see details of leaked memory
==1857==
==1857== For counts of detected and suppressed errors, rerun with: -v
==1857== Use --track-origins=yes to see where uninitialised values come from
==1857== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault

只是阅读第一个错误,它在第61行标记了一个问题,说if(matrix1[i] == '1')正在使用未初始化的内存。

考虑到这一点阅读你的代码,它跳出来matrix1[1]永远不会被初始化,所以有一个错误。这不是Seg Fault。

另一个错误标记在第91行,看起来像错误,但很难理解。所以让我们淘汰gdb。


james@debian:~/code$ gdb a.out
GNU gdb (Debian 8.2.1-2) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...done.
(gdb) run foo.dat
Starting program: /home/james/code/a.out foo.dat

Program received signal SIGSEGV, Segmentation fault.
__strlen_ia32 () at ../sysdeps/i386/i586/strlen.S:51
51      ../sysdeps/i386/i586/strlen.S: No such file or directory.

run foo.dat负责该计划。我们通过一些信息快速解决您的细分问题。

(gdb) info stack
#0  __strlen_ia32 () at ../sysdeps/i386/i586/strlen.S:51
#1  0xb7e28787 in _IO_vfprintf_internal (s=0x4052c0, format=0x402037 "%s",
    ap=0xbffff52c "36021@") at vfprintf.c:1638
#2  0xb7e2ec58 in __fprintf (stream=0x4052c0, format=0x402037 "%s")
    at fprintf.c:32
#3  0x00401438 in main (argc=2, argv=0xbffff614) at foo.c:91
(gdb) frame 3
#3  0x00401438 in main (argc=2, argv=0xbffff614) at foo.c:91
91                          fprintf(fpOut, "%s", matrix1[i]);
(gdb)

info stack打印执行堆栈。我们不关心系统文件级别的错误,我们关心main中的错误。 frame 3切换到第3帧,主要功能位于第3帧。此时您可能已经看到了这个错误,但如果不明显,我们可以深入挖掘。

(gdb) info locals
i = 0
ch = 10 '
'
temp = <optimized out>
numI = 0
count = 2
matrix1 = "01006101606160"
(gdb)

info locals显示所有局部变量。在这一点上,我们有一个相当完整的快照,但只是拼出来......

(gdb) print matrix1[0]
$1 = 1 '01'
(gdb)

在这一点上你必须知道一些C. matrix[0]根本不适合printf("%s")。它期望一个字符指针指向某个有意义的值,但是你给它的数字1,这会导致Seg Fault。

回顾一下我们从valgrind那里得到的错误,现在更容易理解,说我们使用gdb推断出同样的事情:我们试图将数字1作为内存地址读取...

==1857==    by 0x109437: main (foo.c:91)
==1857==  Address 0x1 is not stack'd, malloc'd or (recently) free'd

修复此程序后,您的程序将继续出现错误,我确信,未来的程序会有类似的错误,但使用这两个工具,您应该能够找到大多数问题。

另一答案

如果要打印1和0,则应分配

matrix[i] = '1';

代替

matrix[i] = 1;

以上是关于什么原因导致C中出现分段错误(核心转储)?的主要内容,如果未能解决你的问题,请参考以下文章

c中的分段错误(核心转储)

为啥我的代码中出现分段错误(核心转储)错误?

为啥我的代码会出现分段/核心转储错误?

为啥我在 C 中收到警告“分段错误,核心转储”

C++ 的核心转储分段错误

在我的模板类示例中,出现“分段错误(核心转储)”错误