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

