1

https://github.com/KRegan82/Tinkering/blob/master/sierpinskiBMP.c

(Code retrieved 2017-11-05 — may not be identical to the original, which is another reason to require code in the question.)

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


// data types for the standard MS sruct values for the headers
typedef uint8_t  BYTE;
typedef uint32_t DWORD;
typedef int32_t  LONG;
typedef uint16_t WORD;

//bmp file header struct
typedef struct
{
    WORD bfType;
    DWORD bfSize;
    WORD bfReserved1;
    WORD bfReserved2;
    DWORD bfOffBits;
} __attribute__((__packed__))
BITMAPFILEHEADER;

//bmp info header struct
typedef struct
{
    DWORD biSize;
    LONG biWidth;
    LONG biHeight;
    WORD biPlanes;
    WORD biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG biXPelsPerMeter;
    LONG biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
} __attribute__((__packed__))
BITMAPINFOHEADER;

//bmp pixel struct
typedef struct
{
    BYTE rgbtBlue;
    BYTE rgbtGreen;
    BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
// this program is designed to 'build' a sierpinski triangle of n layers given the users input. triangle built from top down using 2 x 2 pixel structure
// the structs above are completely 'borrowed' from the team at harvards cs50 class, whose mobile IDE is also wehre I wrote this
// and a special thank you to Irene Naya and Aditya Singhania two strangers on facebook for whom I couldn't have made this without
int main(void)
{
    //prompt for and store height (in 2x2 pixel size)
    fprintf(stderr, "How many layers do you want? ");
    int n = get_int();

    //setup paramaters to write to .bmp file and filename

    char ofName[21];
    sprintf(ofName,"sierpinski%05i.bmp",n);
    FILE *outfile = fopen(ofName,"w");

    // setup file header and info header assignments
    BITMAPFILEHEADER bf;
    BITMAPINFOHEADER bi;

    //calculate header and header info values to write using structs in bmp.h
    bi.biWidth = (n * 2) + 4;
    bi.biHeight = 0 -((n * 2) + 4);

    //calculate padding that will be needed
    int pad = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // assign new image size
    bi.biSizeImage = abs(bi.biHeight) * ((bi.biWidth * sizeof(RGBTRIPLE)) + pad);

    // assign new file header parameters

    bf.bfType = 0x4d42;
    bf.bfReserved1 = 0;
    bf.bfReserved2 = 0;
    bf.bfOffBits = 0x36;

    //assign new info header parameters
    bi.biSize = 0x28;
    bi.biPlanes = 1;
    bi.biBitCount = 24;
    bi.biCompression = 0;
    bi.biXPelsPerMeter = 0xb12;
    bi.biYPelsPerMeter = 0xb12;
    bi.biClrUsed = 0;
    bi.biClrImportant = 0;

    // assign new file size
    bf.bfSize = bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

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

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

    //necessary variables for triangle algorithm
    long long body[n][n];
    int print = 0;

    //create rgp triple for manipulation
    RGBTRIPLE pixel;

    //add buffer lines to top of .bmp
    for(int i = 0; i< ((n * 2) + 4); i++)
    {
        pixel.rgbtRed = 0xff;
        pixel.rgbtBlue = 0xff;
        pixel.rgbtGreen = 0xff;
        fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
    }

    //add padding in if necessary
    for (int l = 0; l < pad; l++)
    {
        fputc(0x00, outfile);
    }

    // second layer of top buffer lining
    for(int i = 0; i< ((n * 2) + 4); i++)
    {
        pixel.rgbtRed = 0xff;
        pixel.rgbtBlue = 0xff;
        pixel.rgbtGreen = 0xff;
        fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
    }
    //add padding in if necessary
    for (int l = 0; l < pad; l++)
    {
        fputc(0x00, outfile);
    }
    // iterate over the area and print necessary digits
    for(int i = 0; i < n ; i++)
    {
        // blank space that borders triangle value
        int blankCount = (n + 1) - i;
        //write blank space surrounding start of triangle
        for(int j = 0; j < blankCount; j++ )
        {
            pixel.rgbtRed = 0xff;
            pixel.rgbtBlue = 0xff;
            pixel.rgbtGreen = 0xff;
            fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
        }
        //draw first line of this rows triangle values
        for(int j = 0; j<=i; j++)
        {


            if (j == 0 || i == j)
            {
                print = 1;
                body[i][j] = 1;
            }

            else if( body[i-1][j-1] + body[i-1][j] == 2 || body[i-1][j-1] + body[i-1][j] == 0)
            {
                print = 0;
                body[i][j] = 0;

            }
            else if(body[i-1][j-1] + body[i-1][j] == 1 )
            {
                print = 1;
                body[i][j] = 1;

            }

            if ( print == 0)
            {
                pixel.rgbtRed = 0xff;
                pixel.rgbtBlue = 0xff;
                pixel.rgbtGreen = 0xff;
                fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
                fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
            }
            else if (print == 1)
            {
                pixel.rgbtRed = 0x00;
                pixel.rgbtBlue = 0x00;
                pixel.rgbtGreen = 0x00;
                fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
                fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
            }

        }
        // proceeding blank space bordering back end of triangle
        for(int j = 0; j < blankCount; j++ )
            {
                pixel.rgbtRed = 0xff;
                pixel.rgbtBlue = 0xff;
                pixel.rgbtGreen = 0xff;
                fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
            }
        //add back in if necessary
        for (int l = 0; l < pad; l++)
        {
            fputc(0x00, outfile);
        }
        //this is really just a second iteration of drawing the same row. each row has to be drawn twice because each element is 2 pixels by two pixels

        for(int j = 0; j <blankCount ; j++ )
        {
            pixel.rgbtRed = 0xff;
            pixel.rgbtBlue = 0xff;
            pixel.rgbtGreen = 0xff;
            fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
        }

        for(int j = 0; j<=i; j++)
        {


            if (j == 0 || i == j)
            {
                print = 1;
                body[i][j] = 1;
            }

            else if( body[i-1][j-1] + body[i-1][j] == 2 || body[i-1][j-1] + body[i-1][j] == 0)
            {
                print = 0;
                body[i][j] = 0;

            }
            else if(body[i-1][j-1] + body[i-1][j] == 1 )
            {
                print = 1;
                body[i][j] = 1;

            }

            if ( print == 0)
            {
                pixel.rgbtRed = 0xff;
                pixel.rgbtBlue = 0xff;
                pixel.rgbtGreen = 0xff;
                fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
                fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
            }
            else if (print == 1)
            {
                pixel.rgbtRed = 0x00;
                pixel.rgbtBlue = 0x00;
                pixel.rgbtGreen = 0x00;
                fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
                fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
            }

        }
        for(int j = 0; j < blankCount; j++ )
            {
                pixel.rgbtRed = 0xff;
                pixel.rgbtBlue = 0xff;
                pixel.rgbtGreen = 0xff;
                fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
            }
        //add padding in if necessary
        for (int l = 0; l < pad; l++)
        {
            fputc(0x00, outfile);
        }

    }
    // add buffer lines to bottom of .bmp
    for(int i = 0; i< ((n * 2) + 4); i++)
    {
        pixel.rgbtRed = 0xff;
        pixel.rgbtBlue = 0xff;
        pixel.rgbtGreen = 0xff;
        fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
    }
    //add padding in if necessary
    for (int l = 0; l < pad; l++)
    {
        fputc(0x00, outfile);
    }
    for(int i = 0; i< ((n * 2) + 4); i++)
    {
        pixel.rgbtRed = 0xff;
        pixel.rgbtBlue = 0xff;
        pixel.rgbtGreen = 0xff;
        fwrite(&pixel, sizeof(RGBTRIPLE), 1, outfile);
    }
    //add padding in if necessary
    for (int l = 0; l < pad; l++)
    {
        fputc(0x00, outfile);
    }
    // just tidying up here
    fclose(outfile);
    return 0;
}

I am taking CS50 class, and wrote this program to output a Sierpinski triangle to a .bmp file of a user given height. It works fine for generating anything up to and a somewhat over 512 rows, but at 1024 (the next complete triangle height) I get a seg fault.

Not sure why this is happening, is it because I'm allocating memory off of the stack and not the heap? Any help would be appreciated.

Here is the segment of code where I initialize the array that keeps track of the values each pixel should hold.

 long long body[n][n];

I changed it to a long long hoping that would fix the problem, but clearly it's something else. Puzzled.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Kyle Regan
  • 13
  • 2
  • 5
    Make a [MCVE] and post it here. – Jabberwocky Nov 01 '17 at 19:56
  • 2
    _is it because I'm allocating memory off of the stack and not the heap?_ So why don't you try to allocate memory elsewhere than on the stack? – Jabberwocky Nov 01 '17 at 19:58
  • Not sure how to allocate a 2 dimensional array with pointers and malloc, but I guess I need to figure that out. – Kyle Regan Nov 01 '17 at 20:08
  • Try to make a static global array. – Jabberwocky Nov 01 '17 at 20:15
  • All arrays are global in c I thought. Also, how could I declare it globally before I gather the n size where it bases it's dimensions off of? – Kyle Regan Nov 01 '17 at 20:21
  • Give it some a fixed size, if it it's too big it doesn't matter. And when it works then you have some clue where the problem might be. – Jabberwocky Nov 01 '17 at 20:38
  • Did that and it worked, tried it declaring the array in the body of the code, and it caught a segmentation fault between size of n = 1018 and 1019. Still puzzled as to why. – Kyle Regan Nov 01 '17 at 21:10
  • After having a look at the code, As mentioned by @WeatherVane. When the value of `i = 0` you are trying to access the memory which is not allocated(`body[i-1][j-1]` line 164). that's is when segmentation fault happens. – yadhu Nov 01 '17 at 21:25
  • Will just reading (not writing) out of bounds cause a seg fault? – Bachman Nov 01 '17 at 21:32
  • Couldn't it be that when trying to allocate on the stack 1019*1019 long longs, it's just too big for the stack? – Bachman Nov 01 '17 at 21:34
  • @Yadhunandana I deleted that comment because I misread the `j` loop. – Weather Vane Nov 01 '17 at 21:34
  • @KyleRegan you said "tried declaring the array in the body of the code" but that will still be on the stack. Define the array as a global array, before any code body, to validate the code. Likely you will need dynamic allocation, if the dimensions are not know in advance. – Weather Vane Nov 01 '17 at 21:37
  • Or just malloc the array inside the function. – Bachman Nov 01 '17 at 21:39
  • 1
    @bachman has a point. It is too much memory to be allocated in stack, Why don't you use heap? – yadhu Nov 01 '17 at 21:39
  • 1
    Obviously, but @KyleRegan already answered earlier comments to that effect, saying *Not sure how to allocate a 2 dimensional array with pointers and malloc, but I guess I need to figure that out.* – Weather Vane Nov 01 '17 at 21:48
  • @KyleRegan, you say "Still puzzled as to why". The reason is because the stack usually has a very small size compared to the heap. – Weather Vane Nov 01 '17 at 21:49
  • I'm still puzzled because I don't see why declaring the array globablly matters since all arrays are globally accessible in C I thought. Does declaring an array globally (i.e. before the main function) allocate the memory from the heap instead of the stack? – Kyle Regan Nov 02 '17 at 04:43
  • Either way, it is working if I either declare the array globally or if I allocate the memory dynamically. Now I'm bumping into file size limitations for bitmaps, I could probably stretch the parameters a bit more if I switch the format to black and white since that's all it uses anyway, but that will have to wait till another day, lol. – Kyle Regan Nov 02 '17 at 05:07

1 Answers1

0

Your body[n][n] array is too large to be allocated on the stack. You can allocate it on the heap instead where you will be much less limited by size. See previous answer for how to dynamically allocate a 2d array: Allocate memory 2d array in function C

Bachman
  • 701
  • 1
  • 6
  • 25
  • Hey, thank you. The link you provided worked great! I'm going to pour over it though as I'm not sure how it did work, like, why do we use three ***'s when passing the array to the function? Also, what does setting the *array inside the parentheses do? – Kyle Regan Nov 02 '17 at 05:03
  • "Not sure how it worked" - take a look at this [answer](https://stackoverflow.com/questions/19240540/dynamically-allocating-array-explain/19240932#19240932) – Bachman Nov 02 '17 at 07:28
  • Literally just joind yesterday . Not enough clout to vote. – Kyle Regan Nov 02 '17 at 12:38