C : scanf 和空格。我已经尝试了几乎所有的东西,目前正在学习 struct
C : scanf and whitespaces. I've tried almost everything , currently learning about struct
我搜索了整个网络,但还没有找到真正的解决方案(也许我没有用 google 搜索正确的词,我不知道)。
但我们在这里:这是我的第一个带有结构的 C 项目,我尝试使用 gets 和 puts 来克服 printf-scanf 的空格问题,但是 gets 导致了很多问题(程序直接跳到 puts , 没有 gets) 所以我进入了本论坛另一位嘉宾的话题
scanf("%[^\n]",str);
我把它应用到我的代码中,但我遇到了同样的问题,我也试过
scanf("%[^\n]s",str);
scanf("%[^\n]",&str); //despite looked senseless to me
我读过有关 fgets 和 fscanf 的内容,但我处于早期阶段
这是代码...我在 Windows 10.
上使用 Visual Studio 2015,运行
#include <stdio.h>
#include <string.h>
typedef struct s_libro {
char titolo[50];
char autore[50];
char editore[20];
int pagine;
int costo$;
}t_libro;
int main() {
t_libro libro1;
t_libro libro2;
printf("Inserire autore(max 50) ,titolo(max 50) , editore(max 20), pagine, costo$\n");
//LIBRO 1
printf("\nLIBRO 1\n");
printf("\nInserisci il nome dell'autore del libro1 : \n");
scanf("%[^\n]", libro1.autore);
printf("\nInserire titolo del libro1 : \n");
scanf("%[^\n]", libro1.titolo);
printf("\nInserire nome dell'editore del libro1:\n");
scanf("%[^\n]", libro1.editore);
printf("\nInserire numero di pagine del libro1 : \n");
scanf("%d", &libro1.pagine);
printf("\nInserire il costo (dato numerico) del libro1 : \n");
scanf("%d", &libro1.costo$);
printf("\nLIBRO1\t");
printf("\nTitolo Libro1\t %s", libro1.titolo);
printf("\nAutore Libro1\t %s", libro1.autore);
printf("\nPagine Libro1\t %d", libro1.pagine);
printf("\nEditore Libro1\t %s", libro1.editore);
printf("\nCosto Libro1\t %d $", libro1.costo$);
printf("\n\n");
//LIBRO 2
printf("\nLIBRO 2\n");
printf("\nInserisci il nome dell'autore del libro2 : ");
scanf("%[^\n]", &libro2.autore);
printf("\nInserire il titolo del libro2 : ");
scanf("%[^\n]", &libro2.titolo);
printf("\nInserire L'editore del libro2:");
scanf("%[^\n]", libro2.editore);
printf("\nInserire il numero di pagine del libro2 : ");
scanf("%d", &libro2.pagine);
printf("\nInserire il costo (dato numerico) del libro2 : ");
scanf("%d", &libro2.costo$);
printf("\nLIBRO2\t");
printf("\nTitolo Libro2\t %s", libro2.titolo);
printf("\nAutore Libro2\t %s", libro2.autore);
printf("\nPagine Libro2\t %d", libro2.pagine);
printf("\nEditore Libro2\t %s", libro2.editore);
printf("\nCosto Libro2\t %d $", libro2.costo$);
printf("\n\n");
}
如果你想保留白色 spaces,我建议使用 fgets
然后删除任何尾随的换行符,例如使用 strcspn
(如 xing 所建议的)。阅读一个项目将如下所示:
printf("\nInserisci il nome dell'autore del libro1 : \n");
fgets(libro1.autore,50,stdin);
libro1.autore[strcspn(libro1.autore,"\n")] = '[=10=]';
优点是如果用户输入 "to many characters",您就不会担心缓冲区溢出;请注意,有效名称最多包含 48 个字符(+ 换行符 + 字符串终止符)。并且 - 在用户的常规输入中 - 对于可能影响任何后续 scanf("....")
语句的换行符,您是安全的。
请注意,scanf
(如 scanf(" %[^\n]", libro1.autore)
格式中以 space 开头的 scanf
不允许用户输入 "empty" 名称,因为 space 中的格式会将(唯一的)换行符消耗为白色 space。没有前导 space 的 scanf
,即 scanf("%[^\n]", libro1.autore)
不会消耗任何新行,从而导致您遇到的问题。
结论:在这种情况下不要使用 scanf
。
你有两个问题:
- 您没有检查
scanf()
是否成功。
- 您不允许
scanf()
leaves the newlines in the input stream.
您有如下代码:
printf("\nInserisci il nome dell'autore del libro1 : \n");
scanf("%[^\n]", libro1.autore);
printf("\nInserire titolo del libro1 : \n");
scanf("%[^\n]", libro1.titolo);
第一个应该可以。第二个会失败,因为第一个在输入流中留下了换行符,而扫描集不认为换行符有效,所以它失败了。
有几种可能的解决方案。哪个最好取决于您的详细要求。
- 使用标准 C
fgets()
or perhaps POSIX getline()
to read lines and then sscanf()
处理数据。
- 在格式字符串中使用
" %49[^\n]"
以跳过白色 space 包括换行符,然后再将最多 49 个非换行符读入变量。这是最小的变化。长度限制可防止缓冲区溢出。是的,格式字符串中的大小不包括空字节。
每次输入scanf()
后读取该行的剩余部分。例如:
static inline void gobble(void)
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
}
然后:
printf("\nInserisci il nome dell'autore del libro1 : \n");
if (scanf("%49[^\n]", libro1.autore) != 1)
…process error or EOF…
gobble();
printf("\nInserire titolo del libro1 : \n");
if (scanf("%49[^\n]", libro1.titolo) != 1)
…process error or EOF…
gobble();
毫无疑问,还有很多其他选择;您将必须决定什么最适合您。请注意,您应该每次使用它时检查scanf()
的状态,并且您应该确保不允许溢出.
顺便说一句,scanf("%[^\n]", &str)
变体是错误的。传递的参数类型是 char (*)[50]
(如果变量是 char str[50];
),但扫描集转换规范需要一个 char *
——一个完全不同的类型。有一个怪癖意味着你可以侥幸逃脱; str
和 &str
的地址值相同,但类型不同,查看 (str + 1)
和 &str + 1
可以注意到——值将完全不同.正确的表示法是 scanf("%[^\n]", str)
,因此(模数添加溢出保护)。
我搜索了整个网络,但还没有找到真正的解决方案(也许我没有用 google 搜索正确的词,我不知道)。 但我们在这里:这是我的第一个带有结构的 C 项目,我尝试使用 gets 和 puts 来克服 printf-scanf 的空格问题,但是 gets 导致了很多问题(程序直接跳到 puts , 没有 gets) 所以我进入了本论坛另一位嘉宾的话题
scanf("%[^\n]",str);
我把它应用到我的代码中,但我遇到了同样的问题,我也试过
scanf("%[^\n]s",str);
scanf("%[^\n]",&str); //despite looked senseless to me
我读过有关 fgets 和 fscanf 的内容,但我处于早期阶段
这是代码...我在 Windows 10.
上使用 Visual Studio 2015,运行#include <stdio.h>
#include <string.h>
typedef struct s_libro {
char titolo[50];
char autore[50];
char editore[20];
int pagine;
int costo$;
}t_libro;
int main() {
t_libro libro1;
t_libro libro2;
printf("Inserire autore(max 50) ,titolo(max 50) , editore(max 20), pagine, costo$\n");
//LIBRO 1
printf("\nLIBRO 1\n");
printf("\nInserisci il nome dell'autore del libro1 : \n");
scanf("%[^\n]", libro1.autore);
printf("\nInserire titolo del libro1 : \n");
scanf("%[^\n]", libro1.titolo);
printf("\nInserire nome dell'editore del libro1:\n");
scanf("%[^\n]", libro1.editore);
printf("\nInserire numero di pagine del libro1 : \n");
scanf("%d", &libro1.pagine);
printf("\nInserire il costo (dato numerico) del libro1 : \n");
scanf("%d", &libro1.costo$);
printf("\nLIBRO1\t");
printf("\nTitolo Libro1\t %s", libro1.titolo);
printf("\nAutore Libro1\t %s", libro1.autore);
printf("\nPagine Libro1\t %d", libro1.pagine);
printf("\nEditore Libro1\t %s", libro1.editore);
printf("\nCosto Libro1\t %d $", libro1.costo$);
printf("\n\n");
//LIBRO 2
printf("\nLIBRO 2\n");
printf("\nInserisci il nome dell'autore del libro2 : ");
scanf("%[^\n]", &libro2.autore);
printf("\nInserire il titolo del libro2 : ");
scanf("%[^\n]", &libro2.titolo);
printf("\nInserire L'editore del libro2:");
scanf("%[^\n]", libro2.editore);
printf("\nInserire il numero di pagine del libro2 : ");
scanf("%d", &libro2.pagine);
printf("\nInserire il costo (dato numerico) del libro2 : ");
scanf("%d", &libro2.costo$);
printf("\nLIBRO2\t");
printf("\nTitolo Libro2\t %s", libro2.titolo);
printf("\nAutore Libro2\t %s", libro2.autore);
printf("\nPagine Libro2\t %d", libro2.pagine);
printf("\nEditore Libro2\t %s", libro2.editore);
printf("\nCosto Libro2\t %d $", libro2.costo$);
printf("\n\n");
}
如果你想保留白色 spaces,我建议使用 fgets
然后删除任何尾随的换行符,例如使用 strcspn
(如 xing 所建议的)。阅读一个项目将如下所示:
printf("\nInserisci il nome dell'autore del libro1 : \n");
fgets(libro1.autore,50,stdin);
libro1.autore[strcspn(libro1.autore,"\n")] = '[=10=]';
优点是如果用户输入 "to many characters",您就不会担心缓冲区溢出;请注意,有效名称最多包含 48 个字符(+ 换行符 + 字符串终止符)。并且 - 在用户的常规输入中 - 对于可能影响任何后续 scanf("....")
语句的换行符,您是安全的。
请注意,scanf
(如 scanf(" %[^\n]", libro1.autore)
格式中以 space 开头的 scanf
不允许用户输入 "empty" 名称,因为 space 中的格式会将(唯一的)换行符消耗为白色 space。没有前导 space 的 scanf
,即 scanf("%[^\n]", libro1.autore)
不会消耗任何新行,从而导致您遇到的问题。
结论:在这种情况下不要使用 scanf
。
你有两个问题:
- 您没有检查
scanf()
是否成功。 - 您不允许
scanf()
leaves the newlines in the input stream.
您有如下代码:
printf("\nInserisci il nome dell'autore del libro1 : \n");
scanf("%[^\n]", libro1.autore);
printf("\nInserire titolo del libro1 : \n");
scanf("%[^\n]", libro1.titolo);
第一个应该可以。第二个会失败,因为第一个在输入流中留下了换行符,而扫描集不认为换行符有效,所以它失败了。
有几种可能的解决方案。哪个最好取决于您的详细要求。
- 使用标准 C
fgets()
or perhaps POSIXgetline()
to read lines and thensscanf()
处理数据。 - 在格式字符串中使用
" %49[^\n]"
以跳过白色 space 包括换行符,然后再将最多 49 个非换行符读入变量。这是最小的变化。长度限制可防止缓冲区溢出。是的,格式字符串中的大小不包括空字节。 每次输入
scanf()
后读取该行的剩余部分。例如:static inline void gobble(void) { int c; while ((c = getchar()) != EOF && c != '\n') ; }
然后:
printf("\nInserisci il nome dell'autore del libro1 : \n"); if (scanf("%49[^\n]", libro1.autore) != 1) …process error or EOF… gobble(); printf("\nInserire titolo del libro1 : \n"); if (scanf("%49[^\n]", libro1.titolo) != 1) …process error or EOF… gobble();
毫无疑问,还有很多其他选择;您将必须决定什么最适合您。请注意,您应该每次使用它时检查scanf()
的状态,并且您应该确保不允许溢出.
顺便说一句,scanf("%[^\n]", &str)
变体是错误的。传递的参数类型是 char (*)[50]
(如果变量是 char str[50];
),但扫描集转换规范需要一个 char *
——一个完全不同的类型。有一个怪癖意味着你可以侥幸逃脱; str
和 &str
的地址值相同,但类型不同,查看 (str + 1)
和 &str + 1
可以注意到——值将完全不同.正确的表示法是 scanf("%[^\n]", str)
,因此(模数添加溢出保护)。