stdin缓冲模式工作原理、适用场景及代码示例疑问
stdin的三种缓冲模式及适用场景
和stdout类似,stdin的三种缓冲模式核心区别在于何时把输入数据从系统缓冲区传递给用户程序:
无缓冲(unbuffered)
输入的字符会立刻被传递给程序,不会在缓冲区暂存。这种模式多用于需要即时响应的交互式场景,比如终端中输入中断信号(如Ctrl+C)时,系统不需要等缓冲区满或换行,直接处理信号。行缓冲(line buffered)
只有当输入遇到换行符\n时,系统才会把整行数据从缓冲区传递给程序。默认情况下,stdin连接终端时就是行缓冲模式——比如你在终端输入命令,按下回车后程序才会收到你输入的整行内容。块缓冲(block buffered)
当缓冲区被填满(通常是4KB、8KB这类系统预设的块大小)时,才会把缓冲区里的数据批量传递给程序。这种模式适用于非交互式输入源,比如文件、管道,目的是减少I/O操作次数,提升整体效率。
你的代码疑问解析
先看你的代码逻辑:
// test02.c int main(int argc, char *argv[]){ char ptr[20]; scanf("%s",ptr); printf("%s\n",ptr); return 0; }
执行./test02 < log时,scanf("%s")只读取了log文件的第一行,原因分两点:
stdin的缓冲模式:当stdin重定向到文件时,系统默认使用块缓冲——操作系统会先把log文件的一块数据(比如4KB)读到系统缓冲区里,但这不是你看到“只读第一行”的直接原因。
scanf("%s")的行为规则:
%s格式符的作用是:跳过输入开头的空白字符,然后读取连续的非空白字符,直到遇到空白字符(空格、换行符、制表符等)就停止。如果你的log文件第一行没有任何空白字符,那么scanf会读取到第一行末尾的换行符为止,把换行符之前的所有字符存入ptr,然后停止读取。此时缓冲区里可能还存着文件后续的内容,但你的程序执行完printf就直接return 0退出了,所以不会处理剩余数据。
如果想读取文件的每一行,你应该用fgets(ptr, sizeof(ptr), stdin)这类按行读取的函数,而不是scanf("%s")——后者本质是按“单词”读取,而非按行。
内容的提问来源于stack exchange,提问作者hhx

