Код Мандельброта не интересен при разрешении выше 320 пикселей?

Я изучаю C и пробую новые вещи, чтобы проверить, что я умею. Я написал код, который создает набор Мандельброта с заданным разрешением (RES), равным #define RES в файле .h. Это работает и дает хороший результат для разрешений меньше 321. По какой-то причине, когда RES > 321, код больше не выполняется.

Я использую GCC и рисую вывод с помощью Gnuplot. Я пробовал выполнять отладку с помощью отладчика, но для RES > 321 функция main больше не запускается? Я добавил отпечаток в первую строку main(), чтобы увидеть, но он не запускается. Создан исполняемый файл, и программа компилируется без ошибок?

#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");
}

Я также добавил строку printf("\nFILE CLOSED\n");, чтобы я знал, что результат был записан в файл, но это не запускается с RES > 321.


person Iain McL    schedule 30.05.2019    source источник
comment
Вероятно, у вас закончилось место (stack). Может попробовать malloc() и друзья за complex_grid?   -  person pmg    schedule 30.05.2019
comment
Нужно ли мне тогда переписывать все в терминах указателей (например, * ((a + i)) + j)) или я все еще могу использовать массивы, такие как a [i] [j]?   -  person Iain McL    schedule 30.05.2019
comment
Вы можете использовать нотацию массива для доступа к данным. Фактически, это обычный способ написания кода с использованием динамической памяти.   -  person pmg    schedule 30.05.2019
comment
fprintf(f, "%d ", grid[i][j]); использует несовпадающий спецификатор преобразования, grid[i][j] равно unsigned (может быть преднамеренным)   -  person David C. Rankin    schedule 30.05.2019


Ответы (1)


Вы определяете слишком много данных с автоматическим хранением в функции main(): либо сделайте большие массивы глобальными, статическими, либо выделите их из кучи.

Вот простое решение, которое вы можете попробовать:

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;
}

Вот альтернатива с использованием распределения кучи:

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;
}
person chqrlie    schedule 30.05.2019
comment
Спасибо, статика снова работает только до предела, но с помощью: c complex **complex_grid; complex_grid = malloc(RES*sizeof(complex*)); for(i=0;i<RES;i++){ complex_grid[i] = malloc(RES*sizeof(complex)); } все отсортировано - person Iain McL; 30.05.2019
comment
Существует разница между 2D-массивом, указанным в вопросе, и указателем на массив или указатели, как в вашем комментарии, которые требуют разных прототипов для других функций. Используйте определения из моего ответа, чтобы выделить реальные 2D-массивы из кучи и передать на них указатели. - person chqrlie; 30.05.2019