一、輸入和輸出流
- C 語言的標準輸入輸出函數都是獨立于設備的,不需要考慮如何在特定設備上傳輸數據;C 語言的庫函數和操作系統會確保在特定設備上的操作完全正常。
- C 語言的每個輸入源和輸出目的地都稱為流(stream);流和設備實體相互獨立。
- 程序使用的設備通常都有一個或多個相關的流;
- 磁盤驅動器一般包含多個文件,流和數據源或目的地一一對應,而不是和設備一一對應。
- 輸入輸出流還可以進一步細分為:字符流(character stream)和二進制流(binary stream)。
- 字符流中傳輸的是一系列字符,可以根據格式規范庫例程修改;
- 二進制流中傳輸的數據是以系列字節,不能以任何方式修改。
二、標準流
流有標識它的名稱。C 語言有三個在 <stdio.h> 頭文件中預定義的標準流,程序只要包含這個頭文件,就可以使用這些流。這三個標準流是:
- stdin
- stdout
- stderr
stderr 流只是將來自 C 庫的錯誤信息傳送出去,也可以將自己的錯誤信息傳送給 sterr。寫入 stdout 和 stderr 這兩個流的數據的目的地默認為命令行,這兩個流的主要差別是:
- 輸出到 stdout 的流在內存上緩存,所以寫入到 stdout 的數據不會馬上送到設備。
- 輸出到 stderr 的流不進行緩存,所以寫入 stderr 的數據會立即傳送到設備上。
對于緩存的流,程序會在內存中傳輸緩存區域的數據,在物理設備上傳輸數據可以異步進行。這使得輸入輸出操作更為高效。
使用操作系統命令,stdin 和 stdout 都可以重定向到文件上,而不是默認的鍵盤和屏幕上。
三、鍵盤輸入
stdin 上的鍵盤輸入有兩種形式:
- 格式化輸入,主要由 scanf() 提供;
- 非格式化輸入,通過 getchar() 等函數接收原始的字符串數據。
3.1、格式化鍵盤輸入
scanf 從 stdin 流中讀入字符,并根據格式控制字符串中的格式說明符,將它們轉換成一個或多個值。
示例代碼:
char string[100];
scanf("%s",string);
3.2、輸入格式控制字符串
在 scanf() 函數中使用的格式控制字符串不完全類似于 printf() 中的格式控制字符串。在格式控制字符串中添加一個或多個空白字符串,如空格 ' '、制表符 '\t' 或換行符 '\n',scanf() 會忽略空白字符,直接讀入輸入中的下一個非空白字符。在格式控制字符串中只要出現一個空白字符,就會忽略無數個連續的空白字符。要注意的是,scanf() 默認忽略空白字符,但使用 %c、%[] 或 %n 說明符讀取數據時除外(見下表)。
scanf() 會讀入任何非空白字符(除了%以外),但不會存儲這個連續出現的字符。以下是輸入格式符的一般形式:
% * field_width 長度修飾符 conversion_character
含義如下:
格式部分 | 意 義 |
---|---|
% | 表示格式說明符的開始 |
* | 表示要忽略的輸入值 |
field_width | 指定輸入字段中的字符數 |
長度修飾符 | 指定數值和指針輸入值的長度 |
conversion_character | 指定要把輸入轉換成什么類型 |
以下是一般格式的個部分說明:
- %:表示格式說明符的開頭,不能省略。
- *:可選,表示忽略下一個輸入值。
- 字段寬度:可選,它是一個整數,指定了 scanf() 讀入的字符數。
- 長度修飾符:可選,
示例代碼:
#include <stdio.h>
#define SIZE 20
void try_input(char* prompt, char* format);
int main() {
try_input("Enter as input: -2.35 15 25 ready2go\n", "%f %d %d %[abcdefghijklmnopqrstuvwxyz] %*1d %s%n");
try_input("\nEnter the same input again: ", "%4f %4d %d %*d %[abcdefghijklmnopqrstuvwxyz] %*1d %[^o]%n");
try_input("Enter as input: -2.3A 15 25 ready2go\n", "%4f %4d %d %*d %[abcdefghijklmnopqrstuvwxyz] %*1d %[^o]%n");
return 0;
}
void try_input(char* prompt, char* format) {
int value_count = 0;
float fp1 = 0.0f;
int i = 0;
int j = 0;
char word1[SIZE] = " ";
char word2[SIZE] = " ";
int byte_count = 0;
printf(prompt);
value_count = scanf(format, &fp1, &i, &j, word1, word2, &byte_count);
fflush(stdin);
printf("The input format string for scanf() is:\n \"%s\"\n",format);
printf("Count of bytes read = %d\n",byte_count);
printf("Count of values read = %d\n",value_count);
printf("fp1 = %f i = %d j = %d\n",fp1, i, j);
printf("word1 = %s word2 = %s\n",word1, word2);
}
3.3、輸入格式字符串中的字符
可以在輸入格式字符串中包含一些不是格式轉換說明符的字符。為此,必須指定輸入中有這些字符,且 scanf() 函數應讀取它們,但不存儲它們。這些非格式轉換字符必須和輸入流的字符完全相同,只要有一個不同,scanf() 就會終止輸入。
示例代碼:
#include <stdio.h>
int main() {
int i = 0;
int j = 0;
int value_count = 0;
float fp1 = 0.0f;
printf("Enter: fp1 = 3.14159 i = 7 8\n");
printf("\nInput:");
value_count = scanf("fp1 = %f i = %d %d", &fp1, &i, &j);
printf("\nOutput:");
printf("Count of values read = %d\n", value_count);
printf("fp1 = %f\ti = %d\tj = %d\n", fp1, i, j);
return 0;
}
運行結果:
Enter: fp1 = 3.14159 i = 7 8
輸入:
Input:fp1 = 3.14 i = 4 5
輸出:
Output:Count of values read = 3
fp1 = 3.140000 i = 4 j = 5
這些非格式轉換字符必須和輸入流的字符完全相同,才會得到正常的輸出結果。
3.4、輸入浮點數的各種變化
使用 scanf() 函數讀取格式化的浮點數時,不僅可以選擇格式說明符,還可以輸入不同形式的數,示例代碼:
#include <stdio.h>
int main() {
float fp1 = 0.0f;
float fp2 = 0.0f;
float fp3 = 0.0f;
int value_count = 0;
printf("Enter: 3.14.314E1.0314e+02\n");
printf("\nInput:");
value_count = scanf("%f %f %f", &fp1, &fp2, &fp3);
printf("\nOutput:");
printf("Number of values read = %d\n", value_count);
printf("fp1 = %f fp2 = %f fp3 = %f\n", fp1, fp2, fp3);
return 0;
}
執行結果:
Enter: 3.14.314E1.0314e+02
Input:3.14.314E1.0314e+02
Output:Number of values read = 3
fp1 = 3.140000 fp2 = 3.140000 fp3 = 3.140000
3.5、讀取十六進制和八進制值
可以使用格式說明符 %x 從輸入流中讀取十六進制值,使用 %o 讀取八進制值,示例代碼如下:
#include <stdio.h>
int main() {
int i = 0;
int j = 0;
int k = 0;
int n = 0;
printf("Enter three integer values\n");
n = scanf("%d %x %o", &i, &j, &k);
printf("\nOutput:");
printf("%d values read.\n", n);
printf("i = %d j = %d k = %d\n", i, j, k);
return 0;
}
執行結果:
Enter three integer values: 12 12 12
Output:3 values read.
i = 12 j = 18 k = 10
3.6、使用 scanf() 讀取字符
使用 %c 可以讀取一個字符,并將它存儲為 char 類型。對于字符串可以使用 %s 或是 %[]。此時要給存儲的字符串追加上 '\0',作為最后一個字符。要注意的是,%[] 可以讀入含有空格的字符串,
但是 %s 不可以。使用 %[] 說明符時,只需要在方括號內包含空格字符即可。
示例代碼:
#include <stdio.h>
#define MAX_TOWN 10
int main() {
char initial = ' ';
char name[80] = {' '};
char age[4] = {'0'};
printf("Enter your first initial: ");
scanf("%c", &initial);
printf("Enter your first name: ");
scanf("%s", name);
fflush(stdin);
if(initial != name[0]) printf("%s, you got your initial wrong.\n", name);
else printf("Hi, %s. Your initial is correct. Well done!\n", name);
printf("Enter your full name and your age separated by a comma:\n");
scanf("%[^,] , %[0123456789]", name, age);
printf("\nYour name is %s and your age are %s years old.\n", name, age);
return 0;
}
執行結果:
Enter your first initial: I
Enter your first name: Ivor
Hi, Ivor. Your initial is correct. Well done!
Enter your full name and your age separated by a comma:
Ivor Horton , 23
Your name is
Ivor Horton and your age are 23 years old.
scanf("%c", &initial) 中如果輸入空格,那么程序就會將空白字符當成 initial 的值,根據控制字符串的定義方式,使用說明符 %c 輸入的第一個字符就是要提取的字符。如果不接受空格
為 initial,可以修改為以下輸入語句:
scanf(" %c", &initial);
控制字符串中的第一個字符是空格,因此 scanf() 會讀入且忽略所有空格。
scanf("%[^,] , %[0123456789]", name, age) 中“,”后的空格也是必需的,原因與以上語句一樣。
3.7、從鍵盤上輸入字符串
<stdio.h> 中的 gets_s() 函數可以將一整行的文本作為字符串讀入。其函數原型如下:
char *gets_s(char *str, rsize_t n);
該函數會將之多 n-1 個連續字符讀入指針 str 所指向的內存中,直到按下回車為止。它會用中止字符‘\0’取代按下的回車鍵時讀入的換行符。其返回值與第一個變元相同。如果在輸入的
過程中出錯,str[0] 就設置為‘\0’字符。可以使用標準庫函數 fgets() 替代該函數,示例代碼如下:
#include <stdio.h>
#define MAX_TOWN 10
int main() {
char initial[3] = {' '};
char name[80] = {' '};
printf("Enter your first initial: ");
fgets(initial, sizeof(initial), stdin);
printf("Enter your name: ");
fgets(name, sizeof(name), stdin);
if(initial[0] != name[0]) printf("%s, you got your initial wrong.\n", name);
else printf("Hi, %s, Your initial is correct. Well done!\n", name);
return 0;
}
執行結果:
Enter your first initial: I
Enter your name: Ivor Normal
Hi, Ivor Normal
Your initial is correct. Well done!
fgets() 函數讀取的字符數比第二個變元指定的字符數少 1,再添加終止字符'\0'。fgets() 函數再輸入字符串中存儲一個換行符來對應按下的回車鍵,而 gets_s() 函數不是這樣。
為了避免調用 printf() 輸出姓名時輸出一個換行符,需要覆蓋這個換行符。
對于字符串輸入,使用 gets_s() 和 fgets() 通常是首選,除非要控制字符串的內容,此時可以使用 %[]。
3.8、單個字符的鍵盤輸入
stdio.h 中的 getc() 函數從流中讀取一個字符,把字符代碼返回為 int 類型。getc() 的變元是流標識的。讀到流的末尾時,getc() 返回 EOF,這個符號在 stdio.h 中總是定義
為一個負整數。因為 char 類型可以由編譯器的開發人員確定為帶符號的或是不帶符號的,所以 getc() 不返回 char 類型。如果它返回 char 類型的值,則 char 定義為無符號的類型
時,就不能返回 EOF。一般情況下,函數返回 int 類型的值,但是希望返回 char 類型時,幾乎總是可以肯定它需要返回 EOF。
getchar() 函數可以從 stdin 中一次讀取一個字符,等價于用 stdin 變元調用 getc()。getchar() 在 stdio.h 中定義,原型如下:
int getchar(void);
getchar() 不需要變元,它會把輸入流中讀入的字符代碼返回為 int 類型。getchar() 和 putchar() 每次只處理一個字符,示例代碼:
#include <stdio.h>
int main(void) {
char ch;
while((ch = getchar()) != '#') {
putchar(ch);
}
return 0;
}
執行結果:
Hello MARVEL#I'm Iron man
Hello MARVEL
這里涉及了緩沖區,用戶輸入的字符被收集并存儲在與一個被稱為緩沖區的臨時存儲區,按下 ENTER 鍵后,程序才可使用用戶輸入的字符。緩沖區的意義是:首先,把若干字符作為一個塊進行傳輸比逐個
發送這些字符節省時間;其次,如果用戶打錯了字符,可以直接通過鍵盤修正錯誤。
緩沖分為兩類:
- 完全緩沖 I/O:緩沖區被填滿時才刷新緩沖區,通常出現在文件輸入流中;
- 行緩沖 I/O:出現換行符時刷新緩沖區,鍵盤輸入通常是行緩沖輸入。
ANSI C 和 后續的 C 標準都規定輸入是緩沖的,不過最初 K&R 把這個權利交給了編譯器的編寫者。
stdio.h 中也聲明了 ungetc() 函數,它允許把剛才讀取的一個字符放回輸入流。該函數需要兩個參數:輸入流
的字符和流的標識符(對于標準流就是 stdin)。ungetc() 返回一個 int 類型的值,對應放回輸入流的字符,如果操作失敗,返回一個特殊的字符 EOF。
原則上,可以把一連串字符串放回輸入流,但只保證一個字符有效。
示例代碼如下:
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
#define LENGTH 50
void eatspace(void);
bool getinteger(int* n);
char* getname(char* name, size_t length);
bool isnewline(void);
int main(void) {
int number;
char name[LENGTH] = {'\0'};
printf("Enter a sequence of integers and alphabetic names in asingle line:\n");
while(!isnewline()) {
if(getinteger(&number)) printf("Integer value: %8d\n", number);
else if(strlen(getname(name,LENGTH)) > 0) printf("Name: %s\n", name);
else {
printf("Invalid input.\n");
return 1;
}
}
return 0;
}
void eatspace(void) {
char ch = 0;
while(isspace(ch = (char)getchar()));
ungetc(ch, stdin);
}
bool getinteger(int* n) {
eatspace();
int value = 0;
int sign = 1;
char ch = 0;
if((ch = (char)getchar()) == '-') sign = -1;
else if(isdigit(ch)) value = ch - '0';
else if(ch != '+') {
ungetc(ch, stdin);
return false;
}
while(isdigit(ch = (char)getchar())) {
value = 10*value + (ch - '0');
}
ungetc(ch,stdin);
*n = value * sign;
return true;
}
char* getname(char* name, size_t length) {
eatspace();
size_t count = 0;
char ch = 0;
while(isalpha(ch = (char)getchar())) {
name[count++] = ch;
if(count == length -1) break;
}
name[count] = '\0';
if(count < length - 1) ungetc(ch, stdin);
return name;
}
bool isnewline(void) {
char ch = 0;
if((ch = (char)getchar()) == '\n') return true;
ungetc(ch, stdin);
return false;
}
執行結果:
Enter a sequence of integers and alphabetic names in asingle line:
Ivor 78 Horton 34 Jane 18
Name: Ivor
Integer value: 78
Name: Horton
Integer value: 34
Name: Jane
Integer value: 18
四、屏幕輸出
將格式化數據傳輸到 stout 流的主要函數是 printf(),stdio.h 中還聲明了可選的 printf_s() 函數,也就是 printf() 函數的安全版本。printf_s() 和 printf() 的
主要區別是 printf_s() 不允許在格式字符串中包含 %n,這是因為 該輸出說明符會把數據寫入內存,導致不安全。
4.1、使用 printf() 的格式化輸出
函數原型如下:
int printf(char *format, ...);
printf() 函數的指針變元不能為 NULL,如果變元多余格式說明符,就會忽略多余的變元。
printf() 的格式轉換說明符比 scanf() 復雜很多,輸出格式說明符一般形式如下:
% flag field_width precision size_flag conversion_character
其內容和意義如下:
格式部分 | 標 記 | 意 義 | 是否可選 |
---|---|---|---|
% | 格式說明符的開頭 | 否 | |
flag | -, +, space, # or 0 | 影響輸出的標記 | 是 |
field_width | 輸出字段中的最小字符數 | 是 | |
precision | 精度指定符 | 是 | |
size_flag | h, hh, l, ll, j, z, t, t or L | 修改轉換類型的尺寸標記 | 是 |
conversion_character | d, i, o, u, x, X, p, n, e, E, f, F, g, G, a, A, c, or s | 要使用的輸出轉換類型 | 否 |
影響輸出的標記:
字 符 | 用 途 |
---|---|
+ | 對于有符號的輸出,這個字符確保輸出值的前面總是有一個符號+或-。默認情況下,只有符號有 - 號 |
- | 指定輸出值在輸出字段中左對齊,右邊用空格填充。輸出的默認對齊方式為右對齊 |
0 | 指定在輸出值的前面填充0,以填滿字段寬度 |
# | 指定將0放在八進制的輸出前面,將0X或0x放在十六進制的輸出的前面,或者浮點數包含小數點。對于g或G浮點轉換字符,忽略尾部的0 |
space | 指定在正數或0輸出值前面放置一個空格,而不是+號 |
輸出字段中的最小字符數:
如果輸出需要更多的字符,它會自動增加。如果輸出值需要的字符小于指定的最小字符數,多余位置會填充空白,除非字段寬度用前導 0 指定,例如 09,此時在左邊會補入 0。
精度指定符:
它通常用于浮點數的輸出,包含一個小數點后跟一個整數。說明符 .n 表示輸出值精確到小數點后 n 位。如果輸出的小數點位數多于 n,就四舍五入或舍棄掉。如果把它用于整數裝換,它就指定要在
輸出中顯式的最少位數。
尺寸標記:
標 記 | 作 用 |
---|---|
h | 其后的整數轉換說明符應用于 short 或 unsigned short 變元 |
hh | 其后的整數轉換說明符應用于 signed char 或 unsigned char 變元 |
l | 其后的整數轉換說明符應用于 long 或 unsigned long 變元 |
ll | 其后的整數轉換說明符應用于 long long 或 unsigned long long 變元 |
j | 其后的整數轉換說明符應用于 intmax 或 uintmax_t 變元。該標記會避免編譯器發出警告,因為 size_t 取決于是實現碼的整數類型 |
z | 其后的整數轉換說明符應用于 size_t 變元 |
t | 其后的整數轉換說明符應用于 ptrdiff_t 變元 |
L | 其后的浮點數轉換說明符應用于 long double 變元 |
轉換字符:
應用類型 | 轉換字符 | 生成的輸出 |
---|---|---|
整數 | ||
d 或 i | 帶符號的十進制整數值 | |
o | 不帶符號的八進制整數值 | |
u | 不帶符號的十進制整數值 | |
x | 不帶符號的十六進制整數(使用小寫的十六進制數) | |
X | 不帶符號的十六進制整數(使用大寫的十六進制數) | |
浮點數 | ||
f 或 F | 帶符號的小數值 | |
e | 帶符號和指數的小數值 | |
E | 與 e 相同,使用 E | |
g | 與 e 或 f 相同,取決于值的大小和精度 | |
G | 與 g 相同,但用 E 表示指數 | |
A 或 a | 用十六進制表示雙精度值,十六進制的尾數前面加上 0x 或 0X 前綴,指數前加上 p 或 P,例如:0xh.hhhp±d | |
指針 | ||
p | 把變元的輸出為指針,變元的類型應該是 void* | |
字符 | ||
c | 單個字符或精度字符 | |
s | 在‘\0’之前的所有字符串或已輸出的 precision 個字符 |
注意:%n 只能用于 printf()。對應的變元必須是 int* 類型。作用是將字符數輸入 stdout。
4.2、轉移序列
轉移序列 | 說 明 |
---|---|
\b | 退格 |
\f | 換頁 |
\n | 換行 |
\r | 回車(用于打印機),在屏幕輸出中,就是移動到當前行的開頭 |
\t | 水平制表符 |
4.3、整數輸出
示例代碼:
#include <stdio.h>
int main() {
int i = 15, j = 345, k = 4567;
long long li = 56789LL, lj = 67891234567LL, lk = 23456789LL;
printf("i = %d j = %d k = %d i = %6.3d j = %6.3d k = %6.3d\n", i, j, k, i, j, k);
printf("i = %-d j = %+d k = %-d i = %-6.3d j = %-6.3d k = %-6.3d\n", i, j, k, i, j, k);
printf("li = %d lj = %d lk = %d\n", li, lj, lk);
printf("li = %lld lj = %lld lk = %lld\n", li, lj, lk);
return 0;
}
編譯時會有如下警告:
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long long int’ [-Wformat=]
printf("li = %d lj = %d lk = %d\n", li, lj, lk);
執行結果:
i = 15 j = 345 k = 4567 i = 015 j = 345 k = 4567
i = 15 j = +345 k = 4567 i = 015 j = 345 k = 4567
li = 56789 lj = -828242169 lk = 23456789
li = 56789 lj = 67891234567 lk = 23456789
由以上輸出結果可以看出,標志“-”使輸出左對齊。對于第二個 i 值的輸出,插入了一個前導 0, 因為最小精度指定為 3.如果在格式說明符的最小字符寬度前放置一個 0,并忽略精度說明符,也可以
得到相同的結果。有精度說明符時,會忽略前導 0。
第三行輸出在編譯時會發出警告,給出值的字符寬度及精度不夠大,會造成意想不到的結果。
4.4、輸出浮點數
示例代碼:
#include <stdio.h>
int main() {
float fp1 = 345.678f, fp2 = 1.234E6f;
double fp3 = 234567898.0, fp4 = 11.22334455e-6;
printf("%f %+f %-10.4f %6.4f\n", fp1, fp2, fp1, fp2);
printf("%e %+E\n", fp1, fp2);
printf("%f %g %#+f %8.4f %10.4g\n", fp3, fp3, fp3, fp3, fp4);
return 0;
}
執行結果:
345.678009 +1234000.000000 345.6780 1234000.0000
3.456780e+02 +1.234000E+06
234567898.000000 2.34568e+08 +234567898.000000 234567898.0000 1.122e-05
fp1 的第二個輸出值說明熱如何限制小數點后的位數。為 fp2 的第二個輸出指定的字符寬度太小,放不下小數位,因此會舍棄多余的部分。
4.5、字符輸出
示例代碼:
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
int main() {
int count = 0;
printf("The printable characters are the following:\n");
for(int code = 0; code <= CHAR_MAX; ++code) {
char ch = (char)code;
if(isprint(ch)) {
if(count++ % 32 == 0) printf("\n");
printf(" %c", ch);
}
}
printf("\n");
return 0;
}
執行結果:
! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
@ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
五、其他輸出函數
在 stdio.h 頭文件中聲明的 puts() 函數和 gets_s() 函數互補。該函數原型如下:
int puts(const char *string);
puts() 函數接受字符串指針作為變元,將字符串后的一個換行符寫入標準輸出流 stdout。其字符串必須用字符‘\0’終止。puts() 函數的參數是 const,所以該函數不能修改
傳送給她的字符串。puts() 函數用于輸出單行信息,例如:
puts("Is there no end to input and output?");
使用 printf() 函數必須在字符串末尾添加‘\n’,才能達到該效果。
5.1 屏幕的非格式化輸出
函數 putchar() 也是 stdio.h 中定義的函數,與 getchar() 函數互補。其原型如下:
int putchar(int c);
該函數將單個字符 c 輸出到 stdout 上,并返回所顯示的字符。它可以輸出信息,一次先是一個字符,該方法可以控制是否輸出某些字符。例如,輸出一個字符串:
char string[] = "Beware the Jabberwock, \nmy son!";
puts(string);
或是:
int i = 0;
while() {
if(string[i] != '\n') putchar(string[i]);
++i;
}
5.2、數組的格式化
在 stdio.h 中聲明的 sprintf_s() 或 snprintf_s() 函數,可以格式化數據寫入 char 類型的數組中,它們是 sprintf() 標準函數的安全版本,因此它們禁止寫到數組外部。它們的區別是,
sprintf_s() 將超出數組的范圍看作一個運行錯誤,而 snprintf_s() 僅截斷輸出,使結果能放置在數組中。這里僅討論 snprintf_s(),其函數原型如下:
int snprintf_s(char * restrict str, rsize_t n, const * restrict format, ...);
第一個變元是數組的地址,是數組的地址,使輸出的目的地。第二個變元叔叔祖德長度,它的工作方式與 printf_s() 相同,只是將數據寫入 str,而不是 stdout。示例代碼:
char result[20];
int count = 4;
int nchars = snprintf_s(result, sizeof(result), "A dog has %d legs.", count);
5.3、數組的格式化輸入
可選的 sscanf_s() 函數與 snprintf_s() 函數互補,因為 sscanf_s() 函數可以在格式字符串的控制下,從 char 類型的數組元素中讀取數據。 它是 sscanf() 函數的安全版本,主要區別是
sscanf_s() 需要給每個 c、s 或是 [ 說明符指定地址和長度變元,而 sscanf() 只需要地址。sscanf_s() 函數的原型如下:
int sscanf_s(const char * restrict str, const char * restrict format, ...);
示例代碼:
char *source = "Fred 94";
char name[10] ={0};
int age = 0;
int items = sscanf_s(source, " %s %d", name, sizeof(name), &age);
以上代碼的執行結果是:name 包含字符串 "Fred",age 的值是 94。items 變量的值是 2,因為從source 中讀取了兩項。