Добавление члена int в структуру C вызывает segfault

Я все еще изучаю C и начал использовать его для создания изображений. Я не могу понять, почему одна из моих программ дает сбой. Вот исходный код, урезанный до 40 строк:

#include <stdio.h>
#include <stdlib.h>
struct color {
        unsigned char r, g, b;
};
struct image {
        int w, h/*, o*/;
        struct color **data;
};
int main() {
        // Declarations
        int x, y;
        struct color *black;
        struct image *img;
        // Set up color black
        black = (struct color *) malloc(sizeof(struct color *));
        black->r = 0;
        black->g = 0;
        black->b = 0;
        // Set up image img
        img = (struct image *) malloc(sizeof(struct image *));
        img->w = 1;
        img->h = 1;
        /*img->o = 0;*/
        img->data = (struct color **) malloc(img->h * sizeof(struct color *));
        for (y = 0; y < img->h; y++) {
                img->data[y] = (struct color *) malloc(img->w * sizeof(struct color));
        }
        // Fill in img with black
        for (x = 0; x < img->w; x++) {
                for (y = 0; y < img->h; y++) {
                        img->data[y][x].r = black->r;
                        img->data[y][x].g = black->g;
                        img->data[y][x].b = black->b;
                }
        }
        // Free black
        free(black);
        // Free img
        for (y = 0; y < img->h; y++)
                free(img->data[y]);
        free(img->data); // Segfaults
        free(img); // Also segfaults
        return 0;
}

Он компилируется и работает нормально (используя gcc в Ubuntu и Vista с Cygwin), но раскомментирование двух строк, относящихся к img-›o, ломает его. У меня есть ощущение, что это связано с этим предыдущим вопросом, но я не могу все, что нужно malloc'ed (я думаю). Любая помощь будет оценена по достоинству.


person Community    schedule 24.02.2009    source источник


Ответы (4)


В ваших операторах malloc есть ошибка. Вы выделяете указатель, а не структуру. Это дает вам только 4 байта памяти вместо фактического размера, требуемого вашей структурой.

black = malloc(sizeof(*black));

При выделении памяти для указателя вам нужно выделить память для объекта, на который указывает указатель, а не для не типа указателя. Если вы просто напишете sizeof(*black), как показано, вы всегда получите правильный тип, даже если тип black изменится.

person JaredPar    schedule 24.02.2009
comment
этот способ тоже верный и более понятный, ИМХО: black = malloc(sizeof(struct black)); - person Tiago; 05.06.2010

На первый взгляд кажется, что вы используете дополнительный уровень косвенности указателя, и это вызывает segfault. Когда вы выделяете память, это указатель на объект, а не указатель на указатель на объект. Итак, у вас будет:

img = (struct image *)malloc(sizeof(struct image))
img->o = 0
person sykora    schedule 24.02.2009
comment
Вам не нужно (и не следует) приводить возвращаемое значение malloc() в C. - person aib; 24.02.2009

У JaredPar есть правильный ответ, но если вы получите segfault, первое, что нужно сделать, это запустить программу под valgrind. Это огромная помощь в решении подобных проблем.

Кстати, я потратил дни на эту ошибку. Радуйтесь, что вы столкнулись с этим в начале своей карьеры программиста на C, и всегда будете следить за ним в будущем.

person twk    schedule 24.02.2009

Упс, код обрезался; Я забыл экранировать знак "меньше". Вот:

#include <stdio.h>
#include <stdlib.h>
struct color {
    unsigned char r, g, b;
};
struct image {
    int w, h/*, o*/;
    struct color **data;
};
int main() {
    // Declarations
    int x, y;
    struct color *black;
    struct image *img;
    // Set up color black
    black = (struct color *) malloc(sizeof(struct color *));
    black->r = 0;
    black->g = 0;
    black->b = 0;
    // Set up image img
    img = (struct image *) malloc(sizeof(struct image *));
    img->w = 1;
    img->h = 1;
    /*img->o = 0;*/
    img->data = (struct color **) malloc(img->h * sizeof(struct color *));
    for (y = 0; y < img->h; y++) {
        img->data[y] = (struct color *) malloc(img->w * sizeof(struct color));
    }
    // Fill in img with black
    for (x = 0; x < img->w; x++) {
        for (y = 0; y < img->h; y++) {
            img->data[y][x].r = black->r;
            img->data[y][x].g = black->g;
            img->data[y][x].b = black->b;
        }
    }
    // Free black
    free(black);
    // Free img
    for (y = 0; y < img->h; y++)
        free(img->data[y]);
    free(img->data);
    free(img);
    // Return
    return 0;
}
person Community    schedule 24.02.2009