Добавление члена 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, нарушает его. У меня есть ощущение, что это связано с этим предыдущим вопросом , но я забиваю все, что нужно забрать (я думаю). Любая помощь будет оценена по достоинству.
Ответов (4)4
В ваших операторах malloc есть ошибка. Вы нарушаете указатель, а не структуру. Это дает вам только 4 байта памяти вместо фактического размера, требуемого вашей структурой.
black = malloc(sizeof(*black));
При выделении памяти для указателя необходимо выделить память для объекта, на который он указывает, а не для типа указателя. Если вы просто напишете, sizeof(*black)
как показано, вы всегда получите правильный тип, даже если тип black
изменится.
На первый взгляд кажется, что вы используете дополнительный уровень косвенного обращения к указателям, и это вызывает segfault. Когда вы выделяете память, это указатель на объект, а не указатель на указатель на объект. Итак, у вас будет:
img = (struct image *)malloc(sizeof(struct image))
img->o = 0
Ой, код был отключен; Я забыл избежать знака «меньше чем». Вот:
#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;
}
У JaredPar есть правильный ответ, но если вы получите segfault, первое, что нужно сделать, это запустить программу под valgrind. Это огромная помощь в решении подобных проблем.
Кстати, я потратил дни на эту точную ошибку. Будьте счастливы, что вы столкнулись с этим в начале своей карьеры программиста на C, и всегда будете следить за этим в будущем.