CS50 pset4分段错误恢复。c>&燃气轮机;我做错了什么?
编辑2:根据我最初的问题,它是通过 风向标 我们发现了对指针基本原理的严重误解。一旦我检查了指针信息,我就解决了分割错误。谢谢大家 作品: **目标是,给定一个card.raw文件,使用jpeg签名恢复所有jpeg,并假设一旦找到一个jpeg,所有其他jpeg将连续跟踪,直到文件结束。该文件的格式为FAT 512字节块** 正如标题所说,我不确定我在做什么来获得分割错误。我曾经尝试过使用valgrind和gcd进行调试,但由于我对编码还很陌生,所以我找不到分段错误的来源。我承认,试图破译这些调试函数的输出被证明比我预期的更神秘 此外,我还搜索了其他有类似分段错误的人,但我发现的其他人,特别是在这个网站上,都是从代码中的另一个错误中获取错误的,而我(认为)没有 这让我抓狂,因为我似乎已经正确地创建了缓冲区,确保文件总是在不将它们困在条件语句中的情况下打开和关闭,并且正确地利用fwrite创建了块大小正确的jpeg 我感谢所有给予我的帮助 编辑: 根据要求的评论员,以下是我的valgrind输出:CS50 pset4分段错误恢复。c>&燃气轮机;我做错了什么?,c,segmentation-fault,cs50,recover,C,Segmentation Fault,Cs50,Recover,编辑2:根据我最初的问题,它是通过 风向标 我们发现了对指针基本原理的严重误解。一旦我检查了指针信息,我就解决了分割错误。谢谢大家 作品: **目标是,给定一个card.raw文件,使用jpeg签名恢复所有jpeg,并假设一旦找到一个jpeg,所有其他jpeg将连续跟踪,直到文件结束。该文件的格式为FAT 512字节块** 正如标题所说,我不确定我在做什么来获得分割错误。我曾经尝试过使用valgrind和gcd进行调试,但由于我对编码还很陌生,所以我找不到分段错误的来源。我承认,试图破译这些调试
~/workspace/pset4/recover/ $ valgrind --leak-check=full ./recover card.raw
==26277== Memcheck, a memory error detector
==26277== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==26277== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==26277== Command: ./recover card.raw
==26277==
==26277== Invalid read of size 1
==26277== at 0x42DC1F: write_jpeg (recover.c:79)
==26277== by 0x9A904008211C1099: ???
==26277== by 0x82104489A502E0F: ???
==26277== by 0x2104082104082103: ???
==26277== by 0x408210408210407: ???
==26277== by 0x821040821040820: ???
==26277== by 0x9304082104082103: ???
==26277== by 0x21840021840048: ???
==26277== by 0x4208104248208481: ???
==26277== by 0x13F0E30705210447: ???
==26277== by 0x13E8E0CA918D0902: ???
==26277== by 0xD384118482262983: ???
==26277== Address 0x821040821040821 is not stack'd, malloc'd or (recently) free'd
==26277==
==26277==
==26277== Process terminating with default action of signal 11 (SIGSEGV)
==26277== General Protection Fault
==26277== at 0x42DC1F: write_jpeg (recover.c:79)
==26277== by 0x9A904008211C1099: ???
==26277== by 0x82104489A502E0F: ???
==26277== by 0x2104082104082103: ???
==26277== by 0x408210408210407: ???
==26277== by 0x821040821040820: ???
==26277== by 0x9304082104082103: ???
==26277== by 0x21840021840048: ???
==26277== by 0x4208104248208481: ???
==26277== by 0x13F0E30705210447: ???
==26277== by 0x13E8E0CA918D0902: ???
==26277== by 0xD384118482262983: ???
==26277==
==26277== HEAP SUMMARY:
==26277== in use at exit: 1,136 bytes in 2 blocks
==26277== total heap usage: 2 allocs, 0 frees, 1,136 bytes allocated
==26277==
==26277== LEAK SUMMARY:
==26277== definitely lost: 0 bytes in 0 blocks
==26277== indirectly lost: 0 bytes in 0 blocks
==26277== possibly lost: 0 bytes in 0 blocks
==26277== still reachable: 1,136 bytes in 2 blocks
==26277== suppressed: 0 bytes in 0 blocks
==26277== Reachable blocks (those to which a pointer was found) are not shown.
==26277== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==26277==
==26277== For counts of detected and suppressed errors, rerun with: -v
==26277== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault
这是我的密码:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
// prototypes
void write_jpeg(int count, FILE *file, uint8_t buffer[]);
int main(int argc, char *argv[]) {
// ensure correct argument usage
if (argc != 2) {
fprintf(stderr, "Error. Correct usage: ./recover [infile]\n");
return 1;
}
// open infile
FILE *file = fopen(argv[1], "r");
// ensure can open file
if (file == NULL) {
fprintf(stderr, "Error, could not open file\n");
return 2;
}
// initializes bool variable that signals start of jpegs
bool start = false;
// buffer for file block
uint8_t buffer[512];
// loop to find the start of the series of jpegs
while (!start) {
// read FAT blocks into buffer
fread(&buffer, 1, 512, file);
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff
&& (buffer[3] & 0xf0) == 0xe0) {
start = true;
fseek(file, -4, SEEK_CUR);
memset(buffer, 0x00, 512);
}
}
// count for number of jpegs
int count = 0;
// loop to create jpegs
while ((fread(&buffer, 1, 512, file)) == sizeof(buffer)) {
write_jpeg(count, file, buffer);
}
fclose(file);
return 0;
}
// writes into a new file until the start of another jpeg
void write_jpeg(int count, FILE *file, uint8_t buffer[]) {
// creates filenames for jpegs
char file_name[8];
sprintf(file_name, "%03i.jpg", count);
// opens file to write to
FILE *img = fopen(file_name, "w");
if (img == NULL) {
fprintf(stderr, "Error: couldnt create jpg file\n");
return;
}
// bool for end condition
bool end = false;
while (!end) {
// ends if reaches new jpeg signature
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff
&& (buffer[3] & 0xf0) == 0xe0) {
end = true;
fseek(file, -4, SEEK_CUR);
memset(buffer, 0x00, 512);
count++;
} else {
// read the next block into buffer
fread(&buffer, 1, 512, file);
// write the buffer into the new file
fwrite(&buffer, 1, 512, img);
}
}
fclose(img);
}
#包括
#包括
#包括
#包括
#包括
//原型
无效写入jpeg(整数计数,文件*文件,uint8_t缓冲区[]);
int main(int argc,char*argv[]){
//确保正确的参数用法
如果(argc!=2){
fprintf(stderr,“错误。正确用法:./recover[infle]\n”);
返回1;
}
//露天填充物
FILE*FILE=fopen(argv[1],“r”);
//确保可以打开文件
if(file==NULL){
fprintf(stderr,“错误,无法打开文件\n”);
返回2;
}
//初始化表示JPEG开始的bool变量
bool start=false;
//文件块缓冲区
uint8_t缓冲器[512];
//循环以查找JPEG系列的开头
而(!开始){
//将FAT块读入缓冲区
fread(&buffer,1512,文件);
如果(缓冲区[0]==0xff&&buffer[1]==0xd8&&buffer[2]==0xff
&&(缓冲区[3]&0xf0)==0xe0){
开始=真;
fseek(文件-4,SEEK_CUR);
memset(缓冲区,0x00512);
}
}
//计算JPEG的数量
整数计数=0;
//循环以创建JPEG
while((fread(&buffer,1512,file))==sizeof(buffer)){
写入jpeg(计数、文件、缓冲区);
}
fclose(文件);
返回0;
}
//写入新文件,直到另一个jpeg开始
无效写入jpeg(整数计数,文件*文件,uint8\u t缓冲区[]){
//为JPEG创建文件名
字符文件名[8];
sprintf(文件名,“%03i.jpg”,计数);
//打开要写入的文件
文件*img=fopen(文件名,“w”);
如果(img==NULL){
fprintf(stderr,“错误:无法创建jpg文件\n”);
返回;
}
//末端条件的布尔
bool end=false;
当(!结束){
//如果达到新的jpeg签名,则结束
如果(缓冲区[0]==0xff&&buffer[1]==0xd8&&buffer[2]==0xff
&&(缓冲区[3]&0xf0)==0xe0){
结束=真;
fseek(文件-4,SEEK_CUR);
memset(缓冲区,0x00512);
计数++;
}否则{
//将下一个块读入缓冲区
fread(&buffer,1512,文件);
//将缓冲区写入新文件
fwrite(&buffer,1512,img);
}
}
fclose(img);
}
在write\u jpeg
功能中,这是不正确的:
fread(&buffer,
fread
函数需要一个指向写入空间的指针。但是,您提供了一个指向空间的指针,其中存储了指向所述空间的指针
它应该是fread(buffer,
。您在fwrite
中犯了同样的错误,在main
中也犯了同样的错误(但是在这种情况下,由于实现细节的原因,您可以侥幸逃脱)
此外,如果
count
达到1000
,则会出现缓冲区溢出。%03i
printf说明符表示最少3位,而不是最多。使用Valgrind时是否发生崩溃?Valgrind报告了什么?我不理解fseek(文件,-4,SEEK\CUR)的目的;
。您检查了4个签名字节,但实际上读取了512字节-至少我们可以猜到您是这样做的,因为您没有在执行大部分工作的函数中检查fread
的返回值。这意味着您没有在读取一个jpeg数据的循环中检测到文件的结尾。我回顾了我对fseek的使用,现在我已经检查了我相信它没有任何用处。我最初使用它是因为我认为我移动了内嵌的光标4个字节并需要返回,但我对fread和缓冲区所服务的实际机制有误解。如果我理解正确,我不需要使用fseek。@Weather Vane,我不确定我是否理解第二部分c在检查fread的返回值及其对检测循环中的文件结尾的影响时,该循环正在对一个jpeg的数据进行放射线处理。我记得确保fread不返回null非常重要,这一点我将予以实现,但我不确定如何解决我当前的任何问题。顺便说一句,谢谢您的评论。fread
never返回一个指针值,但返回读取的字节数并应始终进行检查。否则,您将如何检测文件结尾?查找另一个jpeg签名将不起作用,因为不会有一个,并且您没有其他方法在write\u jpeg
中中断循环。