【问题标题】:Reading and Writing in C用 C 读写
【发布时间】:2016-10-18 14:56:21
【问题描述】:

所以我用以下代码搞乱了读取函数 fgets 和 scanf 以及打印函数 write 和 printf:

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char *argv[])
{
    printf("Enter an integer: ");
    int n = 0; scanf("%d",&n);
    printf("The input number is: %d\n", n);
    printf("Please enter a string now: ");
    char buffer[200];
    read(0,buffer,200);
    printf("The input string is: %s", buffer);
    printf("which is: %s\n", buffer);
    printf("Now please enter another message: ");
    fgets(buffer,200,stdin);
    write(1,buffer,200);

    return 0;
}

我会收到这些错误:

1-在第一次scanf之后,它不会只显示输入字符串的消息。

2-我现在写的就是要保存在字符串中的内容。

3-它会跳过最后的 fgets...

输出示例:

这根本没有任何意义;我想得到这样的输出:

Enter an integer: 15
The input number is: 15
Please enter a string now: This is the message1
The input string is: This is the message1 which is: This is the message1
Now please enter another message: This is the message2
This is the message2

感谢您的帮助!

【问题讨论】:

  • read 不会将空终止符添加到您的 buffer
  • write输出整个buffer,也不是初始化项。
  • 不要发布文字图片。将文本作为文本发布!

标签: c stdio


【解决方案1】:

有趣的问题。在同一个底层文件描述符(0 又名标准输入;stdin 作为文件流)上混合标准 I/O(scanf()fgets())和文件描述符 I/O(read())充其量是有问题的。你会得到奇数球效果。

在文件流级别,当输入来自终端时,stdinstdout 之间存在一些同步; stdout 上的未决输出通常由库刷新。当你使用read() 时,没有这样的同步。这就是为什么直到您按回车后才会出现提示的原因。

当您键入 1 作为数字时,您还提供了一个换行符。标准 I/O 缓冲换行符;它被保存以便下一个文件流操作可以读取它。然后你读了一行read()。它不知道标准 I/O 缓冲区,因此它等待来自终端的新输入行。您需要捕获读取了多少数据,因为输入不是以空值终止的;这是标准 I/O 库提供的服务,而不是低级 read() 函数。

当您随后调用fgets() 时,它会读取缓冲的换行符(在读取整数时未被scanf() 处理)并返回空行。

请注意,如果您在标准输出上等待任何缓冲输出(例如,您使用了没有换行符的 printf("Beginning of line: ");),那么来自 write() 的输出将出现在缓冲在 stdout 上的信息之前。

使用fread()fwrite() 将为您提供直接二进制I/O(例如,无空终止),但将使用与printf()fgets() 等函数相同的I/O 缓冲区。使用这些时你会得到混合行为——通常最好在单个文件流上使用fread()/fwrite() 或文本 I/O 函数,而不是两者,但混合它们是允许的,相对容易理解,并且偶尔有用。

所以,你看到的都是可以解释的,但是解释起来很辛苦。这也清楚地表明了为什么通常不应该在同一个底层文件描述符上混合文件流和文件描述符 I/O——尤其是标准输入。

【讨论】:

  • 不错的答案。也许还提到在stdin 上使用fread?虽然fread 也不会终止缓冲区,但至少它会与从stdin 读取的其他内容同步。
  • @IanAbbott:好主意;我已经添加了一个关于该主题的段落。谢谢。
【解决方案2】:

为什么不使用格式更好的scanf

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char *argv[]) {
    int n, i;
    char buffer[200], ch;

    printf("Enter an integer: ");
    scanf("%d",&n);

    printf("The input number is: %d\n", n);

    printf("Please enter a string now: ");
    scanf(" %[^\t\n]s",buffer);

    printf("The input string is: %s", buffer);
    printf("which is: %s\n", buffer);

    printf("Now please enter another message: ");
    scanf(" %[^\t\n]s",buffer);

    printf("%s", buffer);

    return 0;
}

【讨论】:

    【解决方案3】:
    read(0,buffer,200);
    

    最多可读取 200 个字符,但不会向 buffer 添加终止空字符。因此,对printf 的以下调用会导致未定义的行为。

    您需要添加代码来捕获函数的返回值并确保以空值终止字符串。

    int n = read(0, buffer, 199);  // Leave one for the terminating null character
    if ( n == -1 )
    {
       // Deal with the error.
    }
    else
    {
       // null terminate the string.
       buffer[n] = '\0';
    }
    

    【讨论】:

    • 不是这样; read(0, buffer, 200); 在 Unix 系统上,输入来自终端,将返回输入缓冲区中可用的字节数,上限为 200。如果有多行排队,则将返回多行;如果一行只有换行符,则返回一个字符;如果还没有可用的字符,它将等到字符可用。你是对的,它不会终止字符串。因此,捕获返回值至关重要,以便了解错误 (-1)、EOF (0) 或实际数据长度 (&gt; 0)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多