c語言中比較特殊的輸入函數(shù)舉例詳解
一.getchar()函數(shù)
getchar()
是C語言中的一個(gè)標(biāo)準(zhǔn)庫函數(shù),用于從標(biāo)準(zhǔn)輸入(通常是鍵盤)讀取一個(gè)字符。它是stdio.h
庫的一部分,常用于簡單的字符輸入操作。
1.基本功能
getchar()
讀取標(biāo)準(zhǔn)輸入中的下一個(gè)字符,并將其作為一個(gè)int
類型的值返回。盡管返回值是int
類型,但它實(shí)際上是一個(gè)字符的ASCII值。
2.使用方法
int ch = getchar();
在這段代碼中,
getchar()
從標(biāo)準(zhǔn)輸入中讀取一個(gè)字符,并將其返回的字符值存儲(chǔ)在ch
變量中。
示例:
(1).讀取單個(gè)字符
#include <stdio.h> int main() { int ch; printf("請輸入一個(gè)字符: "); ch = getchar(); printf("你輸入的字符是: %c\n", ch); return 0; }
解釋:
- 程序等待用戶輸入一個(gè)字符。用戶輸入的字符被
getchar()
讀取并存儲(chǔ)在ch
中。 printf
函數(shù)隨后輸出用戶輸入的字符。
(2).讀取多個(gè)字符(直到遇到換行符)
#include <stdio.h> int main() { int ch; printf("請輸入一行文字,按回車結(jié)束: "); while ((ch = getchar()) != '\n' && ch != EOF) { printf("讀取字符: %c\n", ch); } printf("輸入結(jié)束。\n"); return 0; }
解釋:
- 程序使用
while
循環(huán)來讀取字符,直到遇到換行符('\n'
)或文件結(jié)束符(EOF
)。 - 每次讀取的字符都會(huì)被輸出。
(3).處理輸入中的空白字符
#include <stdio.h> int main() { int ch; printf("請輸入字符,輸入結(jié)束請按 Ctrl+D (Linux) 或 Ctrl+Z (Windows):\n"); while ((ch = getchar()) != EOF) { if (ch == ' ' || ch == '\n' || ch == '\t') { printf("[空白字符]\n"); } else { printf("讀取字符: %c\n", ch); } } printf("輸入結(jié)束。\n"); return 0; }
解釋:
- 這個(gè)程序讀取用戶輸入的每個(gè)字符,并檢查它是否是空白字符(空格、換行符、制表符)。
- 如果是空白字符,程序會(huì)輸出
[空白字符]
,否則輸出字符本身。 - 當(dāng)用戶按下
Ctrl+D
或Ctrl+Z
時(shí),輸入結(jié)束。
3.返回值
讀取的字符: 如果讀取成功,
getchar()
返回讀取的字符的ASCII值。例如,如果用戶輸入字符'A'
,getchar()
將返回值65
(即'A'
的ASCII碼)。EOF (End of File): 如果在讀取時(shí)遇到文件結(jié)束符(通常是在控制臺輸入時(shí)按下
Ctrl+D
或Ctrl+Z
),getchar()
將返回常量EOF
,其值通常為-1
。EOF
用于指示輸入的結(jié)束或錯(cuò)誤情況。
4.應(yīng)用場景
簡單字符輸入:
getchar()
通常用于簡單的字符輸入操作,例如讀取單個(gè)字符或控制臺中的用戶輸入。處理空白字符: 當(dāng)你需要明確處理空白字符(例如空格、制表符或換行符)時(shí),
getchar()
特別有用。相比于scanf
,getchar()
不會(huì)跳過空白字符,因此你可以逐字符地處理輸入。控制輸入流:
getchar()
在處理輸入流時(shí)非常靈活,可以用于跳過不需要的字符。例如,在多行輸入或復(fù)雜輸入格式的情況下,它可以幫助你控制和過濾輸入內(nèi)容。
5.注意事項(xiàng)
返回類型為
int
: 盡管getchar()
用于讀取單個(gè)字符,但它的返回類型是int
而不是char
。這樣設(shè)計(jì)是為了能夠返回EOF
來表示文件結(jié)束或錯(cuò)誤。為了避免潛在的錯(cuò)誤,通常應(yīng)該使用int
類型來存儲(chǔ)getchar()
的返回值。緩沖區(qū)問題: 在控制臺輸入時(shí),用戶輸入的內(nèi)容通常會(huì)先進(jìn)入緩沖區(qū)。當(dāng)按下回車鍵時(shí),緩沖區(qū)中的內(nèi)容才會(huì)被
getchar()
逐個(gè)讀取。因此,getchar()
不會(huì)在每個(gè)字符輸入時(shí)立即返回,而是等待用戶按下回車鍵。錯(cuò)誤處理: 當(dāng)使用
getchar()
時(shí),程序應(yīng)該考慮EOF
的可能性,尤其是在文件輸入或批處理輸入的情況下。忽略這一點(diǎn)可能會(huì)導(dǎo)致程序未正確處理輸入結(jié)束的情況。
二.fgets()函數(shù)
fgets
是C語言中用于從文件流中讀取一行字符串的標(biāo)準(zhǔn)庫函數(shù)。它提供了一種安全、方便的方法來讀取輸入,避免了諸如緩沖區(qū)溢出等常見問題。fgets
通常用于讀取用戶輸入、從文件中讀取數(shù)據(jù)等場景。
1.函數(shù)原型
char *fgets(char *str, int n, FILE *stream);
str
: 指向字符數(shù)組的指針,fgets
會(huì)將讀取到的字符串存儲(chǔ)在該數(shù)組中。n
: 要讀取的最大字符數(shù),包括結(jié)尾的空字符\0
。也就是說,fgets
最多讀取n-1
個(gè)字符。stream
: 輸入流指針,指明從哪個(gè)流中讀取數(shù)據(jù)。常見的流有標(biāo)準(zhǔn)輸入流stdin
,文件流等。
返回值
- 成功: 返回指向讀取字符串的指針,即參數(shù)
str
。 - 失敗或到達(dá)文件末尾: 返回
NULL
。
2.工作原理
fgets
函數(shù)從指定的輸入流stream
中讀取字符,并將其存儲(chǔ)到str
指向的字符數(shù)組中,直到發(fā)生以下任一情況:讀取了
(n - 1)
個(gè)字符: 為了保證字符串以\0
結(jié)尾,fgets
最多讀取n - 1
個(gè)字符。遇到換行符
\n
:fgets
會(huì)讀取換行符,并將其存儲(chǔ)在str
中。到達(dá)文件末尾
EOF
: 如果在讀取過程中遇到文件末尾,讀取操作結(jié)束。讀取完成后,
fgets
會(huì)在讀取的字符串末尾自動(dòng)添加一個(gè)空字符\0
,以表示字符串的結(jié)束。
3.使用示例
(1).從標(biāo)準(zhǔn)輸入讀取一行字符串
#include <stdio.h> int main() { char buffer[100]; printf("請輸入一行文本:"); if (fgets(buffer, sizeof(buffer), stdin) != NULL) { printf("您輸入的是:%s", buffer); } else { printf("讀取輸入時(shí)發(fā)生錯(cuò)誤。\n"); } return 0; }
解釋:
fgets(buffer, sizeof(buffer), stdin)
從標(biāo)準(zhǔn)輸入讀取最多99
個(gè)字符(保留1個(gè)字符給\0
),并存儲(chǔ)在buffer
中。- 如果讀取成功,程序會(huì)輸出用戶輸入的內(nèi)容。
注意: 由于 fgets
會(huì)將換行符 \n
一并讀取并存儲(chǔ),如果不想要這個(gè)換行符,需要手動(dòng)去除。
(2).從文件中讀取內(nèi)容
#include <stdio.h> int main() { FILE *fp = fopen("example.txt", "r"); if (fp == NULL) { perror("無法打開文件"); return 1; } char line[256]; while (fgets(line, sizeof(line), fp) != NULL) { printf("%s", line); } fclose(fp); return 0; }
解釋:
- 打開名為
example.txt
的文件,讀取其中的內(nèi)容并逐行打印到標(biāo)準(zhǔn)輸出。 fgets
在每次循環(huán)中讀取一行內(nèi)容,直到文件結(jié)束。
4.處理換行符
正如前面提到的,fgets
會(huì)將輸入中的換行符 \n
一并讀取并存儲(chǔ)在目標(biāo)字符串中。如果在處理時(shí)不需要這個(gè)換行符,可以使用以下方法去除:
方法1:手動(dòng)檢查并替換
size_t len = strlen(buffer); if (len > 0 && buffer[len - 1] == '\n') { buffer[len - 1] = '\0'; }
解釋:
- 首先獲取字符串的長度
len
。 - 如果最后一個(gè)字符是
\n
,將其替換為\0
。
方法2:使用 strcspn
函數(shù)
buffer[strcspn(buffer, "\n")] = '\0';
解釋:
strcspn
函數(shù)返回buffer
中第一個(gè)匹配\n
的位置索引,然后將該位置的字符替換為\0
。
5.與其他輸入函數(shù)的比較
(1). fgets vs gets
gets
: 從標(biāo)準(zhǔn)輸入讀取一行,直到遇到換行符或文件結(jié)束符。不安全,因?yàn)闊o法指定讀取的最大長度,容易導(dǎo)致緩沖區(qū)溢出。fgets
: 可以指定最大讀取長度,安全性更高。建議始終使用fgets
代替gets
。
(2). fgets vs scanf
scanf
: 按照指定的格式從輸入中讀取數(shù)據(jù),默認(rèn)會(huì)忽略空白字符,讀取字符串時(shí)會(huì)在遇到空白字符時(shí)停止。fgets
: 讀取整行輸入,包括空白字符和換行符,更適合讀取包含空格的字符串
示例:
char str1[100], str2[100]; // 使用 scanf scanf("%s", str1); // 輸入:Hello World // str1 的值為:"Hello" // 使用 fgets fgets(str2, sizeof(str2), stdin); // 輸入:Hello World // str2 的值為:"Hello World\n"
(3). fgets vs fgetc
fgetc
: 每次從指定流中讀取一個(gè)字符,適合逐字符處理輸入。fgets
: 一次讀取一行或指定長度的字符串,效率更高。
6、常見錯(cuò)誤和注意事項(xiàng)
(1). 忘記檢查返回值
在使用
fgets
時(shí),應(yīng)該始終檢查其返回值,以確保讀取成功。
錯(cuò)誤示例:
fgets(buffer, sizeof(buffer), stdin); // 未檢查返回值,可能導(dǎo)致程序處理空指針
正確示例:
if (fgets(buffer, sizeof(buffer), stdin) != NULL) { // 處理讀取的數(shù)據(jù) } else { // 錯(cuò)誤處理 }
(2). 未正確處理換行符
如前所述,
fgets
會(huì)保留輸入中的換行符,如果不想要這個(gè)換行符,需要手動(dòng)去除。
(3). 緩沖區(qū)大小不足
確保提供給
fgets
的緩沖區(qū)足夠大,以容納預(yù)期的輸入數(shù)據(jù)和結(jié)尾的空字符。
錯(cuò)誤示例:
char buffer[10]; fgets(buffer, 100, stdin); // 錯(cuò)誤:緩沖區(qū)只有10個(gè)字節(jié),卻試圖讀取100個(gè)字符
正確示例:
char buffer[100]; fgets(buffer, sizeof(buffer), stdin); // 正確:緩沖區(qū)大小與讀取長度匹配
(4). 多次讀取時(shí)的緩沖區(qū)殘留
在某些情況下,輸入流中可能殘留未讀取的字符,需要在下一次讀取前清空緩沖區(qū)。
char buffer1[50], buffer2[50]; printf("輸入第一行:"); fgets(buffer1, sizeof(buffer1), stdin); printf("輸入第二行:"); fgets(buffer2, sizeof(buffer2), stdin);
如果在第一次輸入時(shí)輸入的字符超過了 buffer1
的大小,剩余的字符會(huì)留在輸入緩沖區(qū)中,影響第二次讀取。為避免這種情況,可以在每次讀取后清空緩沖區(qū)。
清空緩沖區(qū)的方法:
int c; while ((c = getchar()) != '\n' && c != EOF);
7.綜合示例
示例:讀取用戶輸入并處理
#include <stdio.h> #include <string.h> int main() { char name[50]; int age; char input[100]; // 讀取姓名 printf("請輸入您的姓名:"); if (fgets(name, sizeof(name), stdin) != NULL) { // 去除換行符 name[strcspn(name, "\n")] = '\0'; } else { printf("讀取姓名失敗。\n"); return 1; } // 讀取年齡 printf("請輸入您的年齡:"); if (fgets(input, sizeof(input), stdin) != NULL) { // 將字符串轉(zhuǎn)換為整數(shù) age = atoi(input); } else { printf("讀取年齡失敗。\n"); return 1; } printf("姓名:%s,年齡:%d\n", name, age); return 0; }
解釋:
- 首先使用
fgets
讀取用戶的姓名,并去除結(jié)尾的換行符。 - 然后再次使用
fgets
讀取用戶的年齡輸入,并使用atoi
將其轉(zhuǎn)換為整數(shù)。 - 最后輸出用戶輸入的信息。
三.sscanf函數(shù)
sscanf
是C語言中用于從字符串中讀取并解析數(shù)據(jù)的標(biāo)準(zhǔn)庫函數(shù)。它的作用類似于scanf
,但sscanf
從字符串中讀取數(shù)據(jù),而scanf
是從標(biāo)準(zhǔn)輸入中讀取數(shù)據(jù)。sscanf
非常適合從已知格式的字符串中提取數(shù)值、字符等數(shù)據(jù)。
1.函數(shù)原型
int sscanf(const char *str, const char *format, ...);
str
: 要解析的源字符串。sscanf
會(huì)從這個(gè)字符串中讀取數(shù)據(jù)。format
: 格式字符串,指定了要解析的數(shù)據(jù)格式。它的語法和scanf
的格式字符串相同,包括各種格式說明符(如%d
,%s
,%f
等)。...
: 可變參數(shù)列表,提供用于存儲(chǔ)從字符串中讀取的數(shù)據(jù)的指針。
返回值
- 成功: 返回成功讀取并匹配的項(xiàng)數(shù)。
- 失敗: 返回
EOF
,如果在解析過程中遇到錯(cuò)誤或在嘗試讀取時(shí)到達(dá)字符串末尾
2.工作原理
sscanf
函數(shù)根據(jù)format
字符串中的格式說明符,從源字符串str
中逐一讀取和解析數(shù)據(jù)。每個(gè)格式說明符都對應(yīng)于一個(gè)傳入的變量地址,sscanf
將解析后的數(shù)據(jù)存儲(chǔ)在這些變量中。格式說明符示例
%d
: 讀取一個(gè)整數(shù)。%f
: 讀取一個(gè)浮點(diǎn)數(shù)。%s
: 讀取一個(gè)字符串,遇到空白字符(如空格、換行)時(shí)停止。%c
: 讀取單個(gè)字符。
示例:
(1).從字符串中解析數(shù)據(jù)
#include <stdio.h> int main() { const char *str = "100 3.14 hello"; int num; float pi; char word[20]; int count = sscanf(str, "%d %f %s", &num, &pi, word); printf("讀取到 %d 項(xiàng)數(shù)據(jù):\n", count); printf("整數(shù): %d\n", num); printf("浮點(diǎn)數(shù): %.2f\n", pi); printf("字符串: %s\n", word); return 0; }
輸出:
讀取到 3 項(xiàng)數(shù)據(jù):
整數(shù): 100
浮點(diǎn)數(shù): 3.14
字符串: hello
解釋:
sscanf
解析字符串"100 3.14 hello"
,并將數(shù)據(jù)分別存儲(chǔ)在num
,pi
,word
中。- 返回值
count
表示成功讀取了3項(xiàng)數(shù)據(jù)。
3.常見用法和注意事項(xiàng)
(1). 解析特定格式的字符串
sscanf
特別適用于解析具有固定格式的字符串,比如日期、時(shí)間、IP地址等。
示例:解析日期
#include <stdio.h> int main() { const char *date = "2024-08-17"; int year, month, day; sscanf(date, "%d-%d-%d", &year, &month, &day); printf("年: %d, 月: %d, 日: %d\n", year, month, day); return 0; }
輸出:
年: 2024, 月: 8, 日: 17
解釋:
- 解析字符串
"2024-08-17"
中的年份、月份和日期,并分別存儲(chǔ)在year
,month
,day
中。
(2). 處理多余的輸入
如果源字符串中的內(nèi)容多于格式說明符指定的內(nèi)容,
sscanf
只會(huì)處理指定的部分,忽略其余部分。
示例:部分解析字符串
#include <stdio.h> int main() { const char *str = "42 3.14 some extra text"; int num; float pi; int count = sscanf(str, "%d %f", &num, &pi); printf("讀取到 %d 項(xiàng)數(shù)據(jù):\n", count); printf("整數(shù): %d\n", num); printf("浮點(diǎn)數(shù): %.2f\n", pi); return 0; }
輸出:
讀取到 2 項(xiàng)數(shù)據(jù):
整數(shù): 42
浮點(diǎn)數(shù): 3.14
解釋:
sscanf
只解析了前兩個(gè)數(shù)據(jù)項(xiàng)(整數(shù)和浮點(diǎn)數(shù)),忽略了字符串末尾的額外內(nèi)容。
(3). 不匹配的格式
如果字符串中的內(nèi)容與格式說明符不匹配,
sscanf
會(huì)停止解析,并返回已成功讀取的項(xiàng)數(shù)。
示例:格式不匹配
#include <stdio.h> int main() { const char *str = "hello 3.14"; int num; float pi; int count = sscanf(str, "%d %f", &num, &pi); printf("讀取到 %d 項(xiàng)數(shù)據(jù):\n", count); return 0; }
輸出:
讀取到 0 項(xiàng)數(shù)據(jù):
(4). 忽略特定數(shù)據(jù)
sscanf
還可以使用*
來忽略某些輸入數(shù)據(jù),不存儲(chǔ)在任何變量中。
示例:忽略數(shù)據(jù)
#include <stdio.h> int main() { const char *str = "42 skip this 3.14"; int num; float pi; sscanf(str, "%d %*s %f", &num, &pi); printf("整數(shù): %d\n", num); printf("浮點(diǎn)數(shù): %.2f\n", pi); return 0; }
輸出:
整數(shù): 42
浮點(diǎn)數(shù): 3.14
解釋:
sscanf
使用%*s
忽略了"skip this"
字符串部分,只提取了整數(shù)和浮點(diǎn)數(shù)。
(5). 返回值處理
sscanf
的返回值用于檢查是否成功解析了預(yù)期的項(xiàng)數(shù)。在實(shí)際編程中,應(yīng)該根據(jù)返回值來驗(yàn)證解析操作的成功與否。
示例:檢查返回值
#include <stdio.h> int main() { const char *str = "100 3.14"; int num; float pi; int result = sscanf(str, "%d %f", &num, &pi); if (result == 2) { printf("成功讀取兩個(gè)數(shù)值:%d 和 %.2f\n", num, pi); } else { printf("解析失敗,已成功讀取 %d 項(xiàng)數(shù)據(jù)。\n", result); } return 0; }
輸出:
成功讀取兩個(gè)數(shù)值:100 和 3.14
解釋:
- 如果
sscanf
成功解析了兩個(gè)值,程序輸出成功消息。否則,輸出失敗消息。
4.常見錯(cuò)誤和陷阱
(1). 未匹配到預(yù)期的數(shù)據(jù)
如果輸入字符串的格式與格式說明符不匹配,
sscanf
會(huì)停止解析,返回已經(jīng)成功解析的項(xiàng)數(shù)。確保格式字符串與輸入字符串的格式一致非常重要。
(2). 忘記檢查返回值
忽略
sscanf
的返回值可能導(dǎo)致錯(cuò)誤的程序行為。檢查返回值是驗(yàn)證解析操作成功與否的關(guān)鍵步驟。
(3). 緩沖區(qū)溢出
當(dāng)讀取字符串?dāng)?shù)據(jù)(如使用
%s
)時(shí),確保目標(biāo)緩沖區(qū)有足夠的空間以避免溢出。使用長度限制格式符號(如%99s
)可以防止緩沖區(qū)溢出。
(4). 處理多余輸入
如果
sscanf
只讀取了部分輸入數(shù)據(jù),而程序的邏輯依賴于完整的數(shù)據(jù)解析,可能會(huì)導(dǎo)致問題。合理設(shè)計(jì)格式說明符和字符串輸入非常重要。
5.sscanf 與其他輸入函數(shù)的比較
(1). sscanf vs scanf
scanf
: 從標(biāo)準(zhǔn)輸入中讀取數(shù)據(jù),適用于直接的用戶輸入操作。sscanf
: 從字符串中讀取數(shù)據(jù),適用于解析已經(jīng)存在的字符串內(nèi)容。
(2). sscanf vs fscanf
fscanf
: 從文件流中讀取數(shù)據(jù),適用于從文件中解析數(shù)據(jù)。sscanf
: 從字符串中讀取數(shù)據(jù),適用于解析內(nèi)存中的字符串。
(3). sscanf vs strtok
strtok
: 用于分割字符串,可以按指定的分隔符逐一提取子字符串。sscanf
: 直接解析字符串中的數(shù)據(jù),并將其轉(zhuǎn)換為相應(yīng)的數(shù)據(jù)類型。
6.綜合示例
示例:解析復(fù)雜字符串
#include <stdio.h> int main() { const char *str = "Name: John Doe, Age: 30, Score: 85.5"; char name[50]; int age; float score; int count = sscanf(str, "Name: %[^,], Age: %d, Score: %f", name, &age, &score); if (count == 3) { printf("姓名: %s\n", name); printf("年齡: %d\n", age); printf("分?jǐn)?shù): %.1f\n", score); } else { printf("解析字符串失敗。\n"); } return 0; }
輸出:
姓名: John Doe
年齡: 30
分?jǐn)?shù): 85.5
解釋:
- 使用
sscanf
從格式化字符串中提取姓名、年齡和分?jǐn)?shù)。%[^,]
格式說明符用于讀取直到遇到逗號,
的所有字符,這樣可以處理包含空格的姓名。
四.fscanf()函數(shù)
fscanf
是C語言中用于從文件中讀取并解析數(shù)據(jù)的標(biāo)準(zhǔn)庫函數(shù)。它的作用類似于scanf
,但fscanf
從文件流中讀取數(shù)據(jù),而scanf
是從標(biāo)準(zhǔn)輸入中讀取數(shù)據(jù)。fscanf
適合從文件中逐行或逐項(xiàng)讀取并解析數(shù)據(jù)。
1.函數(shù)原型
int fscanf(FILE *stream, const char *format, ...);
參數(shù)說明
stream
: 文件指針,指向要讀取的文件流(通常是通過fopen
打開的文件)。format
: 格式字符串,指定了要解析的數(shù)據(jù)格式。它的語法和scanf
的格式字符串相同,包括各種格式說明符(如%d
,%s
,%f
等)。...
: 可變參數(shù)列表,提供用于存儲(chǔ)從文件中讀取的數(shù)據(jù)的指針。
返回值
- 成功: 返回成功讀取并匹配的項(xiàng)數(shù)。
- 失敗: 如果遇到文件結(jié)束符
EOF
,則返回EOF
。如果遇到錯(cuò)誤,返回負(fù)數(shù)。
2.工作原理
fscanf
函數(shù)根據(jù) format
字符串中的格式說明符,從文件流 stream
中逐一讀取和解析數(shù)據(jù)。每個(gè)格式說明符都對應(yīng)于一個(gè)傳入的變量地址,fscanf
將解析后的數(shù)據(jù)存儲(chǔ)在這些變量中。
格式說明符示例
%d
: 讀取一個(gè)整數(shù)。%f
: 讀取一個(gè)浮點(diǎn)數(shù)。%s
: 讀取一個(gè)字符串,遇到空白字符(如空格、換行)時(shí)停止。%c
: 讀取單個(gè)字符。
示例:從文件中解析數(shù)據(jù)
假設(shè)有一個(gè)文本文件 data.txt
,內(nèi)容如下:
42 3.14 hello
#include <stdio.h> int main() { FILE *file = fopen("data.txt", "r"); // 打開文件進(jìn)行讀取 if (file == NULL) { perror("無法打開文件"); return 1; } int num; float pi; char word[20]; int count = fscanf(file, "%d %f %s", &num, &pi, word); printf("讀取到 %d 項(xiàng)數(shù)據(jù):\n", count); printf("整數(shù): %d\n", num); printf("浮點(diǎn)數(shù): %.2f\n", pi); printf("字符串: %s\n", word); fclose(file); // 關(guān)閉文件 return 0; }
輸出:
讀取到 3 項(xiàng)數(shù)據(jù):
整數(shù): 42
浮點(diǎn)數(shù): 3.14
字符串: hello
解釋:
fscanf
從文件data.txt
中解析數(shù)據(jù),并將數(shù)據(jù)分別存儲(chǔ)在num
,pi
,word
中。- 返回值
count
表示成功讀取了3項(xiàng)數(shù)據(jù)。
3.常用用法和注意事項(xiàng)
(1). 讀取一行數(shù)據(jù)
fscanf
通常按格式說明符讀取數(shù)據(jù),直到匹配結(jié)束,或者遇到文件結(jié)束符EOF
。它不會(huì)自動(dòng)處理行結(jié)束符,因此如果要按行讀取數(shù)據(jù),可以結(jié)合fgets
和sscanf
使用。
示例:逐行讀取數(shù)據(jù)
假設(shè)文件 data.txt
內(nèi)容如下:
42 3.14 hello 43 2.71 world
#include <stdio.h> int main() { FILE *file = fopen("data.txt", "r"); if (file == NULL) { perror("無法打開文件"); return 1; } int num; float pi; char word[20]; while (fscanf(file, "%d %f %s", &num, &pi, word) != EOF) { printf("整數(shù): %d, 浮點(diǎn)數(shù): %.2f, 字符串: %s\n", num, pi, word); } fclose(file); return 0; }
輸出:
整數(shù): 42, 浮點(diǎn)數(shù): 3.14, 字符串: hello
整數(shù): 43, 浮點(diǎn)數(shù): 2.71, 字符串: world
(2). 文件指針位置
fscanf
讀取數(shù)據(jù)后,文件指針會(huì)移動(dòng)到讀取結(jié)束的位置。下一次調(diào)用fscanf
會(huì)從當(dāng)前文件指針位置繼續(xù)讀取。
(3). 遇到EOF
當(dāng)
fscanf
遇到文件結(jié)束符EOF
時(shí),它會(huì)返回EOF
,通常是-1
。這可以用來判斷是否已經(jīng)讀取到文件末尾。
(4). 忽略特定數(shù)據(jù)
類似于
sscanf
,fscanf
也可以使用*
來忽略某些輸入數(shù)據(jù),而不存儲(chǔ)在任何變量中。
示例:忽略數(shù)據(jù)
#include <stdio.h> int main() { FILE *file = fopen("data.txt", "r"); if (file == NULL) { perror("無法打開文件"); return 1; } int num; float pi; while (fscanf(file, "%d %*s %f", &num, &pi) != EOF) { printf("整數(shù): %d, 浮點(diǎn)數(shù): %.2f\n", num, pi); } fclose(file); return 0; }
解釋:
fscanf
使用%*s
忽略了字符串部分,只提取了整數(shù)和浮點(diǎn)數(shù)。
(5). 返回值處理
與
sscanf
類似,fscanf
的返回值表示成功讀取并解析的數(shù)據(jù)項(xiàng)數(shù)。在實(shí)際編程中,應(yīng)該根據(jù)返回值來驗(yàn)證解析操作的成功與否。
示例:檢查返回值
#include <stdio.h> int main() { FILE *file = fopen("data.txt", "r"); if (file == NULL) { perror("無法打開文件"); return 1; } int num; float pi; while (fscanf(file, "%d %f", &num, &pi) == 2) { // 期望成功讀取2項(xiàng)數(shù)據(jù) printf("整數(shù): %d, 浮點(diǎn)數(shù): %.2f\n", num, pi); } fclose(file); return 0; }
解釋:
- 只有在成功解析了兩個(gè)值時(shí)才輸出結(jié)果。如果
fscanf
未能成功讀取兩個(gè)值,將停止讀取。
(6). 處理多余輸入
如果文件中的內(nèi)容多于格式說明符指定的內(nèi)容,
fscanf
只會(huì)處理指定的部分,忽略其余部分。
4.常見錯(cuò)誤和陷阱
(1). 格式不匹配
如果文件中的內(nèi)容與格式說明符不匹配,
fscanf
會(huì)停止解析,并返回已成功讀取的項(xiàng)數(shù)。確保格式字符串與文件內(nèi)容格式一致非常重要。
(2). 忘記檢查返回值
忽略
fscanf
的返回值可能導(dǎo)致錯(cuò)誤的程序行為。檢查返回值是驗(yàn)證解析操作成功與否的關(guān)鍵步驟。
(3). 文件結(jié)束符
fscanf
在讀取到文件結(jié)束符EOF
時(shí)會(huì)返回EOF
,這與常規(guī)的返回值檢查不同,處理文件結(jié)束符時(shí)需要特別注意。
5.fscanf 與其他輸入函數(shù)的比較
(1). fscanf vs scanf
scanf
: 從標(biāo)準(zhǔn)輸入中讀取數(shù)據(jù),適用于直接的用戶輸入操作。fscanf
: 從文件流中讀取數(shù)據(jù),適用于從文件中解析數(shù)據(jù)。
(2). fscanf vs sscanf
sscanf
: 從字符串中讀取數(shù)據(jù),適用于解析內(nèi)存中的字符串。fscanf
: 從文件流中讀取數(shù)據(jù),適用于從文件中解析數(shù)據(jù)。
(3). fscanf vs fgets
fgets
: 從文件中讀取一整行字符串,適用于逐行讀取文件內(nèi)容,通常結(jié)合sscanf
使用以進(jìn)一步解析數(shù)據(jù)。fscanf
: 按照格式說明符從文件中讀取數(shù)據(jù),適用于逐項(xiàng)解析數(shù)據(jù)。
6.綜合示例
示例:從文件中讀取并解析數(shù)據(jù)
假設(shè)有一個(gè)文本文件 students.txt
,內(nèi)容如下:
John 20 85.5 Alice 22 90.0 Bob 21 78.5
#include <stdio.h> int main() { FILE *file = fopen("students.txt", "r"); if (file == NULL) { perror("無法打開文件"); return 1; } char name[50]; int age; float score; while (fscanf(file, "%s %d %f", name, &age, &score) == 3) { printf("姓名: %s, 年齡: %d, 分?jǐn)?shù): %.1f\n", name, age, score); } fclose(file); return 0; }
輸出:
姓名: John, 年齡: 20, 分?jǐn)?shù): 85.5
姓名: Alice, 年齡: 22, 分?jǐn)?shù): 90.0
姓名: Bob, 年齡: 21, 分?jǐn)?shù): 78.5
解釋:
fscanf
從文件students.txt
中解析每一行數(shù)據(jù),并輸出到屏幕上。它通過格式說明符%s %d %f
解析每行中的姓名、年齡和分?jǐn)?shù)。
完!
到此這篇關(guān)于c語言中比較特殊的輸入函數(shù)的文章就介紹到這了,更多相關(guān)c語言特殊輸入函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++控制臺實(shí)現(xiàn)隨機(jī)生成路徑迷宮游戲
這篇文章主要為大家詳細(xì)介紹了C++控制臺實(shí)現(xiàn)隨機(jī)生成路徑迷宮游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05深入解讀C++ 內(nèi)聯(lián)函數(shù)inline|nullptr
內(nèi)聯(lián)函數(shù):用** inline 修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會(huì)在調(diào)用的地方展開內(nèi)聯(lián)函數(shù)**,這樣調(diào)用內(nèi)聯(lián)函數(shù)就需要?jiǎng)?chuàng)建棧楨,就提高效率了,這篇文章給大家介紹C++ 內(nèi)聯(lián)函數(shù)inline|nullptr的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧2024-07-07C++11右值引用和轉(zhuǎn)發(fā)型引用教程詳解
這篇文章主要介紹了C++11右值引用和轉(zhuǎn)發(fā)型引用教程詳解,需要的朋友可以參考下2018-03-03Qt基于QRencode實(shí)現(xiàn)生成二維碼
QRencode是一個(gè)開源的庫,專門用于生成二維碼(QR?Code),這篇文章主要為大家詳細(xì)介紹了Qt如何使用QRencode實(shí)現(xiàn)生成二維碼功能,需要的可以參考下2025-02-02C++保存txt文件實(shí)現(xiàn)方法代碼實(shí)例
這篇文章主要介紹了C++保存txt文件實(shí)現(xiàn)方法代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11C++通過共享內(nèi)存ShellCode實(shí)現(xiàn)跨進(jìn)程傳輸
在計(jì)算機(jī)安全領(lǐng)域,ShellCode是一段用于利用系統(tǒng)漏洞或執(zhí)行特定任務(wù)的機(jī)器碼,本文主要為大家介紹了C++如何通過共享內(nèi)存ShellCode實(shí)現(xiàn)跨進(jìn)程傳輸,需要的可以參考下2023-12-12