Мне нужна помощь!
Неважно, что я ввожу, я получаю тот же результат, как будто программа не читает ввод из scanf, какие-нибудь идеи?
Я попытался получить ввод отдельно, чтобы разделить scanf, чтобы получить 8 scanf. Но безуспешно.
Если бы вы могли помочь мне и указать на то, что я делал неправильно, я был бы признателен!
struct point{
double x;
double y;
}pt1,pt2,pt3,pt4;
struct rect{
struct point pt1;
struct point pt2;
struct point pt3;
struct point pt4;
};
int main()
{
struct rect new_screen = {
scanf("%f,%f",&new_screen.pt1.x,&new_screen.pt1.y),
scanf("%f,%f",&new_screen.pt2.x,&new_screen.pt2.y),
scanf("%f,%f",&new_screen.pt3.x,&new_screen.pt3.y),
scanf("%f,%f",&new_screen.pt4.x,&new_screen.pt4.y),
};
printf("the middle between (%.2f,%.2f) and (%.2f,%.2f) is ",new_screen.pt1.x,new_screen.pt1.y,new_screen.pt3.x,new_screen.pt3.y);
print_point(middle(new_screen.pt1,new_screen.pt3));
return 0;
}
struct point middle(struct point pt1, struct point pt2)
{
struct point tmp = {((pt1.x+pt2.x)/2),((pt1.y+pt2.y)/2)};
return tmp;
}
void print_point(struct point pt)
{
printf("(%.2f,%.2f)",pt.x,pt.y);
}
output
the middle between (2.00,2.00) and (0.00,0.00) is (1.00,1.00)
Пожалуйста, всегда включайте предупреждения в вашем компиляторе. Для GCC вы должны добавить -Wall -Wextra -Wpedantic
. Это покажет вам ряд предупреждений.
Это здесь инициализация ...
struct rect new_screen = {
scanf("%f,%f",&new_screen.pt1.x,&new_screen.pt1.y),
scanf("%f,%f",&new_screen.pt2.x,&new_screen.pt2.y),
scanf("%f,%f",&new_screen.pt3.x,&new_screen.pt3.y),
scanf("%f,%f",&new_screen.pt4.x,&new_screen.pt4.y),
};
... не делает то, что вы думаете. scanf
возвращает одно целое число (см. Его справочную страницу, чтобы узнать значение возвращаемого значения), но ваша структура содержит поля struct point
. В сумме получается 8 дублей и 4 звонка на scanf
. Из-за того, как инициализация работает в C, вы можете опустить фигурные скобки и инициализаторы для некоторых полей. Так что это, к сожалению, действительный код. Но он инициализирует только new_screen.pt1
и new_screen.pt2
(четыре вызова scanf
инициализируют четыре двойных). То, что вы отсканировали в них, немедленно перезаписывается. Последние две точки не инициализируются фигурными скобками, поэтому они должны начинаться с нуля, снова перезаписывая все, что вы, возможно, отсканировали в них.
Короче говоря, предполагая, что все вызовы scanf
не терпят неудачу (и мы игнорируем проблему со спецификаторами формата), вы, по сути, написали следующее:
struct rect new_screen = {
{ 2, 2 },
{ 2, 2 },
{ 0, 0 },
{ 0, 0 }
};
Менее ошибочной инициализацией будет:
struct rect new_screen;
scanf("%lf,%lf",&new_screen.pt1.x,&new_screen.pt1.y);
scanf("%lf,%lf",&new_screen.pt2.x,&new_screen.pt2.y);
scanf("%lf,%lf",&new_screen.pt3.x,&new_screen.pt3.y);
scanf("%lf,%lf",&new_screen.pt4.x,&new_screen.pt4.y);
Он не проверяет, что scanf
прошел успешно (поэтому это только менее ошибочный), но он не будет вытеснять содержимое new_screen
возвращаемым значением scanf
. Я также исправил спецификатор формата (вы использовали %f
, но переменные double
требуют %lf
).
Вышеупомянутые ошибки также свидетельствуют о том, насколько важна компиляция с включенными предупреждениями и как их устранять. Например, когда я скомпилировал ваш код с помощью gcc -pedantic-errors -Wall -Wextra
, я получил следующие предупреждения:
warning: format '%f' expects argument of type 'float *', but argument 2 has type 'double *' [-Wformat=]
scanf("%f,%f",&new_screen.pt1.x,&new_screen.pt1.y),
warning: missing braces around initializer [-Wmissing-braces]
struct rect new_screen = {
warning: missing initializer for field 'pt3' of 'struct rect' [-Wmissing-field-initializers]
};
Возьмите за привычку компилировать с включенными предупреждениями и устраняйте их, пока сборка не освободится от диагностики компилятора.
Хорошо видно по запятым. Я думаю, что начинающему программисту нужно немного больше объяснений; это довольно незаметно.
@JonathanLeffler - Хорошее предложение. Я попытался затронуть это немного больше в редактировании, надеюсь, достаточно, чтобы понять суть дела новичка. Я не знаю, как глубоко в это вникать, чтобы новичку не переборщить.
Я не знаю, слишком ли он подробен, но я могу предположить, что исходный инициализатор эквивалентен struct rect new_screen = { { 2, 2 }, { 2, 2 }, { 0, 0 }, { 0, 0 } };
, потому что scanf()
вызывает return 2 (если строки формата фиксированы), и эти возвращенные значения перезаписывают первые четыре элемента структур , а остальные поля инициализируются нулями после того, как вызовы scanf()
установили значения. Таким образом, данные, считанные со стандартного ввода, стираются при инициализации. Я спорил, записывать ли в инициализаторах 2.0
вместо 2
; лень оставила их целыми числами.
@JonathanLeffler - Написание эквивалентного инициализатора - отличная идея. Я добавил это. Спасибо!
@JonathanLeffler - Проголосуйте за эти хорошие предложения находятся или нет. Так что все равно спасибо :)
@JonathanLeffler Большое спасибо! эта информация мне очень помогла! Я начал заниматься информатикой в университете из интереса. Это оказалось очень сложно, но, поскольку такие люди, как вы, я продолжаю изучать что-то новое каждый раз, когда сталкиваюсь с проблемой, спасибо!
@StoryTeller, спасибо! еще один вопрос - будет ли сканирование данных во внутренние структурные переменные лучше выполняться с помощью malloc?
@YaroslavMiloslavsky - не понимаю, зачем тут нужен malloc
. Нет никакого обращения к динамическому распределению памяти.
Вы используете формат
%f
для чтения значенийdouble
. Это неопределенное поведение (%f
для типовfloat
;%lf
дляdouble
). Современные компиляторы обычно предупреждают об этом; если у вас нет, найдите варианты включения предупреждений или получите лучший компилятор.