Всякий раз, когда вы используете массивы фиксированного размера в C, такие как fullName
, и читаете информацию в массив, вы должны надеть шапку бухгалтера и убедиться, что вы записываете в массив не больше символов, чем он может вместить (меньше 1
символ заканчивающийся нулями символ , если вы собираетесь использовать массив символов в качестве строки)
Как упоминалось в моем первом комментарии, при использовании семейства scanf
вы должны использовать модификатор field-width , чтобы scanf
считывал не более size - 1
символов, чтобы сохранить место для нуль-заканчивающийся символ. В противном случае, scanf
с радостью запишет за пределы вашего массива, вызвав Неопределенное поведение (что означает, что на этом этапе определенное выполнение вашего кода закончено, и ваш код может работать нормально или SegFault - или что-нибудь промежуточное)
Что дает лучший совет, какой только можно дать - Не пытайтесь читать строки ввода пользователя с помощью scanf
. Вместо этого используйте fgets
(или POSIX getline
), чтобы прочитать всю строку за раз, а затем проанализировать все, что вам нужно из строки (или, если вы используете всю строку в качестве строки, просто обрежьте '\n'
с конца) , Таким образом, то, что остается в вашем входном буфере, не зависит от используемого scanf
спецификатора преобразования (который мучает новых программистов на C без конца ...)
При вводе пользовательского ввода вы всегда должны защищать пользователя от отмены ввода, вводя Ctrl + d (или Ctrl + z в окнах), чтобы создать руководство EOF
. Вы делаете это, проверяя возвращение любой используемой вами функции ввода.
Если вы хотите убедиться, что пользователь дает вам действительный ввод (или отменяет его), просто поместите ваше приглашение и прочитайте его в непрерывный цикл и break;
цикл, как только вход удовлетворяет всем вашим условиям.
При чтении более одного ввода в один и тот же буфер, например fullName
, помогает сохранить переменную, содержащую количество символов available
(или remaining
). Таким образом, вместо проверки полного размера буфера для вашего второго ввода, вы проверяете оставшиеся символы в буфере, чтобы проверить, подойдет ли ваш lastName
(плюс один дополнительный символ для " "
(пробел) между первым / фамилия.
Чтобы убедиться, что входные данные будут соответствовать, считайте во временный буфер достаточного размера (* Не экономьте на размере буфера!), Например,
#include <stdio.h>
#include <string.h>
#define MAXN 128u /* if you need a constant, #define one (or more) */
#define MAXC 1024u /* max line buffer size */
int main(void)
{
char buf[MAXC]; /* buffer to hold input */
char fullName[MAXN]; /* 128 chars for first/last will do */
size_t available = MAXN - 1; /* avaliable chars in fullName */
Выше у вас есть временный буфер 1024
символов - которого должно быть более чем достаточно, если пользовательский кошка не ложится спать на клавиатуре. Вы прочитаете в буфер символов 1024
и затем проверите, будет ли он соответствовать символам available
для fullName
. Комбинируя это с непрерывным циклом чтения, вы можете сделать:
for (;;) { /* loop continually until valid input or user cancels */
size_t length; /* string funcitons use size_t */
printf ("Please enter the first name: ");
if (!fgets (buf, MAXC, stdin)) { /* use fgets - validate */
fputs ("(user canceled input)\n", stdout);
return 0;
}
buf[(length = strcspn (buf, "\r\n"))] = 0; /* trim trailing '\n' */
if (length > available) { /* validate length - and save length */
fprintf (stderr, "error: name must have < %zu characters.\n",
available);
}
else { /* name fits - copy */
strcpy (fullName, buf);
available -= length;
break;
}
( примечание: нет необходимости в firstName
или lastName
, так как вы вводите оба в fullname
. Просто читайте с buf
и добавляйте к fullName
по ходу дела)
Также обратите внимание на использование strcspn
, которое возвращает количество символов в строке, НЕ содержащейся в наборе исключения "\r\n"
. Таким образом, он считывает количество символов в строке вплоть до первого найденного конца строки - а затем перезаписывает строку, заканчивающуюся нулем (как '\0'
), чтобы завершить нулем в этой точке. Вы можете использовать strlen
, но strcspn
может сделать это за вас, включив набор исключений, позволяющий завершить в одной команде.
Чтение фамилии практически идентично имени, за исключением того, что когда вы собираетесь добавить фамилию к fullName
, вам необходимо добавить " "
, прежде чем вы это сделаете. Разница:
else { /* name fits, concatenate space and lastName */
strcat (fullName, " ");
strcat (fullName, buf);
available -= length + 1;
break;
}
В целом, вы можете сделать:
#include <stdio.h>
#include <string.h>
#define MAXN 128u /* if you need a constant, #define one (or more) */
#define MAXC 1024u /* max line buffer size */
int main(void)
{
char buf[MAXC]; /* buffer to hold input */
char fullName[MAXN]; /* 128 chars for first/last will do */
size_t available = MAXN - 1; /* avaliable chars in fullName */
for (;;) { /* loop continually until valid input or user cancels */
size_t length; /* string funcitons use size_t */
printf ("Please enter the first name: ");
if (!fgets (buf, MAXC, stdin)) { /* use fgets - validate */
fputs ("(user canceled input)\n", stdout);
return 0;
}
buf[(length = strcspn (buf, "\r\n"))] = 0; /* trim trailing '\n' */
if (length > available) { /* validate length - and save length */
fprintf (stderr, "error: name must have < %zu characters.\n",
available);
}
else { /* name fits - copy */
strcpy (fullName, buf);
available -= length;
break;
}
}
for (;;) { /* ditto - above comments */
size_t length;
printf ("Please enter the last name : ");
if (!fgets (buf, MAXC, stdin)) {
fputs ("(user canceled input)\n", stdout);
return 0;
}
buf[(length = strcspn (buf, "\r\n"))] = 0;
if (length > available - 1) { /* -1 to account for space */
fprintf (stderr, "error: name must have < %zu characters.\n",
available - 1);
}
else { /* name fits, concatenate space and lastName */
strcat (fullName, " ");
strcat (fullName, buf);
available -= length + 1;
break;
}
}
printf ("\nThe full name is: '%s'\n", fullName);
return 0;
}
Пример использования / вывода
$ ./bin/first_last
Please enter the first name: Samuel
Please enter the last name : Clemens
The full name is: 'Samuel Clemens'
или случай, когда пользователь отменяет ввод:
$ ./bin/first_last
Please enter the first name: (user canceled input)
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.