Определите ошибку, вызывающую ошибку сегментации (сброс ядра)

#c #pointers #segmentation-fault #cs50

Вопрос:

Я новичок в программировании на си. Решил, что буду учиться, выполняя некоторые из задач, поставленных в открытом учебном пособии cs50. Следующий код выдает ошибку ошибки сегментации (сброс ядра). Я не могу понять, почему. Я читал, что ошибка сегментации связана с доступом к памяти, к которой у вас нет доступа. Я не понимаю, что могло бы быть причиной этого. Я предполагаю, что это связано с указателями. Я новичок в указателях. Спасибо.

 #include lt;stdio.hgt;  // https://cs50.harvard.edu/x/2021/labs/1/population/  float yearly_llamas(float starting_population) {  // returns number of llamas at the end of the year  float born = starting_population / 3;  float died = starting_population / 4;  float end_of_year_pop = starting_population   born - died;   return end_of_year_pop; }  int main(void) {    // use floats for precision  float *start_population;  float *end_population;   // set start lower limit  int start_min = 9;     // make sure input for starting population is greater than or equal to 9  do {  printf("Starting population: ");  scanf("%f", start_population);  } while (*start_population lt; start_min);       // get ending population, make sure greater than or equal to the starting population  do {  printf("Ending population: ");  scanf("%f", end_population);  } while (*end_population lt; *start_population);   // print for verification  printf("%fn", *start_population);  printf("%fn", *end_population);   float end_pop = yearly_llamas(*start_population);   printf("Llamas at the end of the year: %fn", end_pop);    return 0; }  

Комментарии:

1. Сейчас самое время научиться отлаживать. Запустите свою программу в отладчике, и она укажет вам точную строку кода, которая вызывает ошибку seg. Также можно использовать отладчик для отслеживания/проверки потока кода и значений переменных.

2. float *start_population; объявляет неинициализированный указатель. scanf("%f", start_population); пытается прочитать данные и записать их в этот указатель. Мораль этой истории в том, что не используйте указатели, если вам это не нужно, но если вы это сделаете, убедитесь, что они указывают на правильную память. В вашем случае используйте float sp; scanf("%f", amp;sp);

3. float *start_population; scanf("%f", start_population); Это не сработает, как start_population неинициализированный указатель. Попробуй float start_population; scanf("%f", amp;start_population);

Ответ №1:

Вы объявили указатель на float, но этот указатель просто ни на что не указывал, потому что вы не назначили ему адрес.

Измените эти строки

 float *start_population; float *end_population;  

Для

 float f_start_population; float f_end_population; float *start_population = amp;f_start_population; float *end_population = amp;f_end_population;  

следует устранить ошибку сегментации.

Ответ №2:

В то время как другой ответ подсказывает вам решение, я хочу подчеркнуть способ поиска (и решения) такого рода проблем: используйте отладчик. Это важный инструмент программиста, и лучше всего научиться использовать его раньше, чем позже. В этом случае ваша проблема достаточно проста, чтобы ее можно было легко найти с помощью любого отладчика. Позже, когда вы будете работать с более сложным кодом и многопоточностью, вам будет трудно научиться его использовать, пока вы пытаетесь решить свою (сложную) проблему. Пожалуйста, попробуйте решить эту проблему самостоятельно с помощью отладчика.

Если вы работаете в Linux, вы можете использовать gdb и запускать код до тех пор, пока он не выйдет из строя. Затем вы проверяете backtrace ( bt ), чтобы увидеть последнюю выполненную строку. Наконец, вы определяете точку останова ( p #n где #n номер строки) в предыдущей строке сбоя, проверяете значения ( p $variable с $variable именем вашей переменной) и пытаетесь понять, почему это не работает.

С отладчиком графического интерфейса это должно быть проще (например, с Visual Studio или Code::blocks).

Ответ №3:

Когда вы объявляете переменную указателя f, например, таким float *f; образом, вы можете «использовать» ее только в том случае, если указатель фактически указывает на зарезервированную вами память (термин выделен). Вы можете либо выделить переменную в «куче» с помощью malloc() функции, либо, что проще, создать отдельную переменную в стеке (называемую автоматической переменной), написав float my_float; и используя ее. Таким образом, вы получаете:

 float my_startfloat; float *start_population = amp;my_startfloat;  

Тем не менее, я бы объявил только плавающую (первую) строку, а затем, при необходимости, использовал ее адрес: amp;my_startfloat . Например:

 float my_startfloat;  scanf("%f", amp;my_startfloat);