4

我正在尝试用 C 编写汉明代码程序。但是,在编译后尝试运行 ./a.out 时,我不断收到分段错误(核心转储)错误。它编译时没有错误,我知道在尝试解决释放空间或修改字符串文字时可能会发生此错误。我不相信我在做这两件事,我只是有一个简单的矩阵我正在填写和交叉检查。对此问题的任何见解都将不胜感激,我已经在下面留下了到目前为止的代码:

这是一个家庭作业问题,涉及创建一个汉明代码程序来处理 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 == '\n')
                        {
                                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, "\n");

                                ch = getc(fp);
                        }

                        count++;
                }
        }
}

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

4

4 回答 4

4

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

也许在启用 AddressSanitizer 的情况下进行构建,并查看在检查了上述潜在问题后会收到哪些运行时警告。(应该只是在 gcc 命令中添加以下标志... -g -fsanitize=address -fno-omit-frame-pointer

于 2019-04-09T22:01:22.713 回答
2

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

于 2019-04-09T22:08:06.560 回答
2

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

我会冒险假设您在这里使用 linux 并逐步完成代码的调试过程。

首先,我们在启用调试信息的情况下进行编译。

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

现在让我们使用两个工具valgrindgdb


尤其是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 "\360\021@") 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 帧,即 main 函数所在的位置。此时您可能已经看到了该错误,但如果它不明显,我们可以深入挖掘。

(gdb) info locals
i = 0
ch = 10 '\n'
temp = <optimized out>
numI = 0
count = 2
matrix1 = "\001\000\061\001\060\061\060"
(gdb)

info locals显示所有局部变量。在这一点上,我们对正在发生的事情有了一个相当完整的快照,但只是把它拼出来......

(gdb) print matrix1[0]
$1 = 1 '\001'
(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

我敢肯定,在您修复此问题后,您的程序将继续出现错误,并且未来的程序也会出现类似的错误,但是使用这两个工具您应该能够追踪大多数问题。

于 2019-04-09T22:46:24.340 回答
1

如果你想打印 1 和 0,你应该分配

matrix[i] = '1';

代替

matrix[i] = 1;
于 2019-04-09T22:36:10.680 回答