扫描直到新行

5
我希望读取所有输入的文本,直到输入一个新行字符为止。
这是我的代码。
int i=0;
char ch[MAX];
printf("Enter the text\n");
while(true)
{
     scanf("%c",&ch[i]);
     if(ch[i]=='\n')
         break;
     i++;
}

但是当我尝试执行时,它只读取一个单词。
我也尝试过scanf("%s",ch);,但结果相同。

1
@almasshaikh 不,gets()绝不能被推荐。它是危险的。 - unwind
好的,@unwind,谢谢你纠正我。 - SMA
2
"它只读取一个单词" - 不对。您的代码正好做到了您需要的。另一种方法是使用 scanf("%[^\n]",ch);getchar(); - Spikatrix
1
你没有给字符串加上空字符。你还没有检查scanf()返回的字符;你应该始终检查它是否返回了你期望的内容。你还应该检查输入是否超过了ch的长度,以免出现缓冲区溢出(在这种情况下,当然会导致堆栈溢出)。 - Jonathan Leffler
5个回答

9

将注释转换为答案。

您的代码可以工作。您发布的代码会扫描所有内容,直到找到换行符(\n)。但正如Jonathan Leffler所评论的那样,您从未对字符串进行NUL终止。只需使用以下方法即可:

ch[i]='\0';

循环后。此外,用户可能输入的字符数超过了 MAX-1(末尾的一个 \0 额外占用一个字符的空间),这可能会导致缓冲区溢出。你应该添加如下检查:

if(i==MAX-1)
break;

为了防止scanf溢出,请在其之前使用以下代码:

fgets(ch, sizeof(ch), stdin);

请注意,scanf("%s",ch);会一直扫描,直到遇到空格或换行符。


不必循环并逐个字符地扫描,只需使用以下代码:

fgets(ch, sizeof(ch), stdin);

scanf("%[^\n]",ch);
getchar();

上面的代码中,scanf会扫描所有内容直到找到换行符并将它们放入ch中。然后getchar()会从stdin中丢弃\n。您还可以通过限制scanf读入ch中的字符数量来提高安全性。
scanf("%49[^\n]",ch);

上述的scanf将最多扫描49个字符,并在末尾添加\0。您可以在那里替换MAX-1的值。我已经用50作为示例。

2
你没有给字符串加上空字符终止符;你没有检查缓冲区的长度。 - Jonathan Leffler
@JonathanLeffler,是的。你说得对。我已经编辑了答案。 - Spikatrix
我现在有点担心你对格式字符串中宏MAX的评论。如果你有#define MAX 39(举个例子),并且有宏#define STRINGIZE(x) EVALUATE(x)#define EVALUATE(x) #x,并且你定义了char ch[MAX+1];,那么你可以使用scanf("%" STRINGIZE(MAX) "[^\n]", ch),但是MAX必须扩展为一个简单的数字,而不是一个一般表达式。否则,我不知道它怎么能够工作。 - Jonathan Leffler
@JonathanLeffler,预处理器不是在编译阶段之前完成它的工作吗? - Spikatrix
是的,但标准C中的预处理器不会在字符串内展开宏。在早期的C语言标准中,一些预处理器会在宏扩展中查找字符串内的宏参数,但那已经是很久以前的事情了!#运算符被引入来处理这个问题;##运算符被引入来处理标记粘合,而在一些早期的预处理器中则使用#define PASTE(x,y) x/**/y。标准要求在注释的位置放置一个空格,并使用#define PASTE(x, y) x ## y将参数粘合在一起。 - Jonathan Leffler
显示剩余2条评论

7

在依赖于ch[i]具有有效值之前,您没有检查scanf()是否成功,这不是一个好主意。

只需使用fgets()一次读取整行即可。


谢谢。我刚刚谷歌了一下fgets()的相关内容:char *fgets(char *str, int n, FILE *stream)请问,应该如何设置参数*stream以从键盘读取? - Aditya Kiran
1
@AdityaKiran,针对你的情况,你可以使用fgets(ch,MAX,stdin); - Spikatrix

3

正如@Jonathan Leffler所评论的,OP的代码没有对字符串进行空终止或防止缓冲区溢出。

由于代码一次只获取1个字符,因此应使用更简单的函数。

int i=0;
char ch[MAX];
int single;  // Important that this in an int to distinguish EOF from input.

printf("Enter the text\n");

while((single = fgetc(stdin)) != EOF) {
  if (i >= (MAX-1)) {
    ;  // Too many, do not save or maybe indicate error
  } else {
    ch[i++] = single;
  }
  if (single == '\n') {
    break;
  }
}
ch[i] = '\0';  // Add termination

0

希望这对您的代码有帮助:

int main()
{
    int i=0;
    char ch[100];
    printf("Enter the text\n");
    gets(ch);  // input text
    puts(ch);  // output text
    return 0;
}

输入: asdf ghjkl zxcvb 输出: asdf ghjkl zxcvb

4
不!绝对不要,永远不要, 绝对不要, 千万不要 建议使用 gets()。它非常糟糕和有毒。它不再是标准的 C 语言,可以轻松地争辩(很容易地)它从未应该被包括在 C89 中 - 尽管这么说,包括它在 C89 中也有原因。请参见 为什么 gets() 函数很危险?为什么不应该使用? - Jonathan Leffler
@JonathanLeffler 永远不要说永远。如果有人想要优雅的代码来故意造成缓冲区溢出,scanf和gets是很好的选择 :) - Sujay Phadke

0

你的代码运行良好。我检查了一下,它读取的是一行而不是一个单词。


1
代码没有对字符串进行空终止或确保没有缓冲区溢出。 - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接