#c #segmentation-fault #cs50 #recover
#c #ошибка сегментации #cs50 #восстановить
Вопрос:
Я полный новичок в программировании, и я действительно не могу понять, где я ошибся. Я просмотрел код других людей и изменил множество вещей, но ничего не сработало : / Любая помощь была бы оценена!
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage ./recover imagen");
return 1;
}
FILE *card = fopen(argv[1], "r");
if (card == NULL)
{
printf("ERRORn");
return 1;
}
int jpeg_num = 0;
typedef uint8_t BYTE;
BYTE buffer[512];
char filename[10];
FILE *image = NULL;
while (fread(buffer, sizeof(BYTE), 1, card) == 1)
{
if (buffer[0] == 0xff amp;amp; buffer[1] == 0xd0 amp;amp; buffer[2] == 0xff amp;amp; (buffer[3] amp; 0xf0) == 0xe0)
{
if (jpeg_num > 0)
{
fclose(image);
}
sprintf(filename, "i.jpeg", jpeg_num);
image = fopen(filename, "w");
fwrite(buffer, sizeof(BYTE), 1, image);
jpeg_num ;
}
else
{
fwrite(buffer, sizeof(BYTE), 1, image);
}
}
fclose(image);
fclose(card);
return 0;
}
Комментарии:
1. Если вы запускаете свой код через отладчик, он должен остановить вас на точной строке, где произошел сбой в сегментации (это может быть не та строка, в которой находится ваша ошибка, но если вы проверите значения определенных переменных в этот момент, вы сможете определить это из контекста.)
2.
fread(buffer, sizeof(BYTE), 1, card)
считывается только один байт , но вы просматриваете другие байты в буфере. Всегда записывайте возвращаемое значение изfread
, чтобы вы знали, сколько нужно записать.3.
fwrite(buffer, sizeof(BYTE), 1, image);
в предложении else может / будет срабатывать противNULL
указателя на файл изображения в этом коде. Если предложение if не выполнено хотя бы один раз,image
будет равно null, и этот код вызывает неопределенное поведение.
Ответ №1:
CS50 заставляет программы компилироваться с использованием средства очистки адресов ( -fsanitize=address
), верно? Если это так, вы должны были получить что-то вроде следующего:
ASAN:DEADLYSIGNAL
=================================================================
==4179==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f280eabf92e bp 0x000000000001 sp 0x7fffc6e02bd0 T0)
==4179==The signal is caused by a READ memory access.
==4179==Hint: address points to the zero page.
#0 0x7f280eabf92d in _IO_fwrite (/lib/x86_64-linux-gnu/libc.so.6 0x7f92d)
#1 0x7f281020107f in main /.../a.c:45
#2 0x7f280ea61b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6 0x21b96)
#3 0x7f2810200c79 in _start (/.../a 0xc79)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libc.so.6 0x7f92d) in _IO_fwrite
==4179==ABORTING
(Это из, gcc
а не clang
, но clang
средство очистки адресов должно выдавать нечто подобное.)
Итак, вы попытались прочитать с нулевого адреса. Это может быть NULL
или инициализированный указатель. Мы даже знали, что это произошло при вызове fwrite
в строке 45!
Передаются два указателя на fwrite
, buffer
и image
. buffer
это автоматически выделяемый массив, поэтому он является допустимым указателем. image
с другой стороны, инициализируется следующим образом:
FILE *image = NULL;
Возможно ли, что он никогда не менялся до достижения неудачного вызова fwrite
? ДА. Это плохо.
Комментарии:
1. Спасибо за вашу помощь! Я понимаю, в чем проблема, но где / как мне изменить ее перед fwrite? Извините, я просто не могу понять, что мне нужно добавить :/