0

Pset4 Recover is different since it uses files; fopen, fcloser, fprintf, and fread. It adds a whole new dimension to the coding. Its change from just formatting conceptions to making sure all the files are opened closed and written to properly.

I've learned enough of these concepts to put together the following code that compiles. It passes the first three checks in check50. But when running the program it still gives segmentation fault. I'm at a loss of knowing what part needs attention. I thought it should at least run.

And explanation of it a little more conceptually as well as what the code is missing would be greatly appreciated.

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


int main(int argc, char *argv[])
{

    if (argc != 2)
    {
        fprintf(stderr, "Usage: ./recover image\n");
        return 1;
    }

    FILE * fPointer;
    fPointer = fopen("card.raw", "r");

    if (fPointer == NULL)
    {
        printf("Error: File does not exist\n");
        return 1;
    }

    // Output file file for picture set to 0   
    FILE *img = NULL; 

    unsigned char* buffer = NULL;
    char filename[8];

    // Counter for image labels set to 0
    int counter = 0;

    // Checking flag for use of loops
    bool check = false;
    int i = 0;

    // open memory card
    // look for beginning of a jpeg (0xff 0xd8 0xff 0xe_)
    // if jpeg, open and make new jpeg file
    // if not skip forward 512 bytes 
    // when found write 512 bytes chunks until a new jpeg  is found
    // stop, make new file, and continue the process
    // until you read end of file

    while (fread(buffer, 512, 1, fPointer) == 512)
    {           

        //Else close and continue reading
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {   

            // Yes?
            if (check == false)
            {
                fclose(fPointer);
                sprintf(filename, "%03i.jpg", i);
                img = fopen(filename, "w");
                fwrite(&buffer, 512, 1, img);
                fclose(img);

                counter++;
                i++;
                check = true; 
                //fopen(fPointer, "r");
            }

            // No?
            if (check == true)
            {
                fclose(fPointer);
                img = fopen(filename, "a");
                fwrite(&buffer, 512, 1, img);
                fclose(img);
            }

            if (check == true && counter > 0)
            {
                fclose(fPointer);
                sprintf(filename, "%03i.jpg", i);
                img = fopen(filename, "w");
                fwrite(&buffer, 512, 1, img);
                fclose(img);

                counter++;
                i++;
            }

        }

    }        

fclose(fPointer);
fclose(img);

//Success
return 0;

}
  • Did you find the line that's causing the seg fault yet? – Cliff B Apr 27 '20 at 4:08
  • I did! It's this line while (fread(buffer, 512, 1, fPointer) == 512) Looking over questions by others some people have used '&buffer' instead but it's still a seg fault. And changing '==512' to '!= EOF' I went with this as my new condition and it works for only one more line until it reaches the 'if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)' condition. Which is frustrating because that's one part I was sure was sound. while (fread(&buffer, 1, 512, fPointer) == 512) – wardthomas17 Apr 29 '20 at 14:02
  • Also troubles with the debugger tool. From what I understand you set the break points on the left of the line with the little red dots right? Then run debug50 and the side bar will pop up on the right and step through each line of code. But when I try this with a few break points set it just falls right through and ends the debugger and automatically closes down the side bar. It's not very helpful. – wardthomas17 Apr 29 '20 at 14:08
3

First, you really, really need to learn how to determine which line is generating a seg fault in any program! Seg faults are going to occur over and over and over. This is one of the most critical skills - identifying which line causes a problem!!!! I can't stress this enough!!!!

There are two common ways to track down a seg fault. One is to run the program in a debugger. Set breakpoints at strategic places (for instance, the first line of a significant code block) and see which is the last breakpoint that you get to before it breaks. Then you know it's between the last breakpoint that will execute and the next breakpoint past where the code failed. Then, just narrow it down with more breakpoints, or simply step through the code line by line until you find the line that has the seg fault. Remember, seg faults occur at a specific point, not in a general area.

However, sometimes, running inside a debugger won't actually generate the seg fault. It can actually mask the problem, although that's rare. In this case, insert print statements in the code (just like breakpoints described above) and see which unique printf statement is the last to print. Eventually, you'll have a printf before and one after the bad code and you'll know which is causing the problem.

THAT's the first phase. FIND the offending code! You must perfect this skill!!!!

So, when you can tell me which line of code is causing the problem and have tried to fix it, post a message here. If you really can't find the problem, I'll help you with it then. But you need to at least find the line with the problem!!! ;-)

Here's a hint. It's an easy fix for an experienced programmer. It may be hard for you, simply because you just haven't had the experience yet! That's not bad or good. It just "is". You'll get the experience by doing this!!! ;-)

[EDIT]

Great!!!!! You've found the offending line!!!! That's half the battle!!!

while (fread(buffer, 512, 1, fPointer) == 512)

This is generating a seg fault. Why? It's trying to read from the file at fPointer and write it into buffer. There are likely two possibilities, a problem with the input file or with the buffer. The input file appears to have been opened correctly. But what about buffer? What is it? It's a pointer to memory. What's it currently pointing at? Null??????????? Is the fread trying to write to a null pointer?????? Where is it supposed to put the data?

Some advice. Dynamically allocating memory with a pointer and a malloc is great when you don't know how much memory will be needed and you need to use more and more memory. But, when you need a fixed amount of memory that you're going to reuse over and over, like buffer, it's better to allocate a simple var or array. In this case, it would be more efficient to allocate a char array large enough to hold the largest word possible and just reuse it.

This while loop will never run. What does fread return??? It returns the number of elements read, i.e., the third parameter, not the size of the elements (the second parameter). That means that it will do the read and return the 3rd parameter or a smaller number when it reads less elements. But in this case, it will never return 512. It returns 1 on a successful read or 0 on a failed read (like EOF).

As for debug50, you need to practice with it and see how it behaves. Just spend some quality time with it and learn how it works.

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .