如何从scanf获取换行符,即使它是唯一的输入

我正在做作业,要求我读取一个表示循环大小的整数n ,然后读取一行字符n次并在用户输入后立即打印。 所以我用scanf然后用printf打印它。 问题是如果用户的输入只是一个换行符,它应该打印另一个\n ,但是当它是单个\n时, scanf似乎忽略了输入。

有没有办法用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 } 

使用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); //  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转换会忽略前导空格:

除非规范包含[cn说明符,否则将跳过输入的空白​​字符(由isspace函数指定)。

因此,如果用户输入一个空行, scanf忽略该输入,除非其格式是exception之一。

您可以使用具有字符集格式的scanf

 scanf("%27[^\n]%*c", buff); 

读取所有字符直到换行(但这里限制为28 - 1以避免缓冲区溢出),然后使用换行而不存储换行符( %*c转换说明符中的%*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 。 这样更好。

我有两个解决方案:

  • 使用fgets而不是scanf
  • 在字符串的末尾添加\n ,因为您知道use将以\n结束输入。

第一解决方案

 ... char buf[28]; fgets(buf, 28, stdin); ... 

二解决方案:

 #include  ... char buf[28]; scanf("%s", buf); strcat(buf, "\n"); // add the newline to the string ... 

一种选择是使用gets一次读取一行,然后使用sscanf解析每一行。

基于注释编辑:使用fgets更合适,因为您可以避免缓冲区溢出。

是的,如果您使用正确的格式说明符,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()调用之间清除stdin,如下所示:

 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