【问题标题】:Where is my segmentation fault? [closed]我的分段错误在哪里? [关闭]
【发布时间】:2012-11-12 01:57:30
【问题描述】:

我的代码编译得很好,但是当我尝试运行它时,我遇到了分段错误,我无法弄清楚哪里出了问题。

该程序的重​​点是将不同尺寸和片段数量的片段 ascii 艺术文件的文本拼凑在一起。 这些片段被命名为 part_xx-yy,其中 xx 是从 00 到 11,yy 是从 00 到 05。

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


int main(void)
{
    int width;
    int height;
    int xPieces;
    int yPieces;
    int xTens=0;
    int xOnes=0;
    int yTens=0;
    int yOnes=0;
    printf("Fragment width: ");
    scanf("%d", &width);
    printf("Fragment height: ");
    scanf("%d", &height);
    printf("Number of fragments on x axis: ");
    scanf("%d", &xPieces);
    printf("Number of fragments on y axis: ");
    scanf("%d", &yPieces);
    printf("wtf0");
    char *line=malloc(sizeof(width) * sizeof(char));
    printf("wtf1");
    char array[xPieces][yPieces][height][width];
    printf("wtf2");
    char fileName[50];
    printf("wtf3");
    for(int x = 0; x<xPieces;)
    {
        printf("%d", x);
        for(int y = 0; y<yPieces;)
        {
            printf("%d", y);
            if(xOnes>=10) 
            {
                xOnes=0;
                xTens++;
            }
            if(yOnes>=10)
            {
                yOnes=0;
                yTens++;
            }
            snprintf(fileName, sizeof fileName, "part_%i%i-%i%i", xTens, xOnes, yTens, yOnes);
            FILE *file=fopen(fileName, "r");
            char buffer[(width) * (height)];
            fread(buffer, 1, (width) * (height), file);
            for(int i = 0; i<height; i++)
            {
                printf("%d", i);
                for(int j = 0; j<width; j++)
                {
                    printf("%d", j);
                    array[x][y][i][j] = buffer[j + (i * (width))];
                }
            }
            fclose(file);
            y++;
            yOnes++;
        }
        x++;
        xOnes++;
    }

    FILE *newFile=fopen("newFile", "w");

    for(int y = 0; y<yPieces; y++)
    {
        for(int i = 0; i<height; i++)
        {
            for(int x = 0; x<xPieces; x++)
            {
                for(int j = 0; j<width; j++)
                {
                    fwrite(&array[x][y][i][j], 1, 1, newFile);
                }
            }
        }
    }

    fclose(newFile);
    free(line);
}

我想出了如何使用调试器,这表明 fread() 有问题,我认为这是由我的 fileName 数组引起的,但是我更改了一些东西,现在我从调试器得到的只是这个:

Program received signal SIGSEGV, Segmentation fault.
0x0018d68c in fread () from /lib/tls/i686/cmov/libc.so.6

我想也许 fread() 试图读入一个太小的缓冲区,所以我将缓冲区增加到 10000(这应该是戏剧性的过度杀伤),但可惜,无济于事。 我现在已经研究了很多,在这个问题上挣扎了几个小时,但仍然不知道如何从这里走得更远,因为我发现类似问题对我来说没有多大意义或不够相似.

我认为此时我需要其他人来查看我的代码,因此我们将不胜感激任何帮助。

.

.

更新:我已经更新了我的代码并进行了一些更改,但现在我在这里遇到了分段错误:

Program received signal SIGSEGV, Segmentation fault.
0x08049058 in main () at innlev3.c:50
50                      *array[x][y][i][j] = buffer[j + (i * (*width))];

我觉得这部分很不错...我做错了什么,在这里?

更新 2: 代码再次更新。我发现了一些我认为很奇怪的东西……在我的 scanf 工作之后,那些 printf 都没有……而且我又回到了旧的 fread() 分段错误。我想这是一件好事,我没有对此提出新问题......:P

Program received signal SIGSEGV, Segmentation fault.
0x0018d68c in fread () from /lib/tls/i686/cmov/libc.so.6
(gdb) backtrace
#0  0x0018d68c in fread () from /lib/tls/i686/cmov/libc.so.6
#1  0x08048fc6 in main ()

【问题讨论】:

  • 你应该问你的调试器这类问题。
  • 我更新了一个新的分段错误。可以吗?还是我应该提出一个新问题?
  • 我会说这足以作为一个单独的问题,但我怀疑 Stack Overflow 警察会来敲门。 ;-) 我已经尝试回答您的新问题,如下所示。

标签: c linux gdb


【解决方案1】:

我猜fileNULL,可能说明*fileName不存在。

注意这样的陈述:

fileName[5] = "%i",xTens;

不要做你可能期望的事情。该语句相当于:

fileName[5] = xTens;

这应该会给您一个编译器警告,因为您将 int 分配给 char*

相反,您可能打算使用snprintf 来使用printf 样式的格式来构造文件名。

char filename[50];
snprintf(filename, sizeof filename, "part_%i%i-%i%", xTens, xOnes, yTens, yOnes);
FILE *file=fopen(fileName, "r");

对于您的第二次崩溃:您在array 上多了一层不需要的指针。将其声明为char array...,并在访问时删除*。就目前而言,您已经告诉编译器元素将是指针,但您没有让它们指向任何地方,然后您要求编译器使用* 查看它们指向的位置。轰隆隆!

您对array 的最终使用需要创建一个指向每个字符的指针以传递给fwrite。你可以使用 &amp; 运算符来做到这一点,称为“address-of”,就像 &amp;array... 一样使用。

address-of 运算符与* 相反。程序运行后,您可以在其他地方使用&amp; 来简化您的代码。例如,不用声明 int *width 并使用 malloc 将其从堆中分配,您可以在任何地方删除 * 并将 &amp;width 传递给 scanf


由于我们回到fread segfault:在使用之前检查fopen 的返回值。如果是NULL,则打印错误消息。

if(file == NULL)
{
    printf("can't open %s\n", fileName);
    exit(1);
}

这可能会告诉你出了什么问题。但是,这不是调试代码。您通常应该检查您调用的函数是否有错误返回。

【讨论】:

  • 啊,我明白了。这让我通过了 fread() 段错误,但现在我在这里有了另一个:程序收到信号 SIGSEGV,分段错误。 0x08049058 in main () at innlev3.c:50 50 *array[x][y][i][j] = buffer[j + (i * (*width))];
  • 啊,我已经知道了一些。很高兴知道我正在更好地掌握这些指针。 :) 我现在又回到了旧的 fread() 分段错误,我发现了一个好奇心:没有任何 printf("wtf's that I added, prints... 代码已更新,非常感谢您的帮助。:)
  • 您的 printf 调用正在运行,但是由于您没有在它们的末尾添加换行符“\n”,因此它们的输出会被缓冲,直到您打印换行符为止。
  • 我不知道我必须这样做,实际上...... :P 是的,你的建议确实告诉我出了什么问题。我怎么会错过我试图打开一个我没有的文件的事实。哈哈。谢谢。
【解决方案2】:

在使用它之前,您没有将 *width 设置为任何值。

您想在阅读完尺寸后进行分配。

printf("fragment width: ");
scanf("%i", width);
printf("fragment height: ");
scanf("%i", height);
char *line=malloc(sizeof(*width) * sizeof(char));

另外,这并不是你认为的那样:

        FILE *file=fopen(*fileName, "r");

它将打开一个名为“p”的文件。

这也不是你认为的那样:

        fileName[5] = "%i",xTens;

我想你在想python。

【讨论】:

  • 这似乎不是真的 - 有一个 scanf 应该设置为 *width
  • @JameySharp:但 scanf 是在使用 *width 之后完成的。
  • 啊,我明白你的意思了——但是使用未初始化的width 分配的变量line 没有在任何地方使用,并且崩溃不会在那里发生,而是稍后发生。
  • 我根据你的建议改了代码,也根据另一个建议对我的代码进行了一些更改,所以我现在遇到了新的分段错误。
【解决方案3】:

+1 用于学习使用调试器 :) 你没有检查“fopen”的返回值。 file 的什么值被传递给 fread

【讨论】:

    【解决方案4】:

    如果您运行 gdb 并回溯,您会看到:

    Program received signal SIGSEGV, Segmentation fault.
    0x00007ffff7a8a724 in fread () from /lib/x86_64-linux-gnu/libc.so.6
    (gdb) backtrace
    #0  0x00007ffff7a8a724 in fread () from /lib/x86_64-linux-gnu/libc.so.6
    #1  0x0000000000400ad1 in main ()
    

    这意味着你在fread 中崩溃了。 fread() 中的文件变量似乎不正确。

    【讨论】:

    • 感谢回溯提示。我将来会使用它。 :) 目前,更新代码后出现的新分段错误只会在我进行简单回溯时给我同样的结果,而且我也看不出我的代码有什么问题。