在 C 中从 Stdin 读取两次
Reading From Stdin Twice in C
int getLineCount() {
int ret = 0;
char c;
while ((c = fgetc(stdin)) != EOF)
if (c == '\n')
ret++;
return ret + 1;
}
void fill(char *WORD) {
int charIndex = 0;
char c;
while ((c = fgetc(stdin)) != EOF) {
*(WORD + charIndex++) = c;
}
}
int main() {
int lineNum = getLineCount();
char *WORD = (char*)calloc(lineNum * 18,sizeof(int));
fill(WORD);
return 0;
}
这是我的部分代码,我的问题是(如您所见):
我试图读取标准输入的内容两次,但是在 getLineCount 函数之后,它停留在 EOF,我无法在 中再次读取它填充 函数。
我在 Linux;
中使用此命令从用户那里获取标准输入
$./output < text_file.txt
有什么方法可以将标准输入回滚到起始字符吗?如果没有,我该如何解决这个问题?
谢谢。
您可以使用 rewind(stdin)
将流设置回文件的开头,但请注意它不能保证有效,尤其是当流是管道、终端或设备时。
您的分配方案不正确:您可以计算文件的大小,然后分配那么多字节,但是您当前的 (char*)calloc(lineNum * 18,sizeof(int));
为每行分配了类型 int
大小的 18 倍。一些带有短行的文件将适合此数组,而其他文件将调用未定义的行为。
请注意,对于 c = fgetc(stdin);
,c
必须定义为 int
才能正确存储所有值,包括 EOF
特殊值。
不要使用 rewind
。
当然,您可以保存从 stdin 读取的数据(如果对于主内存而言太大,则可能保存在文件中)并对其进行操作。
另一种可能是这样的:
struct callback {
void (*call) (char, void *);
void * data;
};
void with_characters_from(FILE * file, struct callback const * callbacks, size_t count) {
int c;
while ((c = fgetc(file)) != EOF) {
char character = c & 0xFF;
for (size_t i = 0; i < count; ++i) {
callbacks[i].call(character, callbacks[i].data);
}
}
}
你反向控制,这样你的函数不再是 "pulling data out of" stdin,而是数据(字符)是 "pushed to" 它们。请注意,这可能会导致回调地狱,并且在 C 中,您牺牲了很大一部分类型安全性(以及代码清晰度......没有第一个 class 函数/闭包......叹息)。
struct counter_data {
char const character;
unsigned count;
};
void counter (char character, void * vptr) {
struct counter_data * data = vptr;
if (character == data->character) {
++(data->count);
}
}
int main() {
struct counter_data data [2] = {
{'a', 0}, {'x', 0}};
struct callback callbacks [2] = {
{&counter, &(data [0])},
{&counter, &(data [1])}};
with_characters_from (stdin, callbacks, 2);
printf("Counted %c %u times \n", data [0].character, data [0].count);
printf("Counted %c %u times \n", data [1].character, data [1].count);
return 0;
}
如前所述,对于您的特定示例,您应该考虑一种完全不同的方法:如果可能,预先计算所需的大小。如果您超过该大小(您应该始终测试该大小),则使用 realloc
以获得更大的内存块。
int getLineCount() {
int ret = 0;
char c;
while ((c = fgetc(stdin)) != EOF)
if (c == '\n')
ret++;
return ret + 1;
}
void fill(char *WORD) {
int charIndex = 0;
char c;
while ((c = fgetc(stdin)) != EOF) {
*(WORD + charIndex++) = c;
}
}
int main() {
int lineNum = getLineCount();
char *WORD = (char*)calloc(lineNum * 18,sizeof(int));
fill(WORD);
return 0;
}
这是我的部分代码,我的问题是(如您所见):
我试图读取标准输入的内容两次,但是在 getLineCount 函数之后,它停留在 EOF,我无法在 中再次读取它填充 函数。
我在 Linux;
中使用此命令从用户那里获取标准输入$./output < text_file.txt
有什么方法可以将标准输入回滚到起始字符吗?如果没有,我该如何解决这个问题?
谢谢。
您可以使用 rewind(stdin)
将流设置回文件的开头,但请注意它不能保证有效,尤其是当流是管道、终端或设备时。
您的分配方案不正确:您可以计算文件的大小,然后分配那么多字节,但是您当前的 (char*)calloc(lineNum * 18,sizeof(int));
为每行分配了类型 int
大小的 18 倍。一些带有短行的文件将适合此数组,而其他文件将调用未定义的行为。
请注意,对于 c = fgetc(stdin);
,c
必须定义为 int
才能正确存储所有值,包括 EOF
特殊值。
不要使用 rewind
。
当然,您可以保存从 stdin 读取的数据(如果对于主内存而言太大,则可能保存在文件中)并对其进行操作。
另一种可能是这样的:
struct callback {
void (*call) (char, void *);
void * data;
};
void with_characters_from(FILE * file, struct callback const * callbacks, size_t count) {
int c;
while ((c = fgetc(file)) != EOF) {
char character = c & 0xFF;
for (size_t i = 0; i < count; ++i) {
callbacks[i].call(character, callbacks[i].data);
}
}
}
你反向控制,这样你的函数不再是 "pulling data out of" stdin,而是数据(字符)是 "pushed to" 它们。请注意,这可能会导致回调地狱,并且在 C 中,您牺牲了很大一部分类型安全性(以及代码清晰度......没有第一个 class 函数/闭包......叹息)。
struct counter_data {
char const character;
unsigned count;
};
void counter (char character, void * vptr) {
struct counter_data * data = vptr;
if (character == data->character) {
++(data->count);
}
}
int main() {
struct counter_data data [2] = {
{'a', 0}, {'x', 0}};
struct callback callbacks [2] = {
{&counter, &(data [0])},
{&counter, &(data [1])}};
with_characters_from (stdin, callbacks, 2);
printf("Counted %c %u times \n", data [0].character, data [0].count);
printf("Counted %c %u times \n", data [1].character, data [1].count);
return 0;
}
如前所述,对于您的特定示例,您应该考虑一种完全不同的方法:如果可能,预先计算所需的大小。如果您超过该大小(您应该始终测试该大小),则使用 realloc
以获得更大的内存块。