本書以Visual C++ 6.0為開發平臺,全面介紹了C語言的基礎知識、程序結構及程序編寫技巧。全書共分為12章,包括引言、C語言基礎知識、順序結構程序設計、選擇結構程序設計、循環結構程序設計、函數、預處理、數組、指針、結構體與共用體、文件、位運算。本書內容豐富、結構合理、思路清晰、語言簡練流暢、示例翔實,在準確講解概念的基礎上力求通俗易懂,大量引入實例,分析程序設計思路,旨在培養學生的實踐動手能力。每章均配有豐富的例題和習題,并附有參考答案。本書既可作為普通高校非計算機專業計算機公共課的教材,也可作為學習C語言程序設計的自學用書。
本書以Visual C++ 6.0為開發平臺,全面介紹了C語言的基礎知識、程序結構及程序編寫技巧。全書共分為12章,包括引言、C語言基礎知識、順序結構程序設計、選擇結構程序設計、循環結構程序設計、函數、預處理、數組、指針、結構體與共用體、文件、位運算。本書內容豐富、結構合理、思路清晰、語言簡練流暢、示例翔實,在準確講解概念的基礎上力求通俗易懂,大量引入實例,分析程序設計思路,旨在培養學生的實踐動手能力。每章均配有豐富的例題和習題,并附有參考答案。本書既可作為普通高校非計算機專業計算機公共課的教材,也可作為學習C語言程序設計的自學用書。
“C語言程序設計”是高校計算機專業和理工科專業重要的公共基礎課程之一。C語言的功能強大,使用靈活方便,移植性強,兼有高級語言和低級語言的特點,利用C語言可以編寫系統軟件和應用軟件。
作者根據多年的教學經驗,結合高校非計算機專業計算機基礎教學的最新大綱,在分析國內外多種同類教材的基礎上,編寫了本書。本書力求通過理論聯系實際,采用計算思維的方法,引導和啟發學生掌握思考和解決問題的方法,達到舉一反三的目的。
本書共分12章,主要內容如下:
第1章主要介紹C語言的發展過程及特點、C語言的結構特點、C語言程序的執行過程。
第2章主要介紹C語言的數據類型、標識符、常量和變量、運算符和表達式等內容。
第3章主要介紹算法的基本概念、C語言的基本語句、數據的輸入和輸出等內容。
第4章主要介紹if結構、if…else結構、if語句的嵌套、switch語句。
第5章主要介紹while語句、do…while語句、for語句、循環的嵌套、break和continue語句在循環結構中的應用等內容。
第6章主要介紹函數的基本概念、變量的作用域和存儲類型、內部函數和外部函數、函數的遞歸調用等內容。
第7章主要介紹宏定義、文件包含、條件編譯等內容。
第8章主要介紹數組概述、一維數組、二維數組、字符數組與字符串等內容。
第9章主要介紹指針概述、指針變量與簡單變量的關系、指針與數組、指針作為函數的參數、函數的返回值為指針、指向指針的指針等內容。
第10章主要介紹結構體類型、結構體數組、結構體變量與函數、共用體數據類、枚舉數據類型、鏈表的概念等內容。
第11章主要介紹C文件的基本概念和分類、文件的基本操作、文件的定位、出錯的檢測等內容。
第12章主要介紹位的取反運算、左移運算、右移運算、與運算、或運算、異運算、復合位運算等內容。此章為選講章節。
本書內容豐富、結構合理、思路清晰、語言簡練流暢,書中所有示例都已在Visual C++ 6.0 環境下調試并運行通過。為了幫助讀者更好地掌握C語言,每章末尾都安排了類型豐富的習題,并且隨書提供了自主開發的“C語言輔導學習系統”軟件。輔導學習系統中有“學習指導”、“單元練習”、“綜合練習”以及“經典算法”等模塊,緊密結合教學內容,已應用于教學實踐多年,深受師生好評。讀者依據本書循序漸進地學習,可以鞏固基本知識、培養實踐能力、增強對基本概念的理解和解決實際問題的能力,能夠比較容易地掌握C語言的主要用法。
本書獲內蒙古科技大學教材建設項目資助,由內蒙古科技大學計算機教學基地的教師編寫,由黃迎久、龐潤芳任主編,徐揚、賈茹、趙軍富、胡曉燕任副主編。第1章和第2章由黃迎久編寫;第3章、第4章和前言由徐揚編寫;第5章和第11章由龐潤芳編寫;第6章、第7章和第12章由賈茹編寫;第8章和附錄由趙軍富編寫;第9章和第10章由胡曉燕編寫。全書由黃迎久負責統稿。
由于作者水平有限,書中的疏漏和瑕疵在所難免,歡迎廣大讀者批評指正。
編 者
第1章 引言1
1.1 C語言的發展過程及特點2
1.1.1 C語言的發展過程2
1.1.2 C語言的特點2
1.2 簡單的C語言程序3
1.3 C語言程序的結構5
1.4 C語言程序的執行6
1.4.1 編譯源程序6
1.4.2 鏈接目標程序6
1.4.3 C語言開發工具簡介7
本章小結12
習題13
第2章 C語言基礎知識15
2.1 C語言的數據類型16
2.1.1 整型數據16
2.1.2 浮點型數據18
2.1.3 字符型數據19
2.2 標識符、常量和變量20
2.2.1 標識符20
2.2.2 常量21
2.2.3 變量23
2.3 運算符與表達式24
2.3.1 概述24
2.3.2 算術運算符及算術表達式25
2.3.3 賦值運算符及賦值表達式26
2.3.4 自增、自減運算符27
2.3.5 關系運算符及關系表達式28
2.3.6 邏輯運算符及邏輯表達式29
2.3.7 位運算符及位運算30
2.3.8 條件運算符及條件表達式31
2.3.9 逗號運算符及逗號表達式32
2.3.10 數據類型的轉換32
2.4 小型實訓案例33
本章小結34
習題34
第3章 順序結構程序設計37
3.1 算法38
3.1.1 算法的概念38
3.1.2 算法的表示39
3.2 結構化程序設計的三種基本結構40
3.3 C語言的基本語句40
3.4 數據的輸入/輸出42
3.4.1 格式輸出函數printf( )42
3.4.2 格式輸入函數scanf( )43
3.4.3 格式字符44
3.4.4 字符輸入/輸出函數47
3.5 程序應用實例48
3.6 小型實訓案例50
本章小結51
習題51
第4章 選擇結構程序設計55
4.1 if結構56
4.1.1 if語句56
4.1.2 if…else語句57
4.1.3 if語句的嵌套58
4.2 switch語句60
4.2.1 switch語句的一般格式60
4.2.2 break語句在switch語句中
的應用62
4.3 程序應用實例63
4.4 小型實訓案例65
本章小結66
習題66
第5章 循環結構程序設計71
5.1 概述72
5.2 while語句72
5.3 do…while語句76
5.4 for語句77
5.5 循環的嵌套79
5.6 break語句與continue語句80
5.6.1 break語句80
5.6.2 continue語句81
5.6.3 break語句與continue的
比較83
5.7 幾種循環的比較83
5.8 程序應用實例83
5.9 小型實訓案例89
本章小結90
習題90
第6章 函數95
6.1 函數概述96
6.1.1 函數的定義97
6.1.2 函數的聲明和調用100
6.1.3 函數的參數傳遞105
6.2 變量的作用域和存儲類型107
6.2.1 變量的作用域108
6.2.2 變量的存儲類型110
6.3 內部函數與外部函數114
6.4 函數的遞歸調用116
6.5 程序應用實例117
6.6 小型實訓案例119
本章小結120
習題121
第7章 預處理127
7.1 宏定義128
7.2 文件包含130
7.3 條件編譯131
本章小結133
習題133
第8章 數組137
8.1 概述138
8.2 一維數組139
8.2.1 一維數組的定義139
8.2.2 一維數組的初始化140
8.2.3 一維數組元素的引用140
8.2.4 一維數組的應用142
8.3 二維數組147
8.3.1 二維數組的定義147
8.3.2 二維數組的初始化148
8.3.3 二維數組的引用149
8.3.4 二維數組的應用149
8.4 字符數組與字符串152
8.4.1 字符數組152
8.4.2 字符串153
8.4.3 字符串處理函數155
8.4.4 字符數組的應用159
8.5 數組作函數參數160
8.5.1 數組元素作函數實參160
8.5.2 數組名作函數實參161
8.6 小型實訓案例162
本章小結163
習題164
第9章 指針171
9.1 指針概述172
9.1.1 指針變量的定義172
9.1.2 指針變量的初始化173
9.1.3 指針變量的引用174
9.1.4 指針的運算174
9.2 指針變量與簡單變量的關系175
9.3 指針與數組177
9.3.1 指向一維數組的指針177
9.3.2 指向多維數組的指針178
9.3.3 字符指針182
9.3.4 指針數組185
9.4 指針作為函數的參數186
9.5 函數的返回值為指針188
9.6 指向函數的指針189
9.6.1 指向函數的指針變量定義189
9.6.2 函數指針變量的使用190
9.7 指向指針的指針191
9.8 程序應用實例192
9.9 小型實訓案例194
本章小結195
習題196
第10章 結構體與共用體201
10.1 結構體類型202
10.1.1 結構體的概念202
10.1.2 結構體類型的定義202
10.1.3 結構體變量的定義204
10.1.4 結構體變量的初始化205
10.1.5 結構體變量成員的引用206
10.2 結構體數組208
10.2.1 結構體數組的定義208
10.2.2 結構體數組的初始化208
10.2.3 結構體數組的引用209
10.3 結構體變量與函數210
10.4 共用體數據類型212
10.4.1 共用體類型的聲明212
10.4.2 共用體變量的定義、
初始化及引用213
10.5 枚舉數據類型215
10.5.1 枚舉類型的定義215
10.5.2 枚舉變量的定義215
10.5.3 有關枚舉型數據的操作216
10.6 鏈表的概念216
10.6.1 動態分配內存217
10.6.2 單鏈表的建立218
10.6.3 從單鏈表中刪除節點220
10.6.4 向鏈表中插入節點220
10.7 小型實訓案例222
本章小結223
習題223
第11章 文件229
11.1 C語言文件的基本概念與分類230
11.1.1 文件的基本概念230
11.1.2 文件的分類230
11.2 文件的基本操作231
11.2.1 文件類型指針231
11.2.2 打開文件函數fopen( )232
11.2.3 關閉文件函數fclose( )233
11.3 文件的讀寫233
11.3.1 字符讀/寫函數234
11.3.2 字符串讀/寫函數237
11.3.3 數據塊讀/寫函數237
11.3.4 格式化讀/寫函數238
11.4 文件的定位239
11.4.1 rewind()函數239
11.4.2 fseek()函數239
11.4.3 ftell()函數240
11.5 出錯的檢測241
11.6 小型實訓案例242
本章小結243
習題243
第12章 位運算247
12.1 按位取反運算248
12.2 按位左移運算249
12.3 按位右移運算249
12.4 按位與運算250
12.5 按位或運算251
12.6 按位異或運算252
12.7 復合位運算符253
本章小結254
習題254
附錄A C語言的關鍵字257
附錄B ASCII碼表259
附錄C 常用庫函數260
附錄D C運算符的優先級與結合性267
第2章 C語言基礎知識
【本章要點】
* C語言的基本數據類型
* C語言的標識符、變量和常量
* C語言程序的運算符與表達式
【學習目標】
* 掌握C語言的基本數據類型的特點及應用
* 掌握C語言的標識符、常量和變量的基本知識及應用
* 掌握C語言的各種運算符及表達式的應用
2.1 C語言的數據類型
數據類型是數據的基本屬性,描述的是數據的存儲格式和運算規則。不同類型的數據在內存中所需存儲空間的大小是不同的,能夠支持的運算、相應的運算規則也不同,因而在學習C程序時必須準確地掌握和運用數據的數據類型。
C語言的數據類型分類如圖2-1所示。
圖2-1 C語言的數據類型
2.1.1 整型數據
1. 基本概念
整型數據就是整數,整數又分為兩大類:有符號型和無符號型。有符號的整數既可以是正數,也可以是負數;不帶符號位(只包含0和正數)的整數為無符號整數。
整型(int)數據類型可以用4種修飾符的搭配來描述:signed(有符號)、unsigned(無符號)、long(長型)和short(短型)。
Visual C++ 6.0環境下整型數據的長度及取值范圍如表2-1所示。
表2-1 整型數據的長度及取值范圍
數據類型
占用字節
取值范圍
整型(int)
4
-2147483648~2147483647
有符號整型(signed int)
4
-2147483648~2147483647
無符號整型(unsigned int)
4
0~4294967295
短整型(short int)
2
-768~767
有符號短整型(signed short int)
2
-768~767
無符號短整型(unsigned short int)
2
0~65535
長整型(long int)
4
-2147483648~2147483647
有符號長整型(signed long int)
4
-2147483648~2147483647
無符號長整型(unsigned long int)
4
0~4294967295
在C語言中,對整型數據類型的說明可以使用簡寫方式,如表2-2所示。
表2-2 整型數據的簡寫方式
完整方式
簡寫方式
short int、signed short int
short
signed int
int
long int、signed long int
long
unsigned short int
unsigned short
unsigned int
unsigned
unsigned long int
unsigned long
2. 整型數據的二進制表示
對于整型數據,其數值是以補碼的形式存儲的。正數的補碼與其二進制原碼相同。例如整數23,其二進制形式的存儲結構如圖2-2所示。(在Visual C++ 6.0環境下,整型數據占4個字節的存儲單元,每個字節含8個位。)
圖2-2 整數23的存儲結構
若為負整數,將該數絕對值的二進制形式按位取反再加1便可得到該數的補碼。
例如,求-23的補碼的步驟如下。
第一步,求出23的二進制形式:00000000 00000000 00000000 00010111
第二步,按位取反:11111111 11111111 11111111 11101000
第三步,再加1:11111111 11111111 11111111 11101001
2.1.2 浮點型數據
1. 基本概念
在計算機的運算過程中,整型數據并不能適用于所有的應用,有時也需要存儲帶小數的數,這類數可以用浮點型數據(即浮點數)來表示。
浮點數的小數點位置是不固定的,可以浮動。C語言提供了三種不同的浮點格式。
* float:單精度浮點數。
* double:雙精度浮點數。
* long double:長雙精度浮點數。
當精度要求不嚴格時,比如某人的工資,需要保留兩位小數,float類型就是很恰當的類型。double類型提供更高的精度,對于絕大多數用戶來說已經足夠用了。long double類型支持極高精度的要求,但很少會用到。
2. 浮點型數據的二進制表示
浮點型數據與整型數據的存儲方式不同,浮點型數據是按照指數形式存儲的。例如浮點數58.625 的指數形式為58.625=5.8625×101。其中,5.8625稱為尾數,10的冪次1稱為指數。
計算機在存儲浮點數的時候,也要將十進制數轉化為二進制數來表示,轉化方法是將浮點數分為整數部分和純小數部分,再將整數部分和純小數部分分別轉化為二進制數。
浮點數的存儲結構如圖2-3所示,分為3個部分:符號位、指數位和尾數。符號位表示數值的正負;指數位用于計算階碼,代表2的冪次;尾數位為有效小數位數。尾數部分占的位數越多,浮點數的有效位越多;指數部分占的位數越多,表示數的范圍就越大。
圖2-3 浮點數的存儲結構
例如,浮點數58.625的二進制存儲格式如圖2-4所示。
圖2-4 浮點數58.625的二進制存儲格式
提示:
* 對于float類型的浮點數,指數位占8位,尾數位占23位。
* 對于double類型的浮點數,指數位占11位,尾數位占52位。
3. 浮點型數據的長度與取值范圍
單精度浮點數和雙精度浮點數由于指數和尾數的位數不同,它們的取值范圍也有所不同。浮點型數據的長度及取值范圍如表2-3所示。
表2-3 浮點型數據的長度及取值范圍
類 型
說 明
占用字節
有效位
取值范圍
float
單精度浮點型
4
6~7
-3.4×10-38~3.4×1038
double
雙精度浮點型
8
15~16
-1.7×10-308~1.7×10308
long double
長雙精度浮點型
16
18~19
-1.2×10-49~1.2×1049
【實例2-1】 C語言浮點數精度示例。
#include<stdio.h>
void main()
{
float x; /* x為單精度類型變量 */
double y;/* y為雙精度類型變量 */
x=123456789.1234;/* 賦予x值 */
y=123456789.1234;/* 賦予y值 */
printf("x=%f\n",x);/* 輸出x的值 */
printf("y=%f\n",y);/* 輸出y的值 */
}
運行結果如圖2-5所示。
圖2-5 實例2-1的運行結果
從程序的運行結果來看,x顯示的結果并不等于賦予它的值,而y顯示的結果等于賦予它的值,說明float(單精度類型)數據只能保證前7位是精確的,double(雙精度類型)數據的精度可以為15~16位。
2.1.3 字符型數據
在C語言中,一個字符型數據在計算機的內存中占據一個字節的存儲空間,但計算機并不是將字符本身存儲到存儲單元中(存儲單元只能存儲二進制編碼),而是將字符所對應的ASCII碼值轉換為二進制的形式存儲到相應的存儲單元中。如大寫字母A的ASCII碼值為65,因此,大寫字母A在存儲單元中的存儲形式實際為整數65的二進制存儲形式,如圖2-6所示。
提示:C語言是將字符常量當作整數來進行處理的。字符常量與其對應的ASCII碼值可以相互替代。字符型數據可以用字符形式輸出,也可以用整數形式輸出。字符型數據還可以作為整數參加運算。例如:
'A'+10
相當于65+10,結果為75。
通過這種關系,可以進行大小寫字母之間的轉換運算,大寫字母的ASCII碼值加上就是其對應的小寫字母的ASCII碼值,即大寫字母=小寫字母-。
【實例2-2】 將大寫字母轉換為小寫字母并顯示在屏幕上。
#include<stdio.h>
void main()
{
char ch1,ch2;
ch1='M';
ch2=ch1+;
printf("ch2=%c\n",ch2);
}
程序運行結果:
ch2=m
2.2 標識符、常量和變量
2.2.1 標識符
在編寫程序時,需要對變量、函數、宏或其他實體進行命名,這些名字稱為“標識符”。標識符只可以使用字母、數字和下劃線,而且必須以字母或下劃線開頭。標識符的長度可以是一個或多個字符,最長不允許超過個字符。
下面是正確的用戶標識符:
name、abc12、person_name
下面是不合法的用戶標識符:
2piece不能以數字開頭
score/student含有既非字母又非數字的字符
a value含有空格
int與關鍵字同名
C語言中的標識符區分大小寫,因此,sum、Sum和SUM分別代表三個不同的標識符。用戶在編程過程中要特別注意的是:標識符不能和C語言系統中的關鍵字相同(關鍵字是C語言系統規定的具有特定意義的標識符,見附錄A),也不能和用戶自定義的函數或C語言庫函數同名。
2.2.2 常量
常量是在程序運行過程中,其值不發生變化的量。在C語言中,常量分為符號常量和直接常量。
1. 符號常量
符號常量是指用一個標識符表示的常量。符號常量在使用前必須定義,定義的形式如下:
#define <標識符> <常量>
在這里,#define是C語言的預處理命令。在編輯C語言源程序時,可以直接使用已定義的符號常量,編譯時會對程序中出現的符號常量進行替換。
【實例2-3】 了解符號常量的用法。
#include<stdio.h>
#define PI 3.1416
void main()
{
int r=10;
float area;
area=PI*r*r;
printf("area=%f\n",area);
}
程序運行結果:
area=314.160000
提示:定義符號常量的目的是為了提高程序的可讀性,方便程序的調試和修改,因此在定義符號常量時,應盡可能地表達它所代表的含義,如前面定義的PI就是代表圓周率3.1416。
2. 直接常量
直接常量是指直接用數值表示的量,如24、3.14、‘T’、“string”等。直接常量分為整型常量、實型常量、字符常量、字符串常量、枚舉常量等不同類型的常量。
1) 整型常量
可以采用十進制、八進制、十六進制來表示一個整型常量。
* 十進制:包含0~9中的數字,但是一定不能以0開頭,如15、-255。
* 八進制:只包含0~7中的數字,必須以0開頭,如017(十進制的15)、0377(十進制的255)。
* 十六進制:包含0~9中的數字和a~f中的字母,以0x或0X開頭,如0xf(十進制的15)、0xff(十進制的-1)、0x7f(十進制的127)。
表2-4為整型常量在不同進制下的表示方法。
表2-4 整型常量的表示方法
整型常量
進 制
對應的十進制數值
17
十進制
17
017
八進制
15
0x17
十六進制
23
17L或17l
十進制
17
17LU或17lu
十進制
17
提示:可以在十進制整型常量后面添加“l”或“u”(“l”和“u”不區分大小寫)來修飾整型常量。若添加“l”(或“L”)則表示該整型常量為“長整型”,如“17l”;若添加“u”(或“U”)則表示該整型常量為“無符號型”,如“17u”;若添加“lu”(或“LU”)則表示該整型常量為“無符號長整型”,如“17lu”。
2) 實型常量
實型常量常用浮點計數法或科學計數法兩種方法表示,如231.46、7.36E-7。
科學計數法要求字母e(或E)的兩端必須都有數字,而且右側必須為整數。如下列科學計數法均是錯誤的:e3、2.1e3.2、e。
3) 字符常量
字符常量是由一對單引號括起來的單個字符,如‘A’、‘9’、‘$’等均為字符常量。在這里,單引號只起定界作用,不代表字符。在C語言中,一個字符占用一個字節的存儲空間,字符在ASCII表中按照其對應的ASCII碼值依次排列。ASCII表詳見附錄B。
除了能直接表示和在屏幕上顯示的字符外,還有一些字符是不能顯示、用來表示不可打印的控制字符和特定功能的字符。如實例2-1中的“printf(“x=%f \n”,x);”,其中的“\n”就是一個這樣的控制字符。這種字符稱為“轉義字符”。轉義字符用反斜杠( \ )后面跟一個字符或者一個八進制或十六進制數表示。表2-5所示為C語言中常用的轉義字符。
表2-5 轉義字符
轉義字符
意 義
ASCII碼值
\n
換行
10
\t
水平制表符
9
\b
退1格
8
\r
回到本行的開始
13
\f
換頁
12
\\
反斜杠
92
\'
單引號字符
39續表
轉義字符
意 義
ASCII碼值
\"
雙引號字符
34
\0
空字符
0
\ddd
1~3位八進制數所代表的字符
\xhh
1~2位十六進制數所代表的字符
提示:
* 字符碼ddd表示1~3位八進制數字,可以不用前綴0。如‘\101’代表ASCII值為八進制數101的字符,八進制數101相當于十進制數65,ASCII值為65的字符是大寫字母‘A’。
* 字符碼hh表示1~2位十六進制數字,不能忽略前綴x。如‘\x47’代表ASCII值為十六進制數47的字符,十六進制數47相當于十進制數71,ASCII值為71的字符是大寫字母‘G’。
* 單引號和反斜杠必須用轉義字符表示。
4) 字符串常量
字符串常量是由一對雙引號括起來的字符序列。如“China”、“a”、“123”等都是字符串常量。雙引號之間沒有任何字符的字符串常量稱為空字符串。
在C語言中,系統會自動在字符串常量的尾端加入一個字符‘\0’作為字符串的結束標記,因此,長度為n個字符的字符串常量,在內存中占用n+1個字節的存儲空間。
例如,字符串常量china有5個字符,則其存儲空間為6個字節,其存儲形式如圖2-7所示。
圖2-7 字符串常量“china”的存儲形式
在C語言中,處理字符串問題時經常要用到數組或指針,這部分內容將在后續章節中講述。
注意:不要混淆字符常量與字符串常量。字符常量是由一對單引號括起來的單個字符,占1個字節的存儲空間,如‘s’、‘\101’等;而字符串常量是由一對雙引號括起來的字符序列,如“china”,占6個字節的存儲空間,其中最后一個字節用來存放字符‘\0’。
2.2.3 變量
1. 變量的定義
變量是指在程序運行過程中其值可以改變的量。在程序定義變量時,編譯系統就會給它分配相應的存儲單元,用來存儲數據,變量的名稱就是該存儲單元的符號地址。
在使用變量之前必須對其進行聲明,為了聲明變量,首先要指定變量的類型,然后說明變量的名字。聲明變量的格式如下:
類型名 變量名表;
提示:
* 類型名:必須是有效的C語言數據類型,如int、float、double、char等。
* 變量名表:可以是相同類型的若干個變量名,變量名之間用逗號隔開。
例如:
int number; /*number為整型變量*/
float score, avg ; /*score、avg為單精度實型變量*/
通常,變量定義的語句放在函數的開頭,也可以放在函數的外部或復合語句的開頭。
2. 變量的初始化
在程序中為變量賦值的時候,編譯系統就會根據變量名稱找到其對應的存儲單元的地址,將所賦的值存放進去。
C語言允許在定義變量的同時對變量進行初始化。一般形式如下:
<類型名> <變量名>=<表達式>, … ;
例如:
int a=3 ;/*定義a為整型變量,初值為3*/
float pi=3.1416,score;/*定義pi、score為單精度實型變量,pi的初值為3.1416*/
char ch='t' ;/*定義ch為字符型變量,初值為't'*/
也可以對定義的變量的一部分賦初值。例如:
int length, width=10, area ;
表示定義length、width和area為整型變量,并且對width賦初值10。
若要對幾個變量賦同樣的值,每個變量應分別賦初值,如寫成以下形式:
int a=10, b=10, c=10;
而絕不能寫成如下形式:
int a=b=c=10;
2.3 運算符與表達式
C語言提供了豐富的運算符,除流程控制語句與輸入/輸出操作之外的絕大多數基本操作都是由運算符來處理的。
2.3.1 概述
1. 運算符的分類
1) 按運算符操作對象的數量分類
運算符能連接運算對象的個數稱為運算符的目。C語言中運算符的目有如下三種。
* 單目運算符:只能連接一個運算對象,如++、--、&等。
* 雙目運算符:可以連接兩個運算對象,如+、-等。C語言中的運算符大多數屬于雙目運算符。
* 三目運算符:可以連接三個運算對象。C語言中只有一個三目運算符,即條件運算符。
2) 按運算符的性質分類
C語言的運算符極其豐富,根據運算符的性質分類,可分為算術運算符、關系運算符、邏輯運算符、賦值運算符、條件運算符、逗號運算符、求字節數運算符和位運算符等。
2. 運算符的優先級和結合方向
優先級是指在使用不同的運算對象進行計算時的先后次序。比如在算術運算符中,乘、除運算符的優先級要高于加、減運算符的優先級。C運算符的優先級共分為15級,1級最高,15級最低。當一個表達式中出現不同類型的運算符時,首先按照它們的優先級順序進行運算,即先對優先級高的運算符進行計算,再對優先級低的運算符進行計算。當兩類運算符的優先級相同時,則要按照運算符的結合性確定運算順序。圓括號的優先級高于任何運算符。
C語言中運算符的優先級關系為:單目運算>算術運算>關系運算>邏輯運算>條件運算>賦值運算>逗號運算。
結合方向是指當一個運算對象連接兩個同一優先級的運算符時,如果先結合左邊的運算符,稱為“自左向右”的結合方向;如果先結合右邊的運算符,稱為“自右向左”的結合方向。
各類運算符的優先級和結合性詳見附錄D。
3. 表達式
由C運算符和運算對象構成的式子稱為“表達式”。運算對象可以是常量、變量或函數。單個的常量、變量和函數有時也可以看作表達式。
C語言表達式中的所有成分都必須以線性形式書寫,沒有分式,沒有上下標。如數學表達式
轉換成C表達式,應寫成
(sin(x)+b)/(a*b)+(a+b)/(a-b)
2.3.2 算術運算符及算術表達式
1. 算術運算符
(1)??+:加法運算符,或正值運算符,如3+5、+3。
(2)??-:減法運算符,或負值運算符,如5-2、-5。
(3)??*:乘法運算符,如3*5。
(4)??/:除法運算符,如5/3。
(5)??%:模運算符,或稱求余運算符,用于計算兩個整數相除后得到的余數,如5%2的值為1。
算術運算符的優先級與數學上的規定相同,先乘除后加減,同一級別的一般情況下按自左向右的順序進行。
注意:
* 對于除法運算符“/”,如果兩個運算對象都為整數,其意義為“整除”,相除的結果為整數,如5/3的結果為整數1,舍去小數部分;如果有一個整數為負數,C語言編譯系統將采取“向零取整”的方法,即-5/3=-1,取整后向零靠攏;如果兩個運算對象中至少有一個為浮點數,則相除的結果為double型浮點數,如3.0/2的結果為1.5。
* 對于求余運算符“%”,其只能應用于整型數據,且計算結果的符號取決于左操作數的正負號。例如:
(-10)%3=-1
10%(-3)=1
2. 算術表達式
用算術運算符和括號將運算對象連接起來的符合C語法規則的式子,稱為“C算術表達式”。運算對象包括常量、變量、函數等。下面是一個合法的C算術表達式:
a*b/c-1.5+'a'-sin(x)
算術表達式的值就是它的計算結果,算術表達式的類型就是它的計算結果的類型。
2.3.3 賦值運算符及賦值表達式
1. 賦值運算符及賦值表達式
在C語言中,“=”稱為賦值運算符,它的作用是將一個表達式的值賦給一個變量。由賦值運算符將一個變量和一個表達式連接起來的式子稱為賦值表達式。一般形式如下:
<變量名>=<表達式>
賦值運算符的結合性是“自右向左”,賦值運算符的左邊必須是一個代表某一存儲單元的變量名(或是具備變量性質的、代表某存儲單元的表達式),賦值運算符的右邊可以是任意合法的C表達式。
賦值運算的功能是先求出右邊表達式的值,然后再把此值賦給運算符左邊的變量,也就是把數據放入以該變量名標識的存儲單元中。例如:
a=10; /* 把整型常量10賦給變量a */
變量、變量值與存儲單元的關系如圖2-8所示。
在程序中,可以多次給一個變量賦值,每賦一次值,相應的存儲單元中的數據就被更新一次,存儲單元總是存放最后一次所賦的數據。
說明:
* 賦值運算符的優先級只高于逗號運算符,比其他任何運算符的優先級都低。如對于下列表達式:
s=13+2*/6+36/9
* 先計算賦值運算符右邊表達式的值,再把計算的結果賦給變量s。
* 賦值運算符右邊的表達式可以是一個賦值表達式。例如:
a=b=5;
是合法的。根據賦值運算符“自右向左”的結合性,它等價于a=(b=5),最終的結果是a和b都等于5。
2. 復合賦值運算符
在賦值運算符“=”之前加上其他的運算符,可以構成復合的賦值運算符。C語言共有10種復合運算符:+=、-=、*=、/=、%=為復合算術運算符,>>=、<<=、&=、^=、|=為復合位運算符。
復合運算符是兩種運算符的結合,它包含兩種運算:賦值運算、和賦值運算符復合的其他運算符的運算。
例如:
x+=10;/*等價于 x=x+10*/
x%=3;/*等價于 x=x%3*/
如果復合賦值運算符的右邊是一個表達式,則相當于它含有一對括號。例如:
x*=y/10-25;/*等價于 x=x*(y/10-25);*/
可以借助以下步驟來理解其運算規則。
(1)將“=”右側的表達式用括號括起來:(y/10-25)。
(2)將“=”左側的內容“x*”移到右側:x*(y/10-25)。
(3)最后補上“=”左側的變量名:x=x*(y/10-25)。
2.3.4 自增、自減運算符
C語言提供了自增和自減運算符。
自增運算符++:功能是將變量的值加1。
自減運算符--:功能是將變量的值減1。
“++”和“--”運算符都是右結合方向的單目運算符,它們既可以作為變量的前綴,又可以作為變量的后綴。
例如:對于變量x,++x、--x表示“++”、“--”作為變量x的前綴,x++、x--表示“++”、“--”作為變量x的后綴。
粗略地看,++x和x++都是使x的值加1,但是++x和x++的區別在于:++x是先將x的值加1,再使用變量x;而x++則是先使用變量x,然后再將x的值加1。例如下面的語句:
x=5;
y=++x;
執行完語句后,x的值為6,y的值也為6。
這是因為語句“y=++x;”等價于“x=x+1; y=x;”。
又如下面的語句:
x=5;
y=x++;
執行完語句后,x的值為6,y的值為5。
因為語句“y=x++;”等價于“y=x; x=x+1;”。
注意:
* “++”和“--”運算符只能應用于變量,不能應用于常量或表達式。例如,12++、(i*j) -- 都是不合法的。
* “++”、“--”與單目運算符具有同一優先級,結合方向都是“自右向左”。因此,對于“-i++”要理解為“-(i++)”,而不能理解為“(-i)++”,這是因為(-i)是表達式,不能做“++”和“--”的操作對象。
2.3.5 關系運算符及關系表達式
1. 關系運算符
關系運算符用于關系運算。關系運算是對兩個操作對象進行比較的運算,通過比較來判斷兩個操作數對象之間是否存在一定的關系。
C語言中的關系運算符共有6種,都是雙目運算符,結合方向都是“自左向右”,如表2-6所示。
表2-6 關系運算符及其含義和優先級
關系運算符
含 義
優先級
>=
大于等于
高
>
大于
<=
小于等于
<
小于
= =
等于
低
!=
不等于
2. 關系表達式
用關系運算符將兩個表達式連接起來的式子,稱為“關系表達式”。
關系表達式的值是一個邏輯值,即“真”和“假”。關系表達式所表達的關系如果成立,其值為“真”;如果不成立,其值為“假”。
在C語言中沒有專門的邏輯型數據,而是用0表示“假”,非0的值表示“真”,通常用1來表示“真”。
注意:
* 關系運算符連接的表達式可以是C語言中任意的合法的表達式。
* 關系運算符的操作對象可以是字符型數據。如表達式‘a’>‘m’的結果為0,因為字符在存儲單元中是按照ASCII碼存儲的(‘a’的ASCII碼為97,‘m’的ASCII碼為109),因而字符型數據的關系運算比較的其實是它們的ASCII碼。
* 若變量x、y都是實型數據,應當避免使用關系運算符“x==y”這樣的表達式,因為通常存放在存儲單元中的實型數據都是有誤差的,因此不可能精確相等,這樣會導致關系表達式的值總為0。
2.3.6 邏輯運算符及邏輯表達式
1. 邏輯運算符
邏輯運算符用于邏輯運算,也就是“真”“假”值的運算。C語言提供的邏輯運算符及其含義和優先級如表2-7所示。
表2-7 邏輯運算符及其含義和優先級
邏輯運算符
含 義
優先級
!
邏輯非
&&
邏輯與
||
邏輯或
邏輯運算符中的“!”為單目運算符,其余都是雙目運算符。
2. 邏輯表達式
用邏輯運算符將表達式連接起來的式子,稱為“邏輯表達式”。邏輯表達式中的操作對象可以是C語言中任意合法的表達式。
邏輯運算符主要用于進一步明確關系表達式的關系,邏輯表達式的結果同關系表達式的結果一樣,只有“真”和“假”。表2-8所示為邏輯運算規則。
表2-8 邏輯運算規則
A
B
A&&B
A||B
!A
真
真
真
真
假
真
假
假
真
假
假
真
假
真
真
假
假
假
假
真
表2-8中的A、B均可以是其他關系表達式。
對于由關系表達式和邏輯表達式組成的復雜表達式,為了提高運行速度,編譯系統會對下列特殊的情況作不同的處理。
1)(表達式1) || (表達式2)
根據語法規則,只要(表達式1)的值為真,不論(表達式2)的值為何值,最終表達式“(表達式1) || (表達式2)”的結果都為真,編譯器不會對(表達式2)進行運算,但會檢查其語法是否有錯誤。
例如有如下語句:
…
int x=10,y=20,z;
z=(x<y) || (--y);
printf("z=%d \n",z);
…
因為表達式(x<y)的結果為真,因而不論后面的表達式為何值,表達式(x<y)||(--y)的結果都為真,此時系統不會計算表達式(--y),y的值也不會減少,程序運行后的結果為z=1、y=20。
2)??(表達式1) && (表達式2)
根據語法規則,只要(表達式1)的值為假,不論(表達式2)的值為何值,最終表達式“(表達式1) && (表達式2)”的結果都為假,編譯器不會對(表達式2)進行運算,但會檢查其語法是否有錯誤。
例如有如下語句:
…
int x=10,y=20,z;
z=(x>y) && (--y);
printf("z=%d \n",z);
…
因為表達式(x>y)的結果為假,因而不論后面的表達式為何值,表達式(x>y)&&(--y)的結果都為假,此時系統不會計算表達式(--y),y的值也不會減少,程序運行后的結果為z=0、y=20。
2.3.7 位運算符及位運算
位運算是指二進制位的運算,主要針對整型和字符型數據而言。位運算符的屬性如表2-9所示。
表2-9 位運算符的屬性
位運算符
含 義
類 型
結合性
優先級
~
按位取反
單目
自右向左
<<
位左移
雙目
自左向右
>>
位右移
雙目
自左向右
&
位與
雙目
自左向右
^
位異或
雙目
自左向右
|
位或
雙目
自左向右
位運算的結果只有0或1,位運算的規則如表2-10所示。
表2-10 位運算的規則
A
B
A|B
A^B
A&B
~A
~B
1
1
1
0
1
0
0
1
0
1
1
0
0
1
0
0
0
0
0
1
1
0
1
1
1
0
1
0
關于位運算的詳細內容,將在第12章中介紹。
2.3.8 條件運算符及條件表達式
條件運算符是C語言中唯一的三目運算符。由條件運算符和運算對象構成的表達式稱為條件表達式,條件表達式由“?”和“:”組成,其結合方向是“自右向左”,一般形式如下:
表達式1? 表達式2:表達式3;
條件表達式的運算過程為:先計算表達式1的值,如果表達式1的值為真(非0),則表達式2被求值,此時表達式2的值就是整個條件表達式的值;如果表達式1的值為假(0),則表達式3被求值,此時表達式3的值就是整個條件表達式的值。
【實例2-4】 條件表達式示例。
#include<stdio.h>
void main()
{
int a=12,b=24,c;
c=a>b ? a+b : a-b;
printf("c=%d\n",c);
}
程序運行結果:
c=-12
條件表達式是可以嵌套使用的,當多個條件表達式嵌套使用時,每個后續的“:”總是與前面最近且沒有配對的“?”相聯系。例如:
a>b ? a: c>d ? c:d
相當于:
a>b ? a: (c>d ? c:d)
如果a=6、b=8、c=12、d=24,則條件表達式的值為24。
2.3.9 逗號運算符及逗號表達式
逗號表達式是由逗號“,”將兩個表達式連接起來組成的一個表達式。逗號表達式的一般形式如下:
表達式1,表達式2,…,表達式n;
逗號表達式的求解過程為:先計算表達式1,再計算表達式2……直至計算表達式n,整個表達式的結果就是表達式n的值。
逗號表達式的運算優先級是最低的,結合方向是“自左向右”。
【實例2-5】 逗號表達式示例。
#include<stdio.h>
void main()
{
int x,y;
y=(x=3*5,x*3,x+12);
printf("y=%d\n",y);
}
程序運行結果:
y=27
2.3.10 數據類型的轉換
在C語言程序中,若出現包括不同類型的常量和變量的一個表達式,那運算結果會是什么呢?C語言規定:不同類型的數據在參加運算時,要先轉換成相同類型的數據,然后再進行運算。運算結果的類型就是轉換后的類型。C語言的數據類型轉換分為系統自動進行的類型轉換和強制類型轉換。
1. 系統自動進行的類型轉換
自動類型轉換的規則:取值范圍較小的類型向取值范圍較大的類型轉換,如圖2-9所示。
注意:
* 圖中指向左側的箭頭表示必須進行的轉換。char、short型數據必須要轉換為int型,float型數據必須要轉換為double型。
* 縱向箭頭表示當運算對象為不同數據類型時轉換的方向,由低向高轉換。例如,int型數據與double型數據進行運算時,要先將int型轉換為double型,然后兩個double型數據進行運算,結果為double型。而不是int型先轉換為unsigned型,再轉換為long型,最后轉換為double型。
【實例2-6】 數據類型轉換分析。計算表達式120-‘m’+24.67的值。
(1) 計算120-‘m’:先將字符‘m’轉換為整數109,再計算120-109,計算結果為11。
(2) 計算11+24.67:由于表達式中有實型數據,因而要先將11和24.67都轉換為double型,再進行運算,結果為35.670000。
2. 強制類型轉換
自動類型轉換是編譯系統自動進行的,不需要用戶干預。C語言允許用戶根據自己的需要將運算對象的數據類型轉換為所需的數據類型。強制轉換的形式如下:
(類型名) (表達式);
功能:強行將表達式的類型轉換為所要求的類型。例如:
(int)4.2; /*將實型數據4.2強行轉換為整型,結果為4*/
(float) (x+y);/*將x+y的結果轉換為float型*/
注意:
強制類型轉換之后,原來的變量或表達式的值并未發生改變。例如:
float a=3.14;
則強制轉換表達式(int)a的數據類型為int型,結果為3;而變量a的數據類型仍然是float型,值仍為3.14。
2.4 小型實訓案例
本案例主要應用本章所學的算術運算符以及算術表達式的知識,對一個三位的整數進行分解。
1. 實訓目的
掌握算術運算符及算術表達式的應用。
2. 實訓內容
假定n是一個三位的正整數,將其各位上的數字分解出來,再計算各位數字之和。例如整數n為123,則各位數字之和為1+2+3=6。
3. 實訓步驟
1) 分析
將n的百位、十位、個位上的數字依次分解出來,再計算它們的和,具體步驟如下。
(1) 計算n的個位數。利用算術運算符“%”,計算n與10的余數,所得的計算結果就是n的個位數:
個位數=n%10;
(2) 計算n的十位數。利用算術運算符“/”關于整數相除的特點,即“兩個整數相除的結果仍然為整數”,將n除以10就可以除掉n的個位數,再利用求模運算符(%)與10求余數,所得的計算結果就是n的十位上的數字:
十位數=n/10%10;
(3) 計算n的百位數。將n除以100,得到的結果就是n的百位數:
百位數=n/100;
(4) 求和。
總和=個位數+十位數+百位數;
2) 編程實現
#include <stdio.h>
void main()
{
int n,g,s,b,sum;/*n表示要分解的整數, g表示個位的數字,s表示十位
?的數字,b表示百位的數字,sum表示各位數字之和 */
n=123;
g=n%10; /* 分解出個位上的數字 */
s=n/10%10; /* 分解出十位上的數字 */
b=n/100; /* 分解出百位上的數字 */
sum=g+s+b;
printf("%d\n",sum);
}
本 章 小 結
本章主要介紹了C語言的數據類型和各類運算符及表達式,這是編寫C語言程序的基礎。
C語言的基本數據類型包括整型、實型和字符型,整型又分為基本整型、短整型、長整型,實型又分為單精度實型、雙精度實型。
C語言的運算符共分為算術運算符、賦值運算符、邏輯運算符、關系運算符、逗號運算符、條件運算符、求字節數運算符及位運算符等,每一種運算符都有其結合方向和運算優先級。
C語言不同類型的表達式是通過不同的運算符構成的,一個常量、變量都可以看作一個表達式。混合表達式在運算時,要按運算符的優先級次序執行,當一個運算符兩側的運算對象的數據類型不同時,系統會遵循“先轉換,后運算”的原則,將數據自動轉換為同一類型后再進行運算。
習 題
一、選擇題
1.若變量a是整型數據,并執行了語句“a=‘A’+1.6;”,則正確的敘述是( )。
A.??a的值為字符CB.??a的值是浮點型
C. 不允許字符型和浮點型相加D.??a的值為字符‘A’的ASCII碼值加1
2.下列變量定義中合法的是( )。
A.??int _a=1-0.1e-1;B.??double b=1+5e2.5;
C.??long d0=0xfdaL;D.??float 2_and=1-e-3
3.已知各變量的類型定義如下:
int k,a,b;
long w=5;
double x=1.42;
則以下不符合C語言語法的表達式是( )。
A.??x%(-3)B.??w+=2
C.??k=(a=2,b=3,a+b)D.??a+=a-=(b=4)*(a=3)
4.字符型常量在內存中存放的是( )。
A.??ASCII碼B.?? BDC碼C.??內部碼D.??十進制碼
5.下面錯誤的字符串常量是( )。
A.??‘abc’B.??“12’12”C.??“0”D.??“ ”
6.若有“int n=7, sum=7;”,則計算表達式sum=n++,sum++,++n后,sum的值是( )。
A.??7B.??8C.??9D.?10
7.設“int x=1,y=1;”,表達式(!x||y--)的值是( )。
A.??0B.??1C.??2D.??-1
8.以下選項中,與k=n++完全等價的表達式是( )。
A.??k=n,n=n+1B.??n=n+1,k=n
C.??k=++nD.??k+=n+1
9.能正確表達數學關系“10≤a<100”的表達式是( )。
A.??10≤a<100B.??(10<=a)&(a<100)
C.??(10<=a )||(a<100)D.?(10<=a)&&(a<100)
10.執行下列C語言程序段后,變量b的值是( )。
double a=1,b;
b=a+5/2;
A.??1B.??3C.??3.0D.??3.5
二、填空題
下列程序的功能是:計算圓的面積,已知半徑r=10。
#include<stdio.h>
void main()
{
① r=10; /*聲明變量r的數據類型 */
② PI=3.1415926,area;/*聲明語句 */
area=r*r*PI; /* 利用數學公式求圓面積 */
printf("%f\n", ③ );/* 輸出計算結果 */
}
三、改錯題
修改下列程序,使得在屏幕上輸出 1+1/2+2/3+3/4 的計算結果。下列程序在每一行“/***********found************/”的下方有一處錯誤,請予以改正,程序的其他部分不得改動。
#include<stdio.h>
void main()
{
/***********found************/
int sum;
sum=1.0+1.0/2+2.0/3+3.0/4;
/***********found************/
printf("%d",sum);
}
四、編程題
1. 編寫程序,計算表達式1-1/2+1/3-1/4+1/5 的計算結果。
2. 編寫程序,將一個大寫字母轉換為小寫字母。