#c #segmentation-fault
#c #ошибка сегментации
Вопрос:
Я пытаюсь просто назначить элемент, определенный как Card
из вектора mtr[i][j]
, 2d-матрице, хранящейся в куче, но отладчик заявляет об ошибке сегментации.
Я думаю, что я перепробовал все, пробовал со статической матрицей, проверял часы NULL
, назначая вручную каждый элемент структуры.
Просто из любопытства я попытался изменить тип матрицы на int
и char
. Несмотря на это, присвоение (после правильного изменения значения на присвоение) не работает.
int g_rows = 0, g_cols=0;
typedef struct{
char color;
int points;
}Segment;
typedef struct{
Segment h;
Segment v;
}Card;
Card** loadBoard(char* fileName, Card* cards) {
short tileRef; short rot;
short i=0;
FILE* fp = fopen(fileName,"r"); if(fp == NULL) return NULL;
if(fscanf(fp, "%hd %hdn", amp;g_rows, amp;g_cols) == 0) {fclose(fp); return NULL;}
Card **mtr = (Card**)malloc(g_rows * sizeof(**mtr)); if(!mtr){printf("Error on first malloc.n");}
for(short i = 0; i<g_rows; i ) {
mtr[i] = (Card*)malloc(g_cols * (sizeof (*mtr)) );
if(!mtr[i]) printf("error on 2nd malloc.n");
}
i=0;
while(!feof(fp)){
for(short j=0;j<g_cols;j ) {
fscanf(fp, "%d/%dn", amp;tileRef, amp;rot);
if (tileRef != -1)
mtr[i][j] = (rot == 0) ? cards[tileRef] : (Card) {.h = cards[tileRef].v, .v = cards[tileRef].h};
else
mtr[i][j] = (Card){{.points=-1,.color=''},{.points=-1,.color=''}};
}
fscanf(fp,"bn"); i ;
}
fclose(fp);
return mtr;
}
Я пытался искать подобные проблемы, но слишком странно, что в итоге я изучил примеры кода для динамического распределения 2d.
Возможно, я пропустил что-то важное, но я действительно не могу это уловить.
ОКОНЧАТЕЛЬНОЕ РЕДАКТИРОВАНИЕ: я обнаружил, что виновником был компилятор, который я использовал (Clang / LLVM от MinGW). Я попытался установить Visual Studio Community в качестве набора инструментов по умолчанию в CLion, и никаких проблем не возникло.
Комментарии:
1. Есть две переменные
g_rows
иg_cols
которые не были объявлены.2. Почему плохо использовать feof() для управления циклом
3. @csawy Я всегда думал, что это не так безопасно, как счетчик. Я попробовал это впервые, увидев это на слайдах колледжа. Спасибо.
4. @anfauglit извините, исправлено для уточнения.
5. У вас есть некоторые ошибки в ваших
fscanf
вызовах.%d
является спецификатором формата дляint
, и%hd
дляshort int
. Кажется, у вас они задом наперед. Ваш компилятор должен предупредить вас об этом, если у вас включены предупреждения (что и должно быть).
Ответ №1:
Проблема, по-видимому, заключается в незначительных опечатках в вызовах malloc.
- При распределении матрицы,
Card **mtr = (Card**)malloc(g_rows * sizeof(**mtr));
malloc выделяет пространство для
g_rows * sizeof(Card)
. Но поскольку mtr используется для хранения указателей на карты, а не карт, мы хотимg_rows * sizeof(Card*)
. - Затем при выделении каждой строки матрицы,
mtr[i] = (Card*)malloc(g_cols * (sizeof (*mtr)) );
malloc выделяет пространство для
g_cols * sizeof(Card*)
. Но поскольку каждая строка матрицы используется для хранения карточек, а не указателей на карточки, мы хотимg_cols * sizeof(Card)
. Эта ошибка, в частности, является плохой, потому что sizeof(Card *) меньше, чем sizeof(Card), поэтому выделяется недостаточно памяти.
Существует также потенциальная проблема ниже в цикле while, который считывает данные из файла. Цикл повторяется до тех пор, пока файл продолжается, без проверки, находится ли i
переменная все еще в границах. Таким образом, если файл неправильно отформатирован, это может привести к тому, что этот код будет списывать конец матрицы и segfault.
Комментарий: Я настоятельно рекомендую использовать Valgrind или средство очистки адресов (ASan). Эти инструменты автоматически проверяют наличие ошибок, связанных с памятью, и имеют неоценимое значение для отладки подобных проблем.
Комментарии:
1. Существует распространенная идиома написания
ptr = malloc(length * sizeof(*ptr))
. Этот код, похоже, пытается это сделать, но немного ошибается; если все сделано последовательно, первым экземпляром будетCard **mtr = malloc(g_rows * sizeof(*mtr));
и второйmtr[i] = malloc(g_cols * sizeof(*mtr[i]));
.2. @PascalGetreuer Вы правы в последней части, я уже изменил управление циклом. В первом случае я инициализировал 2d-матрицу, используя соответственно
sizeof(Card*)
иsizeof(Card)
, но позже я неправильно изменил их, используя имя переменной. Однако исправленный код @NateEldredge по-прежнему не работает. Я попробую с ASan позже.