Я получаю бесконечную работающую программу, когда использую следующий код для чтения строки с клавиатуры и сохранения ее в структурированном векторе.
scanf("%s", strk_zgr_fp->bezeichnung, (int)sizeof(strk_zgr_fp->bezeichnung - 1));
Просто ничего не происходит после того, как эта строка будет достигнута, и программа будет работать бесконечно.
Я знаю, что scanf() не рекомендуется. Мы используем его только в рамках нашего курса C для начинающих, и я хочу, чтобы вы помнили об этом, то есть, пожалуйста, не рекомендуйте на данный момент другие функции, кроме упомянутых выше.
Любая помощь очень ценится, заранее спасибо.
#include <stdio.h>
typedef struct {
int nummer;
char bezeichnung;
int menge;
float preis;
} artikel;
void eingabe_artikel(artikel *strk_zgr_fp, int i_fp);
void ausgabe_artikel(artikel *strk_zgr_fp, int i_fp);
void main(void) {
artikel artikelliste[10];
artikel *strk_zgr;
int anzahl;
do {
printf("Bitte eine #Artikel eingeben [<= 10]: ");
scanf("%d", &anzahl);
if (anzahl < 1 || 10 < anzahl)
printf("\nEs wurde eine falsche #Artikel eingegeben.");
} while(anzahl < 1 || 10 < anzahl);
for(int i = 0; i < anzahl; i++)
eingabe_artikel(&artikelliste[i], i);
int i;
for(strk_zgr = artikelliste, i = 0; strk_zgr < artikelliste + anzahl;
strk_zgr++, i++)
ausgabe_artikel(strk_zgr, i);
}
void eingabe_artikel(artikel *strk_zgr_fp, int i_fp) {
printf("\nBitte den %d. Artikel eingeben: ", ++i_fp);
printf("\nNummer: ");
scanf("%d", &strk_zgr_fp->nummer);
printf("Bezeichnung: );
scanf("%s", strk_zgr_fp, (int)sizeof(strk_zgr_fp->bezeichnung - 1)); /* <-- */
printf("Menge: ");
scanf("%d", &strk_zgr_fp->menge);
float preis;
printf("Preis: );
scanf("%f", &preis);
strk_zgr_fp->preis = preis;
}
void ausgabe_artikel(artikel *strk_zgr_fp, int i_fp) {
printf("\n%d. Artikel: ", ++i_fp);
printf("\nNummer:\t%d", strk_zgr_fp->nummer);
printf("\nBezeichnung:\t%s", strk_zgr_fp->bezeichnung);
printf("\nMenge:\t%d", strk_zgr_fp->menge);
printf("\nPreis:\t%.2f EUR\n", strk_zgr_fp->preis);
}
Также у scanf("%s", one, two); на 1 аргумент слишком много.
и вам действительно следует проверить возвращаемое значение scanf (и большинство функций с прототипом в <stdio.h>): if (scanf(...) != EXPECTED_ASSIGNMENTS) /* error */;
Вы не проверяете, действительно ли scanf() работал.
Я понимаю, что вы все еще учитесь, поэтому я просто хочу убедиться, что вы усвоили дополнительный важный урок: проблемы, которые у вас возникают, - это именно Почему, часто рекомендуется избегать использования scanf. scanf оказывается плохо определенной функцией. Он плохо работает, его трудно использовать правильно, с ним трудно, если вообще возможно, делать более сложные вещи. Опытные программисты на C его вообще не используют; он используется только новичками. Но так как им так сложно пользоваться, у новичков с всегда возникают проблемы.
Если бы вводные учебники C и начинающие инструкторы C прекратили обучать программистов C использованию scanf, C стало бы намного проще для новичков.
Одна большая проблема с циклом, который читает целое число с использованием scanf("%d", &anzahl);, - это то, что происходит, когда вы вводите что-то, что не начинается с необязательного пробела, за которым следует необязательный знак +/-, за которым следует цифра. В этом случае scanf вернет 0, а входной поток останется на позиции нецифрового символа. Итак, когда вы снова обойдете цикл, этот нецифровой символ все еще будет там, и он точно так же выйдет из строя.
(At) Стив: Спасибо за ваш комментарий. Мне известно о проблемах, связанных с устаревшей функцией scanf (). Курс Си написан еще в 2009 году, во всяком случае, даже не в первые дни Си. Однако я хотел бы следовать всем примерам. К сожалению, они используют эту плохо определенную функцию. (At) Ян: Спасибо за ваш комментарий. Я постараюсь помнить о вашей рекомендации всякий раз, когда сталкиваюсь с такой ситуацией.





Много проблем в коде. Пожалуйста, исправьте хотя бы недостающие конечные кавычки в вызовах printf ().
Теперь к говядине:
1) Ваша структура неверна. «Bezeichnung» определяется как отдельный символ, а не строка.
typedef struct {
int nummer;
char bezeichnung[100];
int menge;
float preis;
} artikel;
2) Вы не можете использовать scanf () так, как вы это делали. Если вы хотите ограничить длину ввода (что всегда является хорошей идеей), вам необходимо передать максимальную длину в строку формата. Вам нужно использовать scanf () ?? Потому что с этого момента все становится грязным .... Поскольку максимальная длина ввода может быть переменной или изменяться (см. 1.), вам необходимо создать строку формата для scanf. Что-то вроде этого:
char format_str[15];
format_str[0] = '%';
//Dont use itoa(), it is not C standard.
sprintf(&format_str[1], "%d", (int)sizeof(strk_zgr_fp->bezeichnung) - 1);
strcat(format_str, "s");
scanf(format_str, strk_zgr_fp->bezeichnung);
Надеюсь, это поможет вам.
PS: Вам нужно включить string.h для strcat ().
Альтернатива char format_str[15]; ... strcat(format_str, "s"); -> char format_str[1+20+1 +1]; sprintf(format_str, "%%" "%zu" "s", sizeof(strk_zgr_fp->bezeichnung) - 1);
Ты следуешь за мной? ;) Во всяком случае, почему это: format_str [1 + 20 + 1 +1]; ?
Ваше хорошее решение в 3 строчки кода можно просто сделать более плотным с 1 sprintf(). Я предложил больший размер буфера (1 для%, 20 для обработки всех размеров до 2 ^ 64, 1 для s, 1 для \ 0), поскольку 15 казался неясным для его происхождения.
@chux Хорошо, я вижу, что вы делаете. Когда я пытаюсь написать код для очевидных новичков, я стараюсь писать его так, чтобы они были легко понятны. Это может означать неэлегантный код ... Но разве цель ответов на вопросы - помочь людям лучше понять? То же самое и с простым алгоритмом. И да, 15 было совершенно произвольным.
Re: «То же самое и с основным алгоритмом» -> Не следую за вами - просто совпадение, поскольку у нас, очевидно, есть общие интересы.
Относительно «герметичности» кода: конечно, как программист на C я это ценю. Однако в контексте вопроса OP ясно, что он / она не понимает строки форматирования для семейства функций scanf / printf. Зачем делать это ненужным? Я намеренно написал код, который разбивал все на мелкие кусочки ... И вообще, всегда есть вопрос о кратком коде или явном коде. Это означает удобочитаемость (для человека). После стольких десятилетий программирования на разных языках я бы сказал: удобочитаемость имеет первостепенное значение. Только мои 2 цента.
(At) GermanNerd: Спасибо за ответ. 1) Моя ошибка, в примере кода вместо одного символа определена строка. 2) Я попробую и дам вам знать, если это решит мою проблему.
Я попробовал, и у меня все сработало. Не уверен в этой функции sprintf (). Не могли бы вы объяснить, почему я должен его использовать? К настоящему времени я использовал этот код: char format_str[20]; format_str[0] = '%'; strcat(format_str, "s"); printf("Bezeichnung: "); scanf(format_str, strk_zgr_fp->bezeichnung);
Извините за то, что опять беспокою вас. Был еще один пример, который я сделал, и руководитель курса предоставил функцию scanf (), подобную этой, для чтения строки: scanf("%s", &(strk_zgr_fp->bezeichnung));. Я думал, что когда я читаю строку, адресный оператор не используется. Единственная разница в том, что теперь используется адресный оператор, а элемент заключен в квадратные скобки.
I tried it out and it worked fine for me. Not sure on this sprintf() function. Could you please explain why I'm supposed to use it? By now, I used this code: char format_str[20]; format_str[0] = '%'; strcat(format_str, "s"); printf("Bezeichnung: "); scanf(format_str, strk_zgr_fp->bezeichnung);
Хотя это работает, вы упускаете возможность ограничить длину ввода пользователя. Вот почему я предложил использовать sprintf () для создания (под) строки, содержащей максимально допустимую длину пользовательского ввода, в зависимости от того, насколько большой ваш bezeichnung определен в структуре. Предположим, что 'bezeichnung' имеет ограничение в 100 символов, вы хотите ограничить ввод до 99 (+1 для нулевого завершения), поэтому вам нужна строка формата scanf, подобная этой: «% 99s».
chux предоставил гораздо более компактную версию моих трех строк, но я думаю, что вначале вам будет проще просто собирать такие строки формата по частям, в то же время узнавая, как а) изменять отдельные символы в string, как использовать sprintf () в основном и как объединять строки с помощью strcat ().
There was another example which I did and the course leader provided a scanf() function like this to read a string: scanf("%s", &(strk_zgr_fp->bezeichnung));. I thought when I'm reading a string the address operator isn't used. The only difference is the address operator now is used and the element was put into brackets.
Я считаю, что это плохая практика. Работает, но лишнее. Рассмотрим этот небольшой фрагмент кода:
#include <stdio.h>
#include <stdlib.h>
struct test{
int i;
char a_str[10];
};
int main()
{
struct test a_test;
printf("Normal array adress taking: %p\n", a_test.a_str);
printf("Using '&' to take adress of array: %p\n", &(a_test.a_str));
return 0;
}
Надеюсь, это поможет.
вы не можете сканировать в структуру. вы должны включить сканирование в член структуры.