CS50 pset4分段错误恢复。c>&燃气轮机;我做错了什么?

CS50 pset4分段错误恢复。c>&燃气轮机;我做错了什么?,c,segmentation-fault,cs50,recover,C,Segmentation Fault,Cs50,Recover,编辑2:根据我最初的问题,它是通过 风向标 我们发现了对指针基本原理的严重误解。一旦我检查了指针信息,我就解决了分割错误。谢谢大家 作品: **目标是,给定一个card.raw文件,使用jpeg签名恢复所有jpeg,并假设一旦找到一个jpeg,所有其他jpeg将连续跟踪,直到文件结束。该文件的格式为FAT 512字节块** 正如标题所说,我不确定我在做什么来获得分割错误。我曾经尝试过使用valgrind和gcd进行调试,但由于我对编码还很陌生,所以我找不到分段错误的来源。我承认,试图破译这些调试

编辑2:根据我最初的问题,它是通过

风向标

我们发现了对指针基本原理的严重误解。一旦我检查了指针信息,我就解决了分割错误。谢谢大家

作品:

**目标是,给定一个card.raw文件,使用jpeg签名恢复所有jpeg,并假设一旦找到一个jpeg,所有其他jpeg将连续跟踪,直到文件结束。该文件的格式为FAT 512字节块**

正如标题所说,我不确定我在做什么来获得分割错误。我曾经尝试过使用valgrind和gcd进行调试,但由于我对编码还很陌生,所以我找不到分段错误的来源。我承认,试图破译这些调试函数的输出被证明比我预期的更神秘

此外,我还搜索了其他有类似分段错误的人,但我发现的其他人,特别是在这个网站上,都是从代码中的另一个错误中获取错误的,而我(认为)没有

这让我抓狂,因为我似乎已经正确地创建了缓冲区,确保文件总是在不将它们困在条件语句中的情况下打开和关闭,并且正确地利用fwrite创建了块大小正确的jpeg

我感谢所有给予我的帮助

编辑:

根据要求的评论员,以下是我的valgrind输出:

~/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
中中断循环。