1
N ° 1. В ответ на: «недопустимая или неправильная практика». Некоторые из них являются скорее вопросами вкуса…
- Если вы «должны» использовать
scanf
, не указывайте его на строковом буфере с помощью %s
: укажите длину буфера, например, от %32s
до уменьшите (но возможно не исключайте, что кто-то просто слишком много печатал и ломал вашу программу (или хуже ...) - Но, читайте № 3 ниже, чтобы узнать больше по этому вопросу…
- Если вы разрабатываете что-то с открытым исходным кодом или для личного использования, GNU
readline
- очень хороший вариант (но это GPL , а не LGPL , так что он может не будет использоваться в "не-libre" работах ...)
- Ваш инициализатор структуры не охватывает все элементы. Вы можете использовать
{"", "", "", ""}
- Вы имели в виду
fwrite(entry)
?
Если вы проверяете пропущенные поля перед записью файла, вы можете оставить банк флагов в стороне и вместо этого зацикливаться на «недействительном условии».
while ('\0' == entry.firstname[0]) {
printf("Please enter first name: \n");
scanf("%40[^\r\n\0\04]", &entry.firstname[0]);
}
Нет необходимости открывать файл так рано и оставлять его открытым в ожидании взаимодействия с пользователем. Открытие файла в режиме a+
является довольно «опасным» (см. man lockf
для «тощего»), потому что кто-то другой может попытаться записать файл в то время, пока вы находитесь; если оставить его открытым в этом режиме на длительное время, риск возрастет.
- Вам, вероятно, следует использовать
strerror(errno)
для предоставления пользователю подробной информации о сбое системного вызова, например, при проверке кодов возврата fopen
, fwrite
и fclose
. Из-за того, что буферизованный ввод / вывод работает, fclose
может даже сообщать о проблеме, возникшей с fwrite
при некоторых обстоятельствах.
- Напечатайте ваши сообщения об ошибках на
stderr
, используя fprintf (stderr,
… );
вместо выходного потока…
- Если вы собираетесь использовать флаги для указания того, что данные являются «действительными» (или, по крайней мере, таковыми могут быть), вам, вероятно, следует сделать это после после Пользователь пытается ввести его, а не раньше.
- Функции - ваши друзья ... Я бы, вероятно, разбил что-то вроде этого, используя функцию для сбора ввода пользователя (что-то вроде
prompt_for_field ("first name", &entry.firstname);
), функцию для проверки пропущенных записей и запроса их, а также функцию для записи запись в файл, не менее…
- Обычно считается хорошей формой
exit
с main
, а не return
, например, с использованием exit(EXIT_SUCCESS)
/ exit(EXIT_FAILURE)
. Я считаю, что идея заключается в поддержке эзотерических и возможных вымерших систем, которые могут рассматривать некоторые значения, отличные от 0
, как успешный код состояния (VMS, возможно?), Но, тем не менее, легче читать: -)
2
И № 2, да, вы можете fwrite(entry)
, и до тех пор, пока вы никогда не измените определение struct contact
, вы сможете прочитать его обратно в полном порядке. Со временем вы, вероятно, захотите переключиться на более простой текстовый формат (#include <json-xml-init-religious-war>
), но в этом небольшом примере нет острой необходимости вводить такую сложность.
3
Наконец, N ° 3, вам, вероятно, следует использовать &entry.address[0]
, чтобы получить адрес начала char[]
, но наиболее важно: scanf %s
не читает строку. Это выглядит как printf %s
, но это не ...
s Соответствует последовательности символов без пробелов; следующий
указатель должен быть указателем на символ
массив, который достаточно длинный, чтобы содержать входную последовательность и завершающий нулевой символ ('\ 0'),
который добавляется автоматически. Строка ввода останавливается на пустом месте или на максимальной ширине поля,
что произойдет первым.
Видите это "не пробел?"«Это то, что у вас есть. Остальная часть вашего ввода (после первого пробела) остается в буфере клавиатуры, ожидая, пока другой scanf
его прочитает. Хороший ('ish) способ чтения из терминала и принятия пробела -%40[^\r\n\0\04]
, заменив 40 размером вашего строкового буфера (char[]
). Это означает, что можно принять (до) 40 символов, если только они не являются: возврат каретки, новая строка,нулевой байт или код конца файла (^D
).
В целом, вы все равно на правильном пути. Удачи: -)