C-структуры: ошибка сегментации

Быстрый вопрос о структурах:

struct xint {
     int number;
     char string[12];
};

int main(int argc, char *argv[])
{
  struct xint offsets, *poffsets;
  poffsets=&offsets;
  FILE * pFile = fopen("file","rb");
  fread(poffsets,1,16,pFile);
  printf("Number %d\nString %s\n",offsets.number,offsets.string);
}

Я получаю этот вывод

Number 12345
Segmentation fault

Я знаю, что, вероятно, сделал что-то не так со структурами, указателями и распределением памяти. Заранее спасибо :)


person Hamish Milne    schedule 12.05.2011    source источник


Ответы (4)


Ваша проблема в том, что вы напрямую читаете структуру из файла, не проверяя выравнивание структуры. Сделайте это вместо этого:

  fread(&offset.number,1,sizeof(offsets.number),pFile);
  fread(&offset.string,1,sizeof(offsets.string),pFile);
person Andrea    schedule 12.05.2011
comment
printf все равно будет работать над этим, если строка не заканчивается 0. - person joce; 12.05.2011
comment
&offset.string является избыточным — потеряйте &, потому что offset.string уже является указателем на буфер. - person Heath Hunnicutt; 12.05.2011
comment
Альтернативой также может быть просмотр пакета #pragma, чтобы убедиться, что структура правильно выровнена для вызова fread для всей структуры... - person forsvarir; 13.05.2011

Я подозреваю, что данные файла, которые вы читаете, не заканчивают строку символом NUL ('\0'). По определению строк C, которое соблюдается printf() стандартной библиотеки C, строка должна заканчиваться символом NUL.

Возможно, вам будет лучше, если вы всегда (посредством кода) будете следить за тем, чтобы .string[11] = '\0'.

ИЛИ объявите string[13] и убедитесь, что string[12] = '\0'

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

person Heath Hunnicutt    schedule 12.05.2011

Я предполагаю, что строка не завершается нулем в файле, и ваш код также ничего не делает для завершения строки нулем.

fread(poffsets, 1, 16, pFile);
offsets.string[11] = '\0';
printf("Number %d\nString %s\n", offsets.number, offsets.string);

Или измените файл, чтобы строка заканчивалась нулевым байтом.

person Nick Meyer    schedule 12.05.2011
comment
Символ \0 равен NUL, указатель равен NULL, в противном случае строки завершаются нулем, а не нулем. Нуль в нижнем регистре означает буквально ничего, в отличие от нуля, который ничего не представляет. Таким образом, строка с завершающим нулем будет строкой без завершения. ;) Вы читали Алису в стране чудес или знакомы с Магриттом? Это не труба. - person Heath Hunnicutt; 12.05.2011
comment
Это решение перезапишет последний символ прочитанной строки. - person joce; 13.05.2011

Вы получаете переполнение буфера. Ваша строка состоит из 12 символов, но у вас нет места для завершающего '\0'.

Если вы сделали:

struct xint {
     int number;
     char string[16]; // Make sure you have enough space for the string + '\0'.
};

int main(int argc, char *argv[])
{
    struct xint offsets, *poffsets;

    // Initialize your memory to 0. This will ensure your string is 
    // '\0'-terminated.
    // FYI, sizeof(xint) here is 20.
    memset(&offsets, 0, sizeof(xint)); 

    poffsets=&offsets;
    FILE * pFile = fopen("file","rb");
    fread(poffsets,1,16,pFile);
    fclose(pFile);
    printf("Number %d\nString %s\n",offsets.number,offsets.string);
}

Это решило бы проблему.

person joce    schedule 12.05.2011
comment
Это бы скрыло проблему. Строка из 12 символов по-прежнему будет segfault (в коде OP или 16 в этой версии). - person Mel; 13.05.2011
comment
Я не знаю, что вы подразумеваете под этим, чтобы скрыть проблему. Этот код работает просто отлично. Я включил весь код, чтобы вы поняли идею. Концепция выделения достаточного количества памяти и обеспечения того, чтобы ваша строка была завершена '\ 0', - это то, что имеет значение в текущем контексте, и мое решение четко решает эту проблему IMO - person joce; 13.05.2011
comment
Ах, 16 было преднамеренно. Думал опечатка. Дело в том, что размер вашей структуры теперь не синхронизирован с вашим fread, который вы обычно кодируете как fread(poffsets, 1, sizeof(struct xint), pFile) - person Mel; 13.05.2011