[英]how to use both scanf and fgets to read a file
我需要閱讀以下文本文件:
2 2
Kauri tree
Waterfall
0 0 W S
0 1 E N
我想使用scanf
來獲取第一行,並使用fgets
來獲取第二行和第三行,然后再將scanf
用作其余的行。
我寫了這樣的代碼:
#include <stdio.h>
#define NUM_OF_CHAR 2
int main()
{
int node, edge;
scanf("%d %d", &node, &edge);
FILE* fp;
fp = stdin;
char* str[NUM_OF_CHAR]; //should be char str[NUM_OF_CHAR];
for (int i = 0; i < node; i++) {
fgets(str[i], 2, fp); //should be fgets(str, 2, fp);
}
printf("%s", str[0]); //printf("%s", str);
}
我輸入的輸入是:
2 2
hello
我遇到了Segmentation fault
我在這里看到了一個類似的問題,一個人提到我可以一次調用fgets
來獲取第一行,但是忽略它,然后再次使用fgets
來獲取第二行。 但是我不知道該怎么做。
除非明確初始化,否則函數內部定義的局部變量將具有不確定的值。 對於指針,這意味着它們正在指向看似隨機的位置。 使用任何未初始化的變量(除非對其進行初始化)都會導致未定義的行為 。
此處發生的情況是fgets
將使用(未初始化且看似隨機的)指針並將其寫入其指向的內存中。 在大多數情況下,此內存不屬於您或您的程序,甚至可能會覆蓋一些其他重要數據。 這可能會導致崩潰或其他怪異的行為或結果。
最簡單的解決方案是使str
成為字符數組,例如
#define NUM_OF_STRINGS 2
#define STRING_LENGTH 64
...
char str[NUM_OF_STRINGS][STRING_LENGTH];
...
fgets(str[i], sizeof str[i], stdin);
您需要確保上面的STRING_LENGTH
足以容納每個字符串, 包括換行符和字符串終止符。 在上面顯示的是64
的情況下,這意味着您最多可以有62個字符的行。
現在,對於另一個問題,我指出了,第一個對fgets
調用讀取了一個空行。
如果您有輸入
2 2
hello
輸入存儲在內存中的緩沖區中,然后scanf
和fgets
從該緩沖區讀取。 通過上面的輸入,緩沖區看起來像這樣
+----+----+----+----+----+----+----+----+----+ | 2 | 2 | \n | h | e | l | l | o | \n | +----+----+----+----+----+----+----+----+----+
在scanf
調用讀取兩個數字之后,輸入緩沖區看起來像
+----+----+----+----+----+----+----+ | \n | h | e | l | l | o | \n | +----+----+----+----+----+----+----+
因此,循環中對fgets
第一個調用將是換行符。 因此它將讀取該換行符,然后完成該操作,將字符串"hello\\n"
留在緩沖區中,以供第二次調用fgets
。
有幾種方法可以解決此問題。 我個人更喜歡使用通用的fgets
讀取行,如果您需要對行進行簡單的解析,請使用sscanf
(注意sscanf
的s
,也請參見此處,以獲得所有scanf
變體的良好參考 )。 。
另一種方法是簡單地從輸入中讀取字符,一次輸入一個字符,然后丟棄它們。 閱讀換行符時,請停止循環並繼續執行該程序的其余部分。
考慮以下示例,其中的注釋解釋了一些要點:
#include <stdio.h>
#define NUM_OF_CHAR 2
#define LEN_OF_STR 20
int main()
{
int node, edge;
FILE* fp;
fp = stdin;
char strbuf[LEN_OF_STR];
// stream is available after that
// reading numbers
fscanf(fp, "%d %d", &node, &edge);
// reading strings
for (int i = 0; i < node; i++) {
// reading line from input stream
fgets(strbuf, LEN_OF_STR, fp);
}
// cleaning input buffer
while (getchar() != '\n');
// reading lines with data
char str[NUM_OF_CHAR];
int a, b;
for (int i = 0; i < node; i++) {
// reading two numbers and two characters
fscanf(fp, "%d %d %c %c", &a, &b, &str[0], &str[1]);
// do something with dada, e.g. output
printf("%d %d %c %c\n", a, b, str[0], str[1]);
}
return 0;
}
使用scanf
或fscanf
讀取數據時,可以檢查結果,例如:
if (4 == fscanf(fp, "%d %d %c %c", &a, &b, &str[0], &str[1]))
{
// actions for correct data
}
else
{
// actions for wrong input
}
此處的格式行有4個說明符-“%d%d%c%c”,因此我們將其檢查為“比較返回值與4”
我已經解決了我的問題。 我不應該使用char*
指針並將其指向數組。 傳遞給fgets
函數的第一個參數應該是char*
所以我應該只使用數組。
另外,由於scanf
已經掃描了第一行,如果我接下來使用fgets
,它將自動獲取下一行。
#include <stdio.h>
#define NUM_OF_CHAR 100
int main()
{
int node, edge;
scanf("%d %d", &node, &edge);
FILE* fp;
fp = stdin;
char str[NUM_OF_CHAR] = {'\0'};
for (int i = 0; i < node; i++) {
fgets(str, NUM_OF_CHAR, fp);
}
printf("%s", str);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.