1

I am learning C and trying new things to test what I can do. I have written code which produces a Mandelbrot set with a given resolution (RES) which is #define RES in the .h file. This works and produces good output for resolutions less than 321. For some reason when RES > 321 then the code no longer executes.

I am running using GCC and plotting the output using Gnuplot. I have tried debugging with a debugger however for RES > 321 the main function no longer gets run? I have added a print in the first line of main() to see and this doesn't get run. An executable is made and the program compiles with no errors?

#include <stdio.h>
#include <math.h>

#define MAX_DEPTH 100
#define RES       321

typedef struct complex_t {
    double re;
    double im;
} complex;

void init_complex_grid(complex complex_grid[RES][RES], double left, double right, double top, double bottom);
int converge(complex a);
complex add_complex(complex a, complex b);
complex square_complex(complex a);
double mag_complex(complex a);
void output_grid(unsigned int grid[RES][RES]);

int main(void) {
    // printf("HERE\n");
    int i, j;
    unsigned int convergence_grid[RES][RES];
    complex complex_grid[RES][RES];
    init_complex_grid(complex_grid, -2.5, 1, 1, -1);
    for (i = 0; i < RES; i++) {
        for (j = 0; j < RES; j++) {
            convergence_grid[i][j] = converge(complex_grid[i][j]);
        }
    }
    output_grid(convergence_grid);
    return 0;
}

void init_complex_grid(complex complex_grid[RES][RES], 
                       double left, double right, 
                       double top, double bottom) {
    int i, j;
    double restep = (top - bottom) / RES;
    double imstep = (right - left) / RES;
    for (i = 0; i < RES; i++) {
        for (j = 0; j < RES; j++) {
            complex_grid[i][j].re = left + j * imstep;
            complex_grid[i][j].im = bottom + i * restep;
        }
    }
}

int converge(complex a) {
    complex z = { 0, 0 };
    int cnt = 0;
    while (cnt <= MAX_DEPTH && mag_complex(z) <= 2) {
        z = add_complex(square_complex(z), a);
        cnt++;
    }   
    return cnt;
}

complex add_complex(complex a, complex b) {
    complex added = { a.re + b.re, a.im + b.im };
    return added;
}

complex square_complex(complex a) {
    complex b;
    b.re = a.re * a.re - a.im * a.im;
    b.im = 2 * a.re * b.im;
    return b;
}

double mag_complex(complex a) {
    return sqrt(a.re * a.re + a.im * a.im);
}

void output_grid(unsigned int grid[RES][RES]) {
    FILE *f = fopen("mandelbrot.dat", "w");
    int i, j;
    for (i = 0; i < RES; i++) {
        for (j = 0; j < RES; j++) {
            fprintf(f, "%d ", grid[i][j]);
        }
        fprintf(f, "\n");
    }
    fclose(f);
    printf("\nFILE CLOSED\n");
}

I also added the line printf("\nFILE CLOSED\n"); so I would know that the output had been written to the file but this does not get run either with RES > 321.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Iain McL
  • 164
  • 1
  • 10
  • You probably run out of (*stack*) space. Maybe try `malloc()` and friends for `complex_grid`? – pmg May 30 '19 at 12:26
  • Do I then need to rewrite everything in terms of pointers (such as *((a+i)) + j)) or can I still use arrays like a[i][j]? – Iain McL May 30 '19 at 12:57
  • You can use array notation to access the data. In fact it's the usual way to write code using *dynamic memory*. – pmg May 30 '19 at 13:02
  • `fprintf(f, "%d ", grid[i][j]);` uses a mismatched conversion specifier, `grid[i][j]` is `unsigned` (may be intentional) – David C. Rankin May 30 '19 at 13:27

1 Answers1

1

You are defining too much data with automatic storage in the main() function: either make the large arrays global, static or allocate them from the heap.

Here is a simple fix you can try:

int main(void) {
    int i, j;
    static unsigned int convergence_grid[RES][RES];
    static complex complex_grid[RES][RES];
    init_complex_grid(complex_grid, -2.5, 1, 1, -1);
    for (i = 0; i < RES; i++) {
        for (j = 0; j < RES; j++) {
            convergence_grid[i][j] = converge(complex_grid[i][j]);
        }
    }
    output_grid(convergence_grid);
    return 0;
}

Here is an alternative using heap allocation:

int main(void) {
    int i, j;
    unsigned int (*convergence_grid)[RES] = calloc(sizeof(*convergence_grid), RES);
    complex (*complex_grid)[RES] = calloc(sizeof(*complex_grid), RES);
    if (!convergence_grid || !complex_grid) {
        fprintf(stderr, "cannot allocate arrays\n");
        return 1;
    }
    init_complex_grid(complex_grid, -2.5, 1, 1, -1);
    for (i = 0; i < RES; i++) {
        for (j = 0; j < RES; j++) {
            convergence_grid[i][j] = converge(complex_grid[i][j]);
        }
    }
    output_grid(convergence_grid);
    free(complex_grid);
    free(convergence_grid);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Thanks, static again only worked up to a limit but using: ```c complex **complex_grid; complex_grid = malloc(RES*sizeof(complex*)); for(i=0;i – Iain McL May 30 '19 at 13:36
  • There is a difference between a 2D array as posted in the question and a pointer to an array or pointers as in your comment that require different prototypes for the other functions. Use the definitions from my answer to allocate real 2D arrays from the heap and pass pointers to them. – chqrlie May 30 '19 at 13:40