【问题标题】:Why fgets takes cursor to next line?为什么 fgets 将光标移到下一行?
【发布时间】:2015-02-11 00:52:04
【问题描述】:

我使用fgets() 函数从键盘中取出一个字符串。但是,当我使用printf() 打印字符串时,光标会转到新行。

下面是代码。

#include<stdio.h>
int main()
{
    char name[25];

    printf("Enter your name: ");
    fgets(name, 24, stdin);
    printf("%s",name);

    return 0;
}

下面是输出。

-bash-4.1$ ./a.out
Enter your name: NJACK1 HERO
NJACK1 HERO 
-bash-4.1$

即使我没有在printf() 中添加\n,为什么光标会转到下一行?

但是,我注意到如果我使用scanf() 读取一个字符串,然后使用printf() 打印它(不使用\n),光标不会转到下一行。

fgets() 是否在字符串中附加了\n?如果是这样,它会先附加\0,然后附加\n,还是先附加\n,然后附加\0

【问题讨论】:

  • 使用printf("%s", name) 的要点(并避免使用printf(name) 的常见菜鸟错误,这是一个主要的安全问题)。

标签: c string cursor scanf fgets


【解决方案1】:

printf 输出换行符的原因是您的字符串中有一个换行符。

fgets 不是“添加”换行符 --- 它也只是从输入中读取它。 fgets 的读取在换行符(如果有)之后 停止。

摘自the manpage,强调我的:

fgets() 函数最多从给定流中读取比 size 指定的字符数少 1 的字符,并将它们存储在字符串 str 中。 在找到换行符、文件结尾或错误时停止读取。换行符(如果有)将被保留。如果读取了任何字符并且没​​有错误,则会附加一个 `\0' 字符来结束字符串。

检查是否有换行符的一种简单方法是使用我最喜欢的鲜为人知的函数之一 --- strcspn():

size_t newline_pos = strcspn(name, "\r\n");
if(name[newline_pos])
{
    /* we had a newline, so name is complete; do whatever you want here */
    //...

    /* if this is the only thing you do
       you do *not* need the `if` statement above (just this line) */
    name[newline_pos] = 0;
}
else
{
    /* `name` was truncated (the line was longer than 24 characters) */
}

或者,作为一个单行:

// WARNING: This means you have no way of knowing if the name was truncated!
name[strcspn(name, "\r\n")] = 0;

【讨论】:

  • 如果有人想知道,即使没有换行符,这也有效,因为strcspn() 停在'\0';所以在这种情况下,它基本上是用'\0' 替换'\0'
  • 好的,所以 fgets() 附加了一个 \0 ,但是如果缓冲区中有一个 \n ,它将保留它。所以结果是我的字符串是 NJACK1 HERO\n\0\0\0\0\0\0\0\0\0\0\0\0\0 ?请确认
  • @user266168:我认为会是"NJACK1 HERO\n\0&lt;garbage&gt;";我不认为fgets 填充缓冲区的其余部分(但我不确定;有些功能可以,有些不可以)。但是你不需要关心垃圾,因为整个东西仍然是一个有效的字符串(因为它是'\0'-terminated)。我的strcspn() 技巧会将其更改为"NJACK1 HERO\0\0&lt;garbage&gt;"
  • @user266168:strcspn(name, "\r\n") 基本上会“逐步通过name,直到我们遇到'\r''\n';返回步数”。或者,换句话说,直到第一个'\r''\n' 的长度(“span” --- “spn”)。
【解决方案2】:

因为如果阅读文本中有'\n' 将被fgets() 占用,以下内容摘自1570 草案§7.21.7.2 ¶2强>

fgets 函数最多读取比 n 指定的字符数少一个 从stream指向的流到s指向的数组。没有额外的 在换行符 (保留) 或文件结尾之后读取字符。一种 在读入数组的最后一个字符之后立即写入空字符。

我通过粗体突出显示'\n'fgets() 保留的部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-02
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多