将输入从标准输入传递到函数时进行缓冲
我昨天询问过这个问题,但我仍然遇到问题。我用 C 编写了一个程序,其中有一个处理文件的函数,这些文件可以通过文件指针传递给它。
void process_my_file(FILE *fptr, ...) {
/* do work */
}
我问如何从标准输入读取输入并将其传递给我的函数,建议我尝试使用 stdin 作为参数调用该函数:
my_process_file(stdin, ...);
这可行,但我真正想做的是 从 stdin 读取直到遇到 EOF,然后将所有输入一次性传递给函数。仅传递 stdin 作为参数的问题是,每次用户输入一行输入并按“enter”键时,程序都会过早地吐出相应的输出行。
我希望输入和输出能够完全分离,这样输出只有在用户说出 EOF(Control-d)后才会出现。
再次提前致谢。我是一个学习编程的新手,你的建议对我很有帮助。我真的很欣赏这个网站。
——拉里
I asked about this yesterday, but I'm still having problems. I wrote a program in C which has a function that processes files which can be passed to it by a file pointer.
void process_my_file(FILE *fptr, ...) {
/* do work */
}
I asked how to read input from standard input and pass it to my function, and it was recommended to me that I try calling the function with stdin as the argument:
my_process_file(stdin, ...);
This works, but what I'm really looking to do is read from stdin until EOF is encountered, and then pass all the input at once to the function. The issue with just passing stdin as the argument is that every time the user enters a line of input and presses "enter" the program spits out a corresponding line of output prematurely.
I was hoping for a clean separation of input and output, such that output only comes out after the user has said EOF (Control-d).
Thanks again in advance. I'm a newbie learning to program, and your tips are a big help. I really appreciate this website.
-- Larry
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
假设您要打开一个文件,然后将文件句柄传递给您的函数。函数中的代码仍然必须读取该常规文件的 EOF。此外,它还必须分配足够的空间来存储文件,并处理短读取。
所有这些都与您必须处理 stdin 的问题相同 - 唯一可能的区别是,来自终端的 stdin 将为您提供每行输入的简短读取,而每次从管道读取都会为您提供简短的读取。读取管道缓冲区的大小(或小于缓冲区大小的原子写入),并且普通磁盘文件通常只会为您提供对文件最后一个块的简短读取。由于您的函数无法提前告知需要多少空间(当然不是管道或终端输入),因此您必须准备好处理动态内存分配 -
malloc()
和realloc()。
另外,如果您的函数期望获取已为其读取的数据,为什么要传递文件句柄(FILE 指针)而不是字符缓冲区及其长度?当您需要函数使用文件句柄时,您可以将文件句柄传递给函数 - 从可读句柄读取数据,或写入可写句柄(并且,偶尔,如果句柄打开以进行读写)。
这是一个工作示例程序。我必须找出一些需要将整个文件放入内存中、处理它并输出一些答案的东西 - 所以我选择按字符对文件进行排序。毫无意义,但它演示了该怎么做。它还具有操作变量参数错误报告功能。
玩得开心!
您可以使用一个或多个文件名作为参数来调用它;每个文件名单独排序。你可以将一些东西输入其中;你可以让它从标准输入读取。
我选择忽略
fwrite()
和fclose()
可能失败的可能性;我还选择忽略process_my_file()
中的buflen
溢出的可能性。如果您选择,您可以检查它们。 (请注意,每个文件的输出比输入多包含一个换行符。)读者练习:
Suppose you were to open a file and then pass the file handle to your function. Your code in the function would still have to read to EOF on that regular file. Further, it would have to deal with allocating enough space to store the file, and deal with short reads.
All this is just the same set of issues that you must deal with for stdin - the only possible difference being that stdin coming from a terminal will give you short reads for each line of input, whereas each read from a pipe will give you a short read for the size of the pipe buffer (or the atomic writes smaller than the buffer size), and a plain disk file will only usually give you a short read on the last block of a file. Since your function cannot tell ahead of time how much space is needed (certainly not for the pipe or terminal inputs), you have to be prepared to deal with dynamic memory allocation -
malloc()
andrealloc()
.Also, if your function is expecting to get the data already read for it, why is it being passed a file handle (FILE pointer) and not a character buffer and its length? You pass a file handle to a function when you need the function to use it - to read from a readable handle, or to write to a writable handle (and, just occasionally, both if the handle is open for reading and writing).
Here's a working example program. I had to work out something that needed to slurp the whole file into memory, process it, and spew out some answer - so I've chosen to sort the file by characters. Moderately pointless, but it demonstrates what to do. It also has an operational variable arguments error reporting function in it.
Have fun!
You can call this with one or more file names as arguments; each file name is sorted separately. You can pipe something into it; you can let it read from standard input.
I choose to ignore the possibility that
fwrite()
andfclose()
might fail; I also choose to ignore the possibility of overflow onbuflen
inprocess_my_file()
. You can check them if you choose. (Note that the output for each file contains one more newline than the input does.)Exercises for the reader:
您必须自己进行预缓冲,即读取 stdin 直到看到 EOF,然后将一个长字符串(可能由 \n 分隔的行组成)传递给您的函数。或者您的预缓冲区读取例程可以分配指向分配行的 char* 数组。或者您的预缓冲例程将解析标准输入并返回预处理信息。取决于您想如何处理该信息。
You'll have to do the pre-buffering yourself, i.e., read stdin until EOF is seen and then pass one long string (probably constisting of \n-separated lines) to your function. Or your pre-buffer read routine could allocate an array of char*'s that point to allocated lines. Or your pre-buffer routine would parse stdin and return preprocessed info. Depends on what you want to do with the information.
您现在拥有的是“过滤器”。过滤器是很棒的程序,但当然并不适用于所有情况。不管怎样,看看你是否可以让你的程序作为过滤器工作。
如果您确实必须在处理之前读取所有输入,则必须将输入保存在某处,并且使用 FILE* 调用处理函数是没有意义的(FILE* 中的所有数据已经已读过);您可以将所有输入读取到字符数组中并将该数组传递给您的函数。
What you have now is a 'filter'. Filters are wonderful programs but, of course, not applicable to all situations. Anyway, see if you can keep your program working as a filter.
If you really must read all the input before processing, you have to save the input somewhere, and, it makes no sense calling the processing function with a
FILE*
(all the data in the FILE* has already been read); you can read all the input into a char array and pass that array to your function.