分段错误:CS50 recover.c
Segmentation Fault: CS50 recover.c
该程序接受一个文件名作为输入,并且应该恢复该文件上的所有 jpeg。它一次读取 512 个字节,检查新 jpeg 的开始。
当我 运行 程序编译时,它给出了一个分段错误。请告诉我如何解决这个问题。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// check for proper usage
if (argc != 2)
{
printf("Usage: 1 command line argument\n");
return 1;
}
// check if file can be opened
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("Cannot be opened\n");
return 2;
}
// read 512 bytes into buffer until end of card
int buffer[128];
int counter;
counter = 0;
char filename[8];
FILE *img = NULL;
while(fread(buffer, 4, 128, file) == 128)
{
//check if start of new JPEG
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
//check if first JPEG
if (counter == 0)
{
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
fwrite(buffer, 4, 128, img);
counter += 1;
}
else if (counter > 0)
{
fclose(img);
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
fwrite(buffer, 4, 128, img);
counter += 1;
}
}
else if (counter > 0)
{
fwrite(buffer, 4, 128, img);
}
}
fclose(img);
fclose(file);
return 0;
}
fclose(img)
是罪魁祸首。 img
为空。为了找出原因,您可以在 fopen
之后插入一些 printf
。这是 link 用于调试将来的任何段错误。
$ ./recover card.raw
Memory access error: invalid parameter; abort execution.
# fclose's parameter (0x0) is not a valid FILE pointer.
# Stack trace (most recent call first) of the error.
# [0] file:/recover.c::55, 5
# [1] [libc-start-main]
调用 fread(buffer, 4, 128, file)
将 512 个字节读取(如您所说)到 128 个整数的数组中。但是,当您随后使用以下代码测试新 JPEG 文件的开头时:
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
//...
您正在检查数组中前四个整数中每个整数的低字节,而不是(您应该这样做)检查前四个字节 数组。这四个字节都将在第一个整数元素(buffer[0]
).
中
因此,您的程序将永远找不到新 JPEG 的开头,因此,img
文件将永远不会打开...然后您将调用 fclose
并使用 NULL
文件指针,这是未定义的行为,可能会导致您看到的分段错误。
相反(假设 'endianness' 正确),执行以下检查:
if ((buffer[0] & 0xfffffff0) == 0xffd8ffe0)
{
//...
为了允许 'wrong endianness',您可以检查 buffer[0]
:
中的任一字节顺序
if ((buffer[0] & 0xfffffff0) == 0xffd8ffe0 || (buffer[0] & 0xf0ffffff) == 0xe0ffd8ff)
{
//...
更好的是,只需读取(和写入)缓冲区的内容 - 一个 512 字节的数组,代码如下:
unsigned char buffer[512];
//...
while(fread(buffer, 1, 512, file) == 512)
{
//...
这样,您可以保持 'JPEG start' 测试原样。
该程序接受一个文件名作为输入,并且应该恢复该文件上的所有 jpeg。它一次读取 512 个字节,检查新 jpeg 的开始。
当我 运行 程序编译时,它给出了一个分段错误。请告诉我如何解决这个问题。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// check for proper usage
if (argc != 2)
{
printf("Usage: 1 command line argument\n");
return 1;
}
// check if file can be opened
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("Cannot be opened\n");
return 2;
}
// read 512 bytes into buffer until end of card
int buffer[128];
int counter;
counter = 0;
char filename[8];
FILE *img = NULL;
while(fread(buffer, 4, 128, file) == 128)
{
//check if start of new JPEG
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
//check if first JPEG
if (counter == 0)
{
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
fwrite(buffer, 4, 128, img);
counter += 1;
}
else if (counter > 0)
{
fclose(img);
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
fwrite(buffer, 4, 128, img);
counter += 1;
}
}
else if (counter > 0)
{
fwrite(buffer, 4, 128, img);
}
}
fclose(img);
fclose(file);
return 0;
}
fclose(img)
是罪魁祸首。 img
为空。为了找出原因,您可以在 fopen
之后插入一些 printf
。这是 link 用于调试将来的任何段错误。
$ ./recover card.raw
Memory access error: invalid parameter; abort execution.
# fclose's parameter (0x0) is not a valid FILE pointer.
# Stack trace (most recent call first) of the error.
# [0] file:/recover.c::55, 5
# [1] [libc-start-main]
调用 fread(buffer, 4, 128, file)
将 512 个字节读取(如您所说)到 128 个整数的数组中。但是,当您随后使用以下代码测试新 JPEG 文件的开头时:
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
//...
您正在检查数组中前四个整数中每个整数的低字节,而不是(您应该这样做)检查前四个字节 数组。这四个字节都将在第一个整数元素(buffer[0]
).
因此,您的程序将永远找不到新 JPEG 的开头,因此,img
文件将永远不会打开...然后您将调用 fclose
并使用 NULL
文件指针,这是未定义的行为,可能会导致您看到的分段错误。
相反(假设 'endianness' 正确),执行以下检查:
if ((buffer[0] & 0xfffffff0) == 0xffd8ffe0)
{
//...
为了允许 'wrong endianness',您可以检查 buffer[0]
:
if ((buffer[0] & 0xfffffff0) == 0xffd8ffe0 || (buffer[0] & 0xf0ffffff) == 0xe0ffd8ff)
{
//...
更好的是,只需读取(和写入)缓冲区的内容 - 一个 512 字节的数组,代码如下:
unsigned char buffer[512];
//...
while(fread(buffer, 1, 512, file) == 512)
{
//...
这样,您可以保持 'JPEG start' 测试原样。