Как вы говорите в своем вопросе, вы не можете использовать scanf для чтения сложного имени, включая пробелы.
Но прежде чем искать как сделать это, необходимо решить, что делать.
Возможно, вы не хотите запоминать лишние пробелы в начале и в конце (включая перевод строки), и, вероятно, имя не должно быть пустым.
Но как насчет сложного имени?Если пользователь вводит John Lays
, сохраняете ли вы имя с двумя пробелами или хотите упростить, чтобы иметь только один?Вам нужно управлять другими специальными символами, такими как '-' (John - Lays
/ John- Lays
/ John -Lays
читается как John-Lays
?).
Что делать, если длина входной строки больше 10персонажи ?Просто прекратить читать, оставляя остальное для следующего чтения или обходить новую строку?Поскольку вы печатаете сообщение перед каждым вводом, вам явно требуется ввод для каждой строки, а остальная часть строки должна быть пропущена.
Если вы не хотите читать строку в том виде, в каком она есть, лучше всего ввестинаписать свою собственную функцию чтения строки.
Вы также должны решить, что делать, если пользователь не введет число для ID или Potencia или Avariado, в настоящее время вы даже не обнаруживаете ошибку, это не очень хороший способ.Таким образом, в этом случае вы все отменяете (программа выхода), или вы переделываете чтение?Вероятно, вы предпочитаете читать снова, для этого вам нужно пропустить неверный ввод, но что это значит, чтобы обойти все до новой строки?
Например:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* read an int memorizing its value in v,
return 0 in case of EOF else a non null value */
int readInt(const char * msg, int * v)
{
for (;;) {
fputs(msg, stdout);
if (scanf("%d", v) == 1)
return 1;
/* not a number or EOF, bypass all up to \n */
int c;
while ((c = fgetc(stdin)) != '\n')
if (c == EOF)
return 0;
puts("invalid value"); /* message may be also get in argument */
}
}
/* read a string up to a \n
remove extra spaces at the beginning and end
simplify internal multiple spaces
accept any character and do not manage in a special way characters like like '-'
a non empty string must be read
read at most sz-1 characters in s then place the null character (as fgets), sz must be > 1
if the line too long bypass the rest of the input up to \n
return 0 in case of EOF else a non null value */
int readStr(const char * msg, char * s, size_t sz)
{
fputs(msg, stdout);
/* read the first char bypassing spaces including \n */
if (scanf(" %c", s) == 0)
// EOF
return 0;
size_t index = 1;
int c;
sz -= 1;
while (index != sz) {
c = fgetc(stdin);
if ((c == EOF) || (c == '\n'))
break;
if (!isspace(c))
s[index++] = c;
else if (s[index - 1] != ' ')
s[index++] = ' ';
}
s[(s[index - 1] != ' ') ? index : index-1] = 0;
// bypass possible rest of the line
while ((c != EOF) && (c != '\n'))
c = fgetc(stdin);
return 1;
}
/* ******************* */
struct estruturaCarro {
int id, potencia, avariado;
char name[11];
} carro;
int main()
{
do {
if (!readInt("\n ID......:", &carro.id) ||
!readInt("\n Potencia:", &carro.potencia) ||
!readInt("\n Avariado:", &carro.avariado) ||
!readStr("\n NAME:", carro.name, sizeof(carro.name))) {
puts("EOF");
return -1;
}
else
printf("%-2d %-3d %-1d '%-10s' \n\n", carro.id, carro.potencia, carro.avariado, carro.name);
} while (strcmp(carro.name, "end"));
return 0;
}
Компиляция иВыполнение:
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall r.c
pi@raspberrypi:/tmp $ ./a.out
ID......:aze
invalid value
ID......:qsd
invalid value
ID......:1
Potencia:2
Avariado:3
NAME:aze u iiiiiiiiiiiiiiiiii
1 2 3 'aze u iiii'
ID......:11
Potencia:22
Avariado:0
NAME: end
11 22 0 'end '
pi@raspberrypi:/tmp $
Когда вы читаете в своем файле и предполагаете, что он был создан с помощью fprintf(fp, "%-2d %-3d %-1d %-10s", ...)
:
char line[21]; /* each line has 20 characters newline included */
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%d %d %d", &carro.id, &carro.potencia, &carro.avariado) != 3)
/* abnormal case, invalid file */
break; /* anything else you want to do */
/* the string starts at the index 9 and has 10 characters out of the newline */
memcpy(carro.name, line + 9, 10);
carro.name[10] = 0;
/* ... */
}
, обратите внимание, что имя имеет пробелы в конце, если его длина меньше10 символов
Или вы можете прочитать так же, как и в предыдущем случае на стандартном вводе.