0

I'm working on resize (less comfortable) in pset3 and it returns segmentation error when I execute the code. However, when I try to work out which line actually went wrong using debug50 and go through it step by step, the program suddenly worked and successfully create the larger bmp. Can someone take a look on my codes and give me some advice? Thanks a lot in advance!

// Resize a BMP file
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include "bmp.h"

int main(int argc, char *argv[])
{
    // ensure proper usage
    if (argc != 4)
    {
        fprintf(stderr, "Usage: resize infile outfile\n");
        return 1;
    }

    //check value of n
    if (!isdigit(argv[1]))
    {
        fprintf(stderr, "Usage: resize infile outfile\n");
        return 2;
    }

    int n = atoi(argv[1]);
    if (n <= 0 || n > 100)
    {   
        fprintf(stderr, "incorrect resize value\n");
        return 3;
    }

    // remember filenames
    char *infile = argv[2];
    char *outfile = argv[3];

    // open input file
    FILE *inptr = fopen(infile, "r");
    if (inptr == NULL)
    {
        fprintf(stderr, "Could not open %s.\n", infile);
        return 4;
    }

    // open output file
    FILE *outptr = fopen(outfile, "w");
    if (outptr == NULL)
    {
        fclose(inptr);
        fprintf(stderr, "Could not create %s.\n", outfile);
        return 5;
    }

    // read infile's BITMAPFILEHEADER
    BITMAPFILEHEADER bf;
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

    // read infile's BITMAPINFOHEADER
    BITMAPINFOHEADER bi;
    fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);

    // ensure infile is (likely) a 24-bit uncompressed BMP 4.0
    if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 ||
        bi.biBitCount != 24 || bi.biCompression != 0)
    {
        fclose(outptr);
        fclose(inptr);
        fprintf(stderr, "Unsupported file format.\n");
        return 4;
    }

    BITMAPFILEHEADER new_bf = bf;
    BITMAPINFOHEADER new_bi = bi;

    //new biwidth biheight
    new_bi.biWidth = bi.biWidth * n;
    new_bi.biHeight = bi.biHeight * n;

    //padding
    int ori_padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
    int new_padding = (4 - (new_bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    //new bisizeimage
    new_bi.biSizeImage = ((new_bi.biWidth * sizeof(RGBTRIPLE)) + new_padding) * abs(new_bi.biHeight);

    //new bfsize
    new_bf.bfSize = new_bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    // write outfile's BITMAPFILEHEADER
    fwrite(&new_bf, sizeof(BITMAPFILEHEADER), 1, outptr);

    // write outfile's BITMAPINFOHEADER
    fwrite(&new_bi, sizeof(BITMAPINFOHEADER), 1, outptr);

    // iterate over infile's scanlines by n times
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    {
        for (int b = 0; b < n; b++)
        {
            // iterate over pixels in scanline
            for (int j = 0; j < bi.biWidth; j++)
            {
                // temporary storage
                RGBTRIPLE triple;

                // read RGB triple from infile
                fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
                for (int a = 0; a < n; a++)
                {
                    // write RGB triple to outfile
                    fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
                }
            }
            //padding if required
            for (int k = 0; k < new_padding; k++)
            {
                fputc(0x00, outptr);
            }
            //move back cursor 
            if (b < n - 1)
            {
                fseek(inptr, -(bi.biWidth * sizeof(RGBTRIPLE)), SEEK_CUR);
            }
        }
        // skip over padding, if any
        fseek(inptr, ori_padding, SEEK_CUR);
    }
    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}

1 Answer 1

1

You have just learned an important lesson. Seg faults can be muted by debug environments. When this happens, you need to isolate the offending statement using printf statements to see how far execution goes. By strategically placing unique printf statements, you can compile and run the program and see which is the last printf statement to execute and which is the first not to execute. That tells you the offending code is between them. By inserting more unique printf statements, you can get closer and closer until you have the offending line bracketed by two unique printf statements. In this case, the problem is easily found by doing so.

With enough printf statements strategically placed, this technique can also give you a code execution trace, which can be useful.

But since it's so easy to identify the line, I'll skip ahead and describe it. Look at this line:

//check value of n
if (!isdigit(argv[1]))

The isdigit() function takes a single character as an input. However, this line is trying to feed a string to the isdigit() function, causing it to choke on too much data. That generates a seg fault.

You can't test the entire string variable at argv[1] at once. You need to loop through the string and check each char in the string individually.

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

1
  • ah ha... thanks. I should have noticed that as I have used the loop when checking string input in caesar within the last pset!
    – patrickw
    Commented Jun 11, 2019 at 4:55

You must log in to answer this question.

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