我正在做作业,要求我读取表示循环大小的整数n
,然后读取一行字符n
次并在用户输入后立即打印。所以我使用scanf
,然后用printf
打印它。问题是如果用户的输入只是一个换行符,它应该打印另一个\n
,但scanf
似乎忽略了单个\n
时的输入。
有没有办法使用scanf
进行此作业,还是应该尝试其他内容?
int i;
scanf("%d", &i);
for(int ct=0; ct<i; ct++)
{
char buff[28];
scanf("%s", buff); // if I just press enter here
prtinf("%s\n", buff); // then I must get \n\n here
}
答案 0 :(得分:12)
使用fgets
读取一行更简单,更健壮:
if (!fgets(buff, 28, stdin))
{
// reading failed, do appropriate error handling
// we're just exiting here
exit(EXIT_FAILURE);
}
// We have successfully read in a line, or at least the first 27
// characters of the line. Check whether a full line was read,
// if it was, whether the line was empty
size_t l = strlen(buff); // <string.h> must be included
if (buff[l-1] == '\n')
{
// a full line was read, remove trailing newline unless
// the line was empty
if (l > 1)
{
buff[l-1] = 0;
}
}
else
{
// the input was too long, what now?
// leave the remaining input for the next iteration or
// empty the input buffer?
}
printf("%s\n",buff);
它不适用于scanf("%s",buff)
,因为大多数scanf
次转化会忽略前导空格:
除非是跳过输入的空白字符(由
isspace
函数指定) 该规范包括[
,c
或n
说明符。
因此,如果用户输入一个空行,scanf
将忽略该输入,除非其格式是例外情况之一。
您可以使用scanf
代替字符集格式
scanf("%27[^\n]%*c", buff);
读取所有字符直到换行符(但此处限制为28 - 1
以避免缓冲区溢出),然后使用换行符而不存储换行符(*
转换说明符中的%*c
抑制赋值),它将处理完全由空格组成的非空行,%s
转换不会。但是如果输入的第一个字符是换行符,%27[^\n]
转换失败(感谢chux引起注意),换行符将保留在输入缓冲区中,并使用该格式进行后续扫描如果没有从输入缓冲区中删除换行符,也会失败。
根据我的意见,使用scanf
的一个有点强大(但很难看;并且不处理太长的输入)循环将需要在扫描之前检查换行符,例如
for(int ct = 0; ct < i; ++ct)
{
int ch = getchar();
if (ch == EOF)
{
// something bad happened; we quit
exit(EXIT_FAILURE);
}
if (ch == '\n')
{
// we had an empty line
printf("\n\n");
}
else
{
// The first character was not a newline, scanning
// with the character set format would have succeeded.
// But we don't know what comes next, so we put the
// character back first.
// Although one character of pushback is guaranteed,
if (ungetc(ch,stdin) == EOF)
{
// pushback failed
exit(EXIT_FAILURE);
}
scanf("%27[^\n]%*c",buff);
printf("%s\n",buff);
}
}
真的使用fgets
。它更好。
答案 1 :(得分:2)
我有两个解决方案:
fgets
代替scanf
。\n
,因为您知道该用法将使用\n
结束输入。...
char buf[28];
fgets(buf, 28, stdin);
...
#include <string.h>
...
char buf[28];
scanf("%s", buf);
strcat(buf, "\n"); // add the newline to the string
...
答案 2 :(得分:0)
一种选择是使用gets
一次读取一行,然后使用sscanf
解析每一行。
基于评论编辑:使用fgets
更合适,因为您可以避免缓冲区溢出。
答案 3 :(得分:0)
是的,如果您使用正确的格式说明符,scanf()可以做到这一点:
-接受不超过27个字符和
的字符串
-接受该字符串(包括空格)的所有字符,除了换行符'\ n'和
-要查看scanf()是否进行了转换,请输入:
scanRet = scanf("%27[^\n]s", buf); // fills buf[28] with a string.
if(scanRet < 1) printf("Sorry, scanf didn't change buf[] array.\n");
注意!重复的scanf()调用或转换通常会被用户的意外输入和/或stdin中剩余的“垃圾”破坏。您可以像这样在每个scanf()调用之间清除标准输入:
char junk;
do {
junk = getc(stdin);
printf("junk: %c (int %d)\n", junk, (int)junk); // show me the junk we cleared
}
while(junk != '\n' || junk != EOF);
这是我最好的“干净”解决方案,仅使用scanf():
char buf[28] = ""; // sets buf[0] = '\0';
char junk;
int i, iMax, scanRet;
printf("how many lines? (integer>0):\n");
scanRet = scanf(" %d", &iMax);
if(scanRet < 1) {
printf("Sorry, I couldn't read your integer. Bye.\n");
return 1; // error exit.
}
printf("please enter %d lines of text (<=27 chars/line):\n",iMax);
for(i=0; i<iMax; i++) {
// but first, clear any leftover junk in stdin;
do {
junk = getc(stdin);
printf("junk: %c (int %d)\n", junk, (int)junk); // VERBOSE.
}
while (junk != '\n' && junk != EOF);
// THEN try to read user's latest text string:
scanRet = scanf("%27[^\n]",buf); // [^\n]== accept ALL chars except newline
if(scanRet < 1) { // format conversion failed. Nothing new in buf.
printf("(empty line)\n");
}
else {
printf("%s\n", buf); // non-empty user string
}
}
return 0; // normal exit.
}