本章的主題是C語言的字符串和格式化輸入/輸出。
C語言沒有專門用于存儲(chǔ)字符串的變量類型吗跋,字符串都被存儲(chǔ)在
char
類型的數(shù)組中桌粉。-
數(shù)組是同類型數(shù)據(jù)元素的有序序列。
- 以
char name[40]
為例祭钉,name
后面的方括號表明這是一個(gè)數(shù)組,方括號中的40
表明該數(shù)組中的元素?cái)?shù)量己沛,char
表明每個(gè)元素的類型慌核。 - 字符串可以理解為字符數(shù)組,每個(gè)單元存儲(chǔ)一個(gè)字符申尼,數(shù)組末尾用一個(gè)空字符(null character)標(biāo)識結(jié)束遂铡。
- 以
空字符
\0
是非打印字符,其ASCII碼值為0晶姊。由于空字符的存在,因此字符串實(shí)際能存儲(chǔ)的字符數(shù)要減1伪货,剩下一個(gè)字節(jié)留給空字符们衙。上例中字符串name
實(shí)際能存儲(chǔ)的字符數(shù)為39钾怔。轉(zhuǎn)換字符
%s
用于讀寫字符串,%zd
用于處理sizeof()
和strlen()
的返回值蒙挑。scanf()
在遇到第一個(gè)空白(空格宗侦、制表符或換行符)時(shí)就不再讀取輸入。C語言還有其他的輸入函數(shù)(如忆蚀,fgets()
)矾利,用于讀取一般字符串,后面會(huì)詳談馋袜。-
使用符號常量(symbolic constant)或 明示常量(manifest constant)的好處:
- 常量名比數(shù)字表達(dá)的信息更多男旗;
- 復(fù)用性更好。
-
使用C預(yù)處理器來定義符號常量:
#define NAME value
欣鳖。- 例如察皇,
#define PI 3.14159
。編譯程序時(shí)泽台,程序中所有的PI
都會(huì)被替換成3.14159
什荣。這一過程被稱為編譯時(shí)替換(compile-time substitution)。 - 為什么
PI
要大寫怀酷?因?yàn)橛么髮懕硎痉柍A渴荂語言一貫的傳統(tǒng)稻爬,這樣做是為了提高程序的可讀性,在程序中看到全大寫的名稱就立刻明白這是一個(gè)符號常量蜕依,而非變量桅锄。
- 例如察皇,
-
C90標(biāo)準(zhǔn)新增了
const
關(guān)鍵字,用于限定一個(gè)變量為只讀笔横。const int MONTHS = 12; // MONTHS在程序中不可更改竞滓,值為12
const
用起來比#define
更靈活,后續(xù)會(huì)詳談吹缔。 printf()
和scanf()
是標(biāo)準(zhǔn)輸入/輸出函數(shù)商佑,簡稱為I/O函數(shù)。printf()
把整數(shù)厢塘、浮點(diǎn)數(shù)茶没、字符和字符串轉(zhuǎn)換成顯示在屏幕上的文本,而scanf()
正好與它相反晚碾,把輸入的字符串轉(zhuǎn)換成整數(shù)抓半、浮點(diǎn)數(shù)、字符和字符串存儲(chǔ)在內(nèi)存中格嘁。printf()
的格式為:printf(格式字符串, 待打印項(xiàng)1, 待打印項(xiàng)2, ...)
其中笛求,格式字符串是雙引號括起來的內(nèi)容,包含兩種形式不同的信息:(1)實(shí)際要打印的字符;(2)轉(zhuǎn)換說明探入。待打印項(xiàng)1狡孔、待打印項(xiàng)2等都是要打印的項(xiàng),可以是變量蜂嗽、常量或表達(dá)式苗膝。printf()
的轉(zhuǎn)換說明
轉(zhuǎn)換說明 | 含義 |
---|---|
%a |
浮點(diǎn)數(shù)、十六進(jìn)制數(shù)和p記數(shù)法(C99/C11) |
%A |
浮點(diǎn)數(shù)植旧、十六進(jìn)制數(shù)和p記數(shù)法(C99/C11) |
%c |
單個(gè)字符 |
%d |
有符號十進(jìn)制整數(shù) |
%e |
浮點(diǎn)數(shù)辱揭,e記數(shù)法 |
%E |
浮點(diǎn)數(shù),e記數(shù)法 |
%f |
浮點(diǎn)數(shù)病附,十進(jìn)制記數(shù)法 |
%g |
根據(jù)值的不同问窃,自動(dòng)選擇%f 或%e 。 |
%G |
根據(jù)值的不同胖喳,自動(dòng)選擇%f 或%E 泡躯。 |
%i |
有符號十進(jìn)制整數(shù)(和%d 相同) |
%o |
無符號八進(jìn)制整數(shù) |
%p |
指針 |
%s |
字符串 |
%u |
無符號十進(jìn)制整數(shù) |
%x |
無符號十六進(jìn)制整數(shù),使用十六進(jìn)制數(shù)0f |
%X |
無符號十六進(jìn)制整數(shù)丽焊,使用十六進(jìn)制數(shù)0F |
%% |
打印一個(gè)百分號 |
-
printf()
的轉(zhuǎn)換說明修飾符:在%
和轉(zhuǎn)換字符
之間插入修飾符可修飾基本的轉(zhuǎn)換說明较剃。
修飾符 | 含義 |
---|---|
標(biāo)記 ????????? |
有6種標(biāo)記(- 、+ 技健、空格 写穴、# 、* 和0 )雌贱,可以不使用標(biāo)記或使用多個(gè)標(biāo)記- :待打印項(xiàng)左對齊+ :有符號值若為正啊送,則在值前面顯示加號;若為負(fù)欣孤,則在值前面顯示減號空格 :有符號值若為正馋没,則在值前面顯示前導(dǎo)空格;若為負(fù)降传,則在值前面顯示減號# :把結(jié)果轉(zhuǎn)換為另一種類型篷朵。如果是%o 格式,則以0 開始婆排;如果是%x 或%X 格式声旺,則以0x 或0X 開始;對于所有的浮點(diǎn)格式段只,# 保證了即使后面沒有任何小數(shù)腮猖,也打印一個(gè)小數(shù)點(diǎn)字符;對于%g 和%G 格式赞枕,# 防止結(jié)果后面的0 被刪除* :抑制賦值(詳見后面解釋)0 :對于數(shù)值格式澈缺,用前導(dǎo)0 代替空格填充字段寬度坪创。對于整型格式,如果出現(xiàn)- 標(biāo)記或指定精度姐赡,則忽略該標(biāo)記 ? |
數(shù)字 |
最小字段寬度 如果該字段不能容納待打印的數(shù)字或字符串误堡,系統(tǒng)會(huì)使用更寬的字段 |
.數(shù)字 |
精度 對于 %e 、%E 和%f 轉(zhuǎn)換雏吭,表示小數(shù)點(diǎn)右邊數(shù)字的位數(shù)對于 %s 轉(zhuǎn)換,表示待打印字符的最大數(shù)量對于整型轉(zhuǎn)換陪踩,表示待打印數(shù)字的最小位數(shù) 如有必要杖们,使用前導(dǎo) 0 來達(dá)到這個(gè)位數(shù)只使用 . 表示其后跟隨一個(gè)0 ,所以%.f 和%.0f 相同 |
h |
和整型轉(zhuǎn)換說明一起使用肩狂,表示short int 或unsigned short int 類型的值 |
hh |
和整型轉(zhuǎn)換說明一起使用摘完,表示signed char 或unsigned char 類型的值 |
j |
和整型轉(zhuǎn)換說明一起使用,表示intmax_t 或uintmax_t 類型的值傻谁。這些類型定義在stdint.h 中 |
l |
和整型轉(zhuǎn)換說明一起使用孝治,表示long int 或unsigned long int 類型的值 |
ll |
和整型轉(zhuǎn)換說明一起使用,表示long long int 或unsigned long long int 類型的值 |
L |
和浮點(diǎn)轉(zhuǎn)換說明一起使用审磁,表示long double 類型的值 |
t |
和整型轉(zhuǎn)換說明一起使用谈飒,表示ptrdiff_t 類型的值。ptrdiff_t 是兩個(gè)指針差值的類型 |
z |
和整型轉(zhuǎn)換說明一起使用态蒂,表示size_t 類型的值杭措。size_t 是sizeof() 返回的類型 |
printf()
有一個(gè)返回值,它返回打印字符的個(gè)數(shù)钾恢。如果有輸出錯(cuò)誤手素,則返回一個(gè)負(fù)值。給字符串?dāng)嘈杏?種方法瘩蚪。
// longstrg.c --打印較長的字符串
#include <stdio.h>
int main(void)
{
// 方法1:使用多個(gè)printf()語句
printf("Here's one way to print a ");
printf("long string.\n");
// 方法2:使用反斜杠和Enter鍵組合
printf("Here's another way to print a \
long string.\n");
// 方法3:字符串連接
printf("Here's the newest way to print a "
"long string.\n");
return 0;
}
-
scanf()
函數(shù)的格式為:scanf(格式字符串, 地址列表)
其中泉懦,地址列表
是指向變量的指針,此處不必了解如何使用指針疹瘦,只需記住以下兩條簡單的規(guī)則:- 如果用
scanf()
讀取基本變量類型的值崩哩,則在變量名前加上一個(gè)&
; - 如果用
scanf()
把字符串讀入字符數(shù)組中拱礁,不要使用&
琢锋。
- 如果用
scanf()
函數(shù)所用的轉(zhuǎn)換說明與printf()
函數(shù)幾乎相同。主要的區(qū)別是呢灶,對于float
類型和double
類型吴超,printf()
都使用%f
、%e
鸯乃、%E
鲸阻、%g
和%G
轉(zhuǎn)換說明跋涣,而scanf()
只把它們用于float
類型,對于double
類型要用l
修飾符鸟悴。在
scanf()
中陈辱,除了%c
,其他轉(zhuǎn)換說明都會(huì)自動(dòng)跳過待輸入值前面的所有空白细诸。scanf()
函數(shù)允許把普通字符放在格式字符串中沛贪。除空格字符外的普通字符必須與輸入字符串嚴(yán)格匹配。scanf()
函數(shù)返回成功讀取的項(xiàng)數(shù)震贵。如果沒有讀取任何項(xiàng)利赋,且需要讀取一個(gè)數(shù)字而用戶卻輸入一個(gè)非數(shù)值字符串,scanf()
便返回0
猩系。-
printf()
和scanf()
都可以使用*
修飾符來修改轉(zhuǎn)換說明的含義媚送,但用法不一樣。-
printf()
:如果不想預(yù)先指定字段寬度或精度寇甸,希望通過程序來指定塘偎,可以用*
修飾符代替字段寬度或精度,但需要參數(shù)告訴函數(shù)拿霉,字段寬度或精度應(yīng)該是多少吟秩。 -
scanf()
:把*
放在%
和轉(zhuǎn)換字符之間時(shí),會(huì)使得scanf()
跳過相應(yīng)的輸入項(xiàng)友浸。在程序需要讀取文件中特定列的內(nèi)容時(shí)峰尝,這項(xiàng)跳過功能很有用。
-
使用
scanf()
輸入分?jǐn)?shù)時(shí)收恢,不能直接使用以下語句
/* 這是錯(cuò)誤的分?jǐn)?shù)輸入 */
scanf("%f", &x); // 在實(shí)際輸入的時(shí)候不能輸入類似"3/7"的數(shù)值武学,因?yàn)閟canf()并不能識別"/"
/* 這是正確的分?jǐn)?shù)輸入 */
scanf("%d/%d", &x, &y);
- 使用
scanf()
可以實(shí)現(xiàn)長數(shù)據(jù)的截取與跳過
/* 截取身份證號的出生年月日 */
#include <stdio.h>
int main(void)
{
int year, month, day;
printf("請輸入您的身份證號:");
scanf("%*6d%4d%2d%2d%*4d", &year, &month, &day);
printf("您的生日是:%d年%d月%d日\n", year, month, day);
return 0;
}
下一章的主題是C語言的運(yùn)算符、表達(dá)式和語句伦意。