#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);