Code after suggested changes:

 * copy.c
 * Computer Science 50
 * Problem Set 4
 * Copies a BMP piece by piece, just because.

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

#include "bmp.h"

int main(int argc, char* argv[])
    // ensure proper usage
    if (argc != 4)
        printf("Usage: ./copy infile outfile\n");
        return 1;

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

    int n = atoi(argv[1]); 
        if(n<1 || n>100)
                printf("invalid factor\n");
                return 6;

    // open input file 
    FILE* inptr = fopen(infile, "r");
    if (inptr == NULL)
        printf("Could not open %s.\n", infile);
        return 2;

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

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

    // read infile's BITMAPINFOHEADER
    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)
        fprintf(stderr, "Unsupported file format.\n");
        return 4;

     int origwidth = bi.biWidth;
     int origheight = bi.biHeight;
     bi.biWidth = n * bi.biWidth;
     bi.biHeight = n * bi.biHeight;

     // determine padding for scanlines
        int padding =  (4 - (origwidth * sizeof(RGBTRIPLE)) % 4) % 4;
        int padding1 =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
     bi.biSizeImage = (bi.biWidth * sizeof(RGBTRIPLE) + padding1) * abs(bi.biHeight);
     bf.bfSize = 54 + bi.biSizeImage;

    // write outfile's BITMAPFILEHEADER
    fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
    // write outfile's BITMAPINFOHEADER
    fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);

    int seek=0;

    // iterate over infile's scanlines
    for (int i = 0; i < abs(origheight); i++)
     for(int u = 0;u<n;u++)
        // iterate over pixels in scanline
        for (int j = 0; j < origwidth; j++)
            // temporary storage
            RGBTRIPLE triple;

            // read RGB triple from infile
            fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

            // write RGB triple to outfile

          for (int r=0;r<n;r++)
            fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);


         // skip over padding, if any
        fseek(inptr, padding, SEEK_CUR);

        // then add it back (to demonstrate how)
        for (int k = 0; k < padding1; k++)
            fputc(0x00, outptr);

     seek = seek + origwidth+padding;

    // close infile

    // close outfile

    // that's all folks
    return 0;

1 Answer 1


You have FIVE major problems that will break your code, but for now I'll only tell you about the first one, which is causing the seg fault. This one:

argv1 is a string (sometimes a string with length 1, but still a string) and isdigit() is meant to be used with single chars, not strings:

    return 5;

After fixing that, your program will start, but enter an infinite loop. (EDIT: your comment suggests you've fixed it, so I'll tackle the next problem)

EDIT: explaining the integer overflow:

bi.biHeight can be positive or negative, see MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx

Now look at:

bi.biSizeImage = (bi.biWidth * sizeof(RGBTRIPLE) + padding) * bi.biHeight;

See that "bi.biSizeImage" up there has a chance of being negative, because the variable "bi.biHeight" can also be negative.

As the error you're receiving indicates unsigned integer overflow, let's guess that "bi.biSizeImage" is an unsigned long. An unsigned long cannot represent negative numbers, so, long story short to not burden you with low level details: via arithmetic conversion (you can read about it here) bi.biHeight will become a huge positive integer instead of a negative integer.

Then (bi.biWidth * sizeof(RGBTRIPLE) + padding) * bi.biHeight; will be some number multiplied by this now huge number of bi.biHeight, and that will be too big to fit even an unsigned long.

TL;DR: you need to use the absolute value of bi.biHeight.

After fixing that, you'll get a problem regarding skipping the wrong padding. (EDIT: you've solved that by yourself now. Congratulations.)

After fixing that, you'll get a problem related to not using fseek() to go back to the start of the line after the iteration of a certain loop.
EDIT: you've almost solved that by yourself now

But you're setting "int seek" initially to zero, but the image doesn't start at zero! It starts only after the headers, right? So if you use seek = 0, you'll be going all the way back to the beginning of inptr and writing it's headers to the outfile all over again most likely. Your initial value for seek must account for the header. (hint: maybe use ftell() ? ) –

I think that sums it all up.

  • why am i getting overflow? Oct 28, 2016 at 5:56
  • 1
    I'm still trying to figure out how n could ever be less than 0 and greater than 100 at the same time!?!?!?!? ;-)
    – Cliff B
    Oct 28, 2016 at 7:57
  • @CliffB, yeah, that's why I mentioned only the problems that would break his code! Others like these that don't break anything I decided to not even mention for now :) RanjanShrestha... I'll edit my answer adding info about the overflow, given that it seems you've fixed the continuous loop thing. Oct 28, 2016 at 10:30
  • Could you look at my padding problem please since i have edited code Oct 28, 2016 at 11:40
  • 1
    Thank you very much Oct 29, 2016 at 1:13

You must log in to answer this question.

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