3012C语言_数据
生活随笔
收集整理的這篇文章主要介紹了
3012C语言_数据
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
第二章 數(shù)據(jù)
- 2.1 數(shù)據(jù)類型
-
- 2.1.1 數(shù)據(jù)類型決定
- 1. 數(shù)據(jù)占內(nèi)存字節(jié)數(shù)
- 2. 數(shù)據(jù)取值范圍
- 3. 其上可進(jìn)行的操作
-
- 2.2基本數(shù)據(jù)類型
- 2.2.1分類 基本類型
-
- 類型 符號(hào) 關(guān)鍵字 字節(jié) 16位/32位/64位 位數(shù) 32位 數(shù)的表示范圍 32位
- 整型 ?
- 有
- [signed] int 2/4/4 4*8=32 -2^31 ~ 2^31-1
- [signed] short [int] 2/2/2 2*8=16 -2^15 ~ 2^15-1
- [signed] long [int] 4/4/4 32 -2^31 ~ 2^31-1
- [signed] long long [int] 8/8/8 64 -2^63 ~ 2^63-1
- 無(wú)
- unsigned short [int] 2/2/2 16 0 ~ 2^16-1
- unsigned int 2/4/4 32 0 ~ 2^32-1
- unsigned long [int] 4/4/8 32 0 ~ 2^32-1
- unsigned long long [int] 8/8/8 64 0 ~ 2^64-1
- 有
- 實(shí)型
- 有 float 4/4/4 32 0&土1.2e土38
- 有 double/longdouble有8有16 8/8/8 64 0&土1.2e土308
- 字符(變量)
- 有 [signed] char 1/1/1 8 -128~127 -2^7 ~ 2^7-1
- 無(wú) unsigned char 1/1/1 8 0~255 0~ 2^8-1
- 字符(常量) ? ? /4/ 字節(jié)
- 指針類型
- 指針 無(wú) char*/int*(指針變量) 2/4/8 32
- 整型 ?
- (1)指針大小
- 指針的大小是由內(nèi)存尋址空間決定的,即地址總線決定。
- char*(即指針變量): 4個(gè)字節(jié)(32位的尋址空間是2^32,即32個(gè)bit,也就是4個(gè)字節(jié)。同理64位編譯器)
- 一般32位機(jī)尋址空間4G,所以指針占4字節(jié);
- 一般16位的單片機(jī)尋址空間是64k,所以指針占2字節(jié)。
- (2)字符型符號(hào)
- C標(biāo)準(zhǔn)規(guī)定為 Implementation Defined(由實(shí)作環(huán)境決定)
- ?arm-linux-gcc規(guī)定 char 為 unsigned char
- ?vc 編譯器、x86上的 gcc 規(guī)定 char 為 signed char
- 缺省情況下,編譯器默認(rèn)數(shù)據(jù)為signed類型,但是char類型除外。
- 為了代碼移植,一定不要用 char,用 signed char
- (3)鐵則
- int,long int,short int的寬度都可能隨編譯器而異。
- 但有幾條鐵定的原則(ANSI/ISO制訂的):
- ?sizeof(shortint)<=sizeof(int)
- ?sizeof(int)<=sizeof(longint)
- ?shortint至少應(yīng)為16位(2字節(jié))
- ?longint至少應(yīng)為32位。
- 類型 符號(hào) 關(guān)鍵字 字節(jié) 16位/32位/64位 位數(shù) 32位 數(shù)的表示范圍 32位
-
- 2.2.2? 常量
-
- 在程序運(yùn)行中,其值不能被改變的量稱為常量。
- 2.2.2.1? 分類
- 符號(hào)常量:
- 用標(biāo)識(shí)符代表常量
- 定義格式: #define?? 符號(hào)常量?? 常量
- 一般用大寫(xiě)字母
- 是宏定義預(yù)處理命令,不是C語(yǔ)句
- 直接常量:
- 整型常量
- 實(shí)型常量
- 字符常量
- 字符串常量
- 符號(hào)常量
- 符號(hào)常量:
- 2.2.2.2? 整型常量
- (1)整型常量有3種形式:十進(jìn)制整型常量、八進(jìn)制整型常量和十六進(jìn)制整型常量。
- (注意:c語(yǔ)言中沒(méi)有直接表示二進(jìn)制的整型常量,在c語(yǔ)言源程序中不會(huì)出現(xiàn)二進(jìn)制。)
- 整型常量后可以用u或U明確說(shuō)明為無(wú)符號(hào)整型;用l或L明確說(shuō)明為長(zhǎng)整型數(shù)
- ?? 二進(jìn)制:
- 所有數(shù)字由0,1構(gòu)成,逢二進(jìn)一,二進(jìn)制數(shù)中不會(huì)出現(xiàn)2.。
- 例:110101
- ? ?八進(jìn)制:
- 以數(shù)字0(注意不是以字母O,o)開(kāi)頭,所有數(shù)字由0~7構(gòu)成,逢八進(jìn)一,八進(jìn)制數(shù)中不會(huì)出現(xiàn)8。
- 八進(jìn)制整型常量:051 ,-026 ,0773 等
- ?? 十進(jìn)制:
- 所有數(shù)字由0~9構(gòu)成,逢十進(jìn)一,十進(jìn)制數(shù)中不會(huì)出現(xiàn)10。
- 十進(jìn)制整型常量:123 , 0 ,-24 , 85L(長(zhǎng)整型常量)等
- ?? 十六進(jìn)制:以0x或者0X(數(shù)字0加字母x)開(kāi)頭,
- 所有數(shù)字由0~9,A~F(或者a~f)構(gòu)成,逢十六進(jìn)一
- (其中A、B、C、D、E、F分別代表10、11、12、13、14、15)
- 十六進(jìn)制整型常量:0x55 , 0x1101 , 0x , 0x5AC0 , -0xFF。
- ?? 二進(jìn)制:
- 2.2.2.3? 實(shí)型常量
- 實(shí)型常量有兩種表示形式:小數(shù)形式和指數(shù)形式。
- 編碼形式存儲(chǔ)。
- 小數(shù)形式:5.4?? 0.074?????-23.0
- 指數(shù)形式:5.4e04.3e-3 -3.3e4 -3.3E4??? e可大小寫(xiě)
- (1)小數(shù)部分為0的實(shí)型常量,可以寫(xiě)為453.0 或453。
- (2)用小數(shù)表示時(shí),小數(shù)點(diǎn)的兩邊必須有數(shù),不能寫(xiě)成“ .453“和“453.“,而應(yīng)該寫(xiě)成“0.453“和“453.0“。
- (3)用指數(shù)寫(xiě)法時(shí),e前必須有數(shù)字,e后面的指數(shù)必須為整數(shù)
- (注意:整數(shù)階碼可以是正數(shù),負(fù)數(shù),也可以是八進(jìn)制數(shù)、十六進(jìn)制數(shù),但必須為整數(shù))。
- 2.2.2.4? 字符常量
- 字符常量的標(biāo)志是一對(duì)單引號(hào)‘ ’,c語(yǔ)言中的字符常量有兩類:
- (1)????由一對(duì)單引號(hào)括起來(lái)的一個(gè)字符,如‘a(chǎn) ’, ‘r’,‘#’。
- 注意: ′a′ 和 ′A′ 是兩個(gè)不同的字符常量。
- '1' 是字符占一個(gè)字節(jié),"1"是字符串占兩個(gè)字節(jié)(含有一個(gè)結(jié)束符號(hào))。
- '0' 的ASCII數(shù)值表示為48,'a' 的ASCII數(shù)值是97,'A'的ASCII數(shù)值是65。
- 一般考試表示單個(gè)字符錯(cuò)誤的形式:'65'??? "1"
- 字符是可以進(jìn)行算術(shù)運(yùn)算的,記住:'0'-0=48
- 大寫(xiě)字母和小寫(xiě)字母轉(zhuǎn)換的方法:'A'+32='a'??相互之間相差32。
- (2)由一對(duì)單引號(hào)括起來(lái),以反斜杠\開(kāi)頭,后跟若干數(shù)字或者字母,比如‘\n’,其中“\“是轉(zhuǎn)義的意思,后面跟不同的字符表示不同的意思,這類字符常量叫轉(zhuǎn)義字符。具體如圖所示 。
- ‘A’? =? ‘\101’?=? ‘\x41’? =? 65
- 在程序中 int a = 0x6d,是把一個(gè)十六進(jìn)制的數(shù)給變量a 注意這里的0x必須存在。
- 在程序中 int a = 06d, 是一個(gè)八進(jìn)制的形式。
- 在轉(zhuǎn)義字符中
- ’\x6d’ 才是合法的,0不能寫(xiě),并且x是小寫(xiě)。
- ‘\141’ 是合法的, 0是不能寫(xiě)的。
- ‘\108’是非法的,因?yàn)椴豢梢猿霈F(xiàn)8。
- 2.2.2.5? 字符串常量
- C語(yǔ)言中,以雙引號(hào)括起來(lái)的,由若干個(gè)字符組成的序列即為字符串常量。
- 例:“nihao”?? “happy”等等
- 字符串的概念
- 簡(jiǎn)單而言,字符串是若干有效字符的序列,可包含轉(zhuǎn)義字符、ASCⅡ碼表中的字符;
- 形式為: 用雙引號(hào)括起來(lái)的字符序列;
- 例:"I am a? student."? , "Hello "
- "a[5]="; "%f\n"。
- 字符串的結(jié)束標(biāo)志:‘\0’。
- C語(yǔ)言中,以雙引號(hào)括起來(lái)的,由若干個(gè)字符組成的序列即為字符串常量。
- 2.2.2.6? 符號(hào)常量
- 符號(hào)常量是由宏定義“#define“定義的常量,在C程序中可用標(biāo)識(shí)符代表一個(gè)常量。
- 例:計(jì)算圓的面積的c程序。
- #include<stdio.h>
- #define? PI??3.14159
- main()
- {
- float?r,s;
- r=12.5;
- s=PI*r*r;
- printf("s= %f",s);
- }
- 例:計(jì)算圓的面積的c程序。
- 說(shuō)明:
- #define 是宏定義,此程序中所有出現(xiàn)PI的地方都代表3.14159,同時(shí)PI稱為符號(hào)常量。習(xí)慣上我們用大寫(xiě)字母來(lái)表示符號(hào)常量,小寫(xiě)字母表示變量,這樣比較容易區(qū)別。
- define? f(x)(x*x) 和 define f(x) x*x 之間的差別。一定要好好的注意這寫(xiě)容易錯(cuò)的地方,替換的時(shí)候有括號(hào)和沒(méi)有括號(hào)是很大的區(qū)別。
- 符號(hào)常量是由宏定義“#define“定義的常量,在C程序中可用標(biāo)識(shí)符代表一個(gè)常量。
-
- 2.2.3? 變量
- 定義
- 變量就是其值可以改變的量。變量要有變量名,在內(nèi)存中占據(jù)一定的存儲(chǔ)單元,存儲(chǔ)單元里存放的是該變量的值。不同類型的變量其存儲(chǔ)單元的大小不同,變量在使用前必須定義。
- 2.2.3.1? 整型變量
- 整型變量分為4種:
- 基本型(int)、
- 短整型(short int 或short)、
- 長(zhǎng)整型(long int 或 long)
- 無(wú)符號(hào)型(unsigned int ,unsigned short,unsigned long)。
- 不同的編譯系統(tǒng)對(duì)上述四種整型數(shù)據(jù)所占用的位數(shù)和數(shù)值范圍有不同的規(guī)定。
- 說(shuō)明:
- 單詞signed來(lái)說(shuō)明“有符號(hào)”(即有正負(fù)數(shù)之分),不寫(xiě)signed也隱含說(shuō)明為有符號(hào),unsigned用來(lái)說(shuō)明“無(wú)符號(hào)”(只表示正數(shù))。
- 整型變量分為4種:
- 2.2.3.2? 實(shí)型變量
- C語(yǔ)言中,實(shí)型變量分為單精度類型( float )和雙精度類型( double )兩種。如:
- float? a , b ;
- double? m ;
- 單精度實(shí)數(shù)提供7位有效數(shù)字,雙精度實(shí)數(shù)提供15~16位有效數(shù)字。
- 實(shí)型常量不分float型和double型,一個(gè)實(shí)型常量可以賦給一個(gè)float 型或double型變量,但變量根據(jù)其類型截取實(shí)型常量中相應(yīng)的有效數(shù)字。
- 注意:實(shí)型變量只能存放實(shí)型值,不能用整型變量存放實(shí)型值,也不能用實(shí)型變量存放整型值。
- C語(yǔ)言中,實(shí)型變量分為單精度類型( float )和雙精度類型( double )兩種。如:
- 2.2.3.3? 字符變量
- 字符變量用來(lái)存放字符常量,定義形式:
- char? 變量名;
- 其中關(guān)鍵字char定義字符型數(shù)據(jù)類型,占用一個(gè)字節(jié)的存儲(chǔ)單元。
- 例:char? cr1,cr2;
- cr1= ‘A’ , cr2=‘B’ ;
- 將一個(gè)字符賦給一個(gè)字符變量時(shí),并不是將該字符本身存儲(chǔ)到內(nèi)存中,而是將該字符對(duì)應(yīng)的ASCII碼存儲(chǔ)到內(nèi)存單元中。
- 例如,字符 ′A′ 的ASCII碼為65,在內(nèi)存中的存放形式如下:01000001
- 由于在內(nèi)存中字符以ASCII碼存放,它的存儲(chǔ)形式和整數(shù)的存儲(chǔ)形式類似,所以C語(yǔ)言中字符型數(shù)據(jù)與整型數(shù)據(jù)之間可以通用,一個(gè)字符能用字符的形式輸出,也能用整數(shù)的形式輸出,字符數(shù)據(jù)也能進(jìn)行算術(shù)運(yùn)算,此時(shí)相當(dāng)于對(duì)它們的ASCII碼進(jìn)行運(yùn)算。
- 字符變量用來(lái)存放字符常量,定義形式:
- 2.2.4.4? 類型的自動(dòng)轉(zhuǎn)換和強(qiáng)制轉(zhuǎn)換
- 當(dāng)同一表達(dá)式中各數(shù)據(jù)的類型不同時(shí),編譯程序會(huì)自動(dòng)把它們轉(zhuǎn)變成同一類型后再進(jìn)行計(jì)算。轉(zhuǎn)換優(yōu)先級(jí)為:
- 即下邊級(jí)別“低“的類型向上邊轉(zhuǎn)換。具體地說(shuō),若在表達(dá)式中優(yōu)先級(jí)最高的數(shù)據(jù)是double型,則此表達(dá)式中的其他數(shù)據(jù)均被轉(zhuǎn)換成double型,且計(jì)算結(jié)果也是double型;若在表達(dá)式中優(yōu)先級(jí)最高的數(shù)據(jù)是float型,則此表達(dá)式中的其他數(shù)據(jù)均被轉(zhuǎn)換成float型,且計(jì)算結(jié)果也是float型。
- 在做賦值運(yùn)算時(shí),若賦值號(hào)左右兩邊的類型不同,則賦值號(hào)右邊的類型向左邊的類型轉(zhuǎn)換;當(dāng)右邊的類型高于左邊的類型時(shí),則在轉(zhuǎn)換時(shí)對(duì)右邊的數(shù)據(jù)進(jìn)行截取。
- 除自動(dòng)轉(zhuǎn)換外,還有強(qiáng)制轉(zhuǎn)換,表示形式是:
- 一般形式:(類型說(shuō)明符)(表達(dá)式)
- 功能:把表達(dá)式的運(yùn)算結(jié)果強(qiáng)制轉(zhuǎn)換成類型說(shuō)明符所表示的類型
- 例:(int)(a+b)
- 一定是 (int)a 不是? int(a),注意類型上一定有括號(hào)的。
- 注意(int)(a+b) 和(int)a+b 的區(qū)別。 前是把a(bǔ)+b轉(zhuǎn)型,后是把a(bǔ)轉(zhuǎn)型再加b。
- 例1表達(dá)式(int)((double)(5/2)+2.5)的值是4。
- (int)((double)(5/2)+2.5)
- →(int)((double)2)+2.5)
- →(int)(2.000000+2.5)
- →(int)(4.500000)
- →4。
- 例2:以下程序運(yùn)行后的輸出結(jié)果是(3) 。
- main()
- { ??? int a;
- a=(int)((double)(3/2)+0.5+(int)1.99*2);
- printf("%d\n",a);
- }
- (3/2)=1,
- (double)(3/2)+0.5=1.5,
- (int)1.99*2=2,(double)(3/2)+0.5+(int)1.99*2=3.5,故a=3。
- 三種取整丟小數(shù)的情況:
- 1、int a=1.6;
- 2、(int)a;
- 3、1/2; 3/2; //除法
- 當(dāng)同一表達(dá)式中各數(shù)據(jù)的類型不同時(shí),編譯程序會(huì)自動(dòng)把它們轉(zhuǎn)變成同一類型后再進(jìn)行計(jì)算。轉(zhuǎn)換優(yōu)先級(jí)為:
- 2.2.4.5? 全局變量和局部變量
- 在C語(yǔ)言中,用戶命名的標(biāo)識(shí)符都有一個(gè)有效的作用域。
- 所謂標(biāo)識(shí)符的“作用域”就是指程序中的某一部分,在這部分中,該標(biāo)識(shí)符是有定義的,可以被C編譯和連接程序所識(shí)別。
- 我們知道每個(gè)變量都有自己的作用域,在一個(gè)函數(shù)內(nèi)定義的變量,不能在其他函數(shù)中引用。顯然,變量的作用域與其定義語(yǔ)句在程序中出現(xiàn)的位置有直接的關(guān)系,據(jù)此變量可以劃分為局部變量和全局變量。
- 注意“定義”和 “說(shuō)明”兩個(gè)詞的區(qū)別。“定義”是指給變量分配確定的存儲(chǔ)單元;“說(shuō)明”只是說(shuō)明變量的性質(zhì)。
- (一)局部變量
- 在一個(gè)函數(shù)內(nèi)部定義的變量,它們只在本函數(shù)范圍內(nèi)有效,即只有本函數(shù)才能使用它們,其他函數(shù)不能使用這些變量,我們將這些變量稱為“局部變量”。不同函數(shù)中可以使用相同名字的局部變量,它們代表不同的對(duì)象,在內(nèi)存中占不同的單元,互不干擾。
- (二)全局變量
- 在函數(shù)之外定義的變量稱為外部變量,外部變量是全局變量。全局變量可以為本文件中其他函數(shù)所共用,它的有效范圍從定義變量開(kāi)始到本文件結(jié)束。
- 如果在同一個(gè)源文件中,外部變量與局部變量同名,則在局部變量的作用范圍內(nèi),外部變量被“屏蔽”,即它不起作用。
- 變量作用域和生存期
- 生存期:什么時(shí)候這個(gè)變量開(kāi)始出現(xiàn)了,到什么時(shí)候消亡了
- 作用域:?在(代碼的)?什么范圍內(nèi)可以訪問(wèn)這個(gè)變量(這個(gè)變量可以起作用)
- 對(duì)于本地變量,這兩個(gè)問(wèn)題的答案是統(tǒng)一的:大括號(hào)內(nèi)一塊
- 2.2.4.6? 變量的存儲(chǔ)類別
- 變量值存在的時(shí)間(即生存期)
- 靜態(tài)存儲(chǔ)方式和動(dòng)態(tài)存儲(chǔ)方式。
- 所謂靜態(tài)存儲(chǔ)方式是指在程序運(yùn)行期間分配固定的存儲(chǔ)空間的方式,而動(dòng)態(tài)存儲(chǔ)方式是在程序運(yùn)行期間根據(jù)需要?jiǎng)討B(tài)分配存儲(chǔ)空間的方式
- 在內(nèi)存中供用戶使用的空間可以分為程序區(qū)、靜態(tài)存儲(chǔ)區(qū)和動(dòng)態(tài)存儲(chǔ)區(qū)3個(gè)部分。數(shù)據(jù)分別被存放在靜態(tài)存儲(chǔ)區(qū)和動(dòng)態(tài)存儲(chǔ)區(qū)中。靜態(tài)存儲(chǔ)區(qū)中存放的是全局變量,在程序開(kāi)始執(zhí)行時(shí)就給全局變量分配存儲(chǔ)區(qū)。程序執(zhí)行過(guò)程中它們占據(jù)固定的存儲(chǔ)單元,程序執(zhí)行完畢這些存儲(chǔ)單元就被釋放。
- 每一個(gè)變量和函數(shù)所具有的屬性是:數(shù)據(jù)的存儲(chǔ)類別和數(shù)據(jù)類型(在前面已經(jīng)介紹過(guò))。所謂的存儲(chǔ)類別指的是數(shù)據(jù)在內(nèi)存中存儲(chǔ)的方法,其可分為兩類:靜態(tài)存儲(chǔ)類和動(dòng)態(tài)存儲(chǔ)類。具體包括自動(dòng)(auto)、靜態(tài)(static)、寄存器(register)和外部(extern),共4種。
- (一)auto變量
- 當(dāng)在函數(shù)內(nèi)部或復(fù)合語(yǔ)句內(nèi)定義變量時(shí),如果沒(méi)有指定存儲(chǔ)類別,或使用了auto說(shuō)明符,系統(tǒng)就認(rèn)為所定義的變量具有自動(dòng)類別。如:
- float a;等價(jià)于auto float a;
- auto變量的存儲(chǔ)單元被分配在內(nèi)存的動(dòng)態(tài)存儲(chǔ)區(qū),每當(dāng)進(jìn)入函數(shù)體(或復(fù)合語(yǔ)句)時(shí),系統(tǒng)自動(dòng)為auto變量分配存儲(chǔ)單元,退出時(shí)自動(dòng)釋放這些存儲(chǔ)單元另做他用。因此,這類局部變量的作用域是從定義的位置起,到函數(shù)體(或復(fù)合語(yǔ)句)結(jié)束止。
- 所有自動(dòng)類局部變量的存儲(chǔ)單元都是在進(jìn)入這些局部變量所在的函數(shù)體(或復(fù)合語(yǔ)句)時(shí)生成,退出其所在的函數(shù)體(或復(fù)合語(yǔ)句)時(shí)消失(變?yōu)闊o(wú)定義)。這就是自動(dòng)類局部變量的“生存期“。當(dāng)再次進(jìn)入函數(shù)體(或復(fù)合語(yǔ)句)時(shí),系統(tǒng)將為它們另行分配存儲(chǔ)單元,因此變量的值不可能被保留。隨著函數(shù)的頻繁調(diào)用,動(dòng)態(tài)存儲(chǔ)區(qū)內(nèi)為某個(gè)變量分配的存儲(chǔ)單元位置會(huì)隨程序的運(yùn)行而改變。
- 當(dāng)在函數(shù)內(nèi)部或復(fù)合語(yǔ)句內(nèi)定義變量時(shí),如果沒(méi)有指定存儲(chǔ)類別,或使用了auto說(shuō)明符,系統(tǒng)就認(rèn)為所定義的變量具有自動(dòng)類別。如:
- (二)register變量
- 寄存器變量也是自動(dòng)類變量。它與auto變量的區(qū)別僅在于:用register說(shuō)明變量是建議編譯程序?qū)⒆兞康闹当A粼贑PU的寄存器中,而不是像一般變量那樣占用內(nèi)存單元。程序運(yùn)行時(shí),訪問(wèn)寄存器內(nèi)的值要比訪問(wèn)內(nèi)存中的值快得多。因此,當(dāng)程序?qū)\(yùn)行速度有較高要求時(shí),把那些頻繁引用的少數(shù)變量,指定為register變量,有助于提高程序運(yùn)行的效率。
- 說(shuō)明:
- (1)CPU中寄存器的數(shù)目是有限的,因此只能說(shuō)明少量的寄存器變量。在同一個(gè)函數(shù)中,允許說(shuō)明為寄存器變量的數(shù)目不僅取決于CPU的類型,也與所用的C編譯程序有關(guān)。當(dāng)沒(méi)有足夠的寄存器來(lái)存放指定的變量,或編譯程序認(rèn)為指定的變量不適合放在寄存器中時(shí),將自動(dòng)按auto變量來(lái)處理。因此,register說(shuō)明只是對(duì)編譯程序的一種建議,而不是強(qiáng)制性的。
- (2)由于register變量的值存放在寄存器內(nèi)而不是存放在內(nèi)存中,所以register變量沒(méi)有地址,也就不能對(duì)它實(shí)行求地址運(yùn)算。
- (3)register變量的說(shuō)明應(yīng)盡量靠近其使用的地方,用完之后盡快釋放,以便提高寄存器的利用效率。
- 說(shuō)明:
- 寄存器變量也是自動(dòng)類變量。它與auto變量的區(qū)別僅在于:用register說(shuō)明變量是建議編譯程序?qū)⒆兞康闹当A粼贑PU的寄存器中,而不是像一般變量那樣占用內(nèi)存單元。程序運(yùn)行時(shí),訪問(wèn)寄存器內(nèi)的值要比訪問(wèn)內(nèi)存中的值快得多。因此,當(dāng)程序?qū)\(yùn)行速度有較高要求時(shí),把那些頻繁引用的少數(shù)變量,指定為register變量,有助于提高程序運(yùn)行的效率。
- (三)靜態(tài)存儲(chǔ)類別的局部變量
- 當(dāng)函數(shù)體(或復(fù)合語(yǔ)句)內(nèi)部用static來(lái)說(shuō)明一個(gè)變量時(shí),可以稱該變量為靜態(tài)局部變量。它與auto變量、register變量的本質(zhì)區(qū)別是:
- (1)在整個(gè)程序運(yùn)行期間,靜態(tài)局部變量在內(nèi)存中的靜態(tài)存儲(chǔ)區(qū)中占據(jù)著永久性的存儲(chǔ)單元。即使退出函數(shù)后,下次再進(jìn)入該函數(shù)時(shí),靜態(tài)局部變量仍使用原來(lái)的存儲(chǔ)單元。由于不釋放這些存儲(chǔ)單元,這些存儲(chǔ)單元中的值得以保留,因而可以繼續(xù)使用存儲(chǔ)單元中原來(lái)的值。由此可知,靜態(tài)局部變量的生存期將一直延長(zhǎng)到程序運(yùn)行結(jié)束。
- (2)靜態(tài)局部變量的初值是在編譯時(shí)賦予的,在程序執(zhí)行期間不再賦以初值。對(duì)未賦值的局部變量,C語(yǔ)言編譯程序自動(dòng)給它賦初值為0。
- 當(dāng)函數(shù)體(或復(fù)合語(yǔ)句)內(nèi)部用static來(lái)說(shuō)明一個(gè)變量時(shí),可以稱該變量為靜態(tài)局部變量。它與auto變量、register變量的本質(zhì)區(qū)別是:
- (四)用static聲明外部變量
- 有時(shí)在程序設(shè)計(jì)中希望某些外部變量只限于本文件使用,而不能被其他文件引用,這時(shí)可以在定義外部變量時(shí)加一個(gè)static聲明。
- 并不是對(duì)外部變量加上static才是靜態(tài)存儲(chǔ)而不加static的是動(dòng)態(tài)存儲(chǔ)。兩種形式的外部變量都是靜態(tài)存儲(chǔ)方式,只是作用范圍不同而已。
- 有時(shí)在程序設(shè)計(jì)中希望某些外部變量只限于本文件使用,而不能被其他文件引用,這時(shí)可以在定義外部變量時(shí)加一個(gè)static聲明。
- (五)用extern聲明外部變量
- ① 在一個(gè)文件內(nèi)聲明外部變量
- 當(dāng)全局變量定義在后,引用它的函數(shù)在前時(shí),應(yīng)該在引用它的函數(shù)中用extern對(duì)此全局變量進(jìn)行說(shuō)明,以便通知編譯程序,該變量是一個(gè)已在外部定義了的全局變量,已經(jīng)分配了存儲(chǔ)單元,不需要為它另開(kāi)辟存儲(chǔ)單元。這時(shí)其作用域從extern說(shuō)明處起,延伸到該函數(shù)末尾。
- 全局變量的說(shuō)明與全局變量的定義不同。變量的定義(開(kāi)辟存儲(chǔ)單元)只能出現(xiàn)一次,在定義全局變量時(shí),不可使用extern說(shuō)明符;而對(duì)全局變量的說(shuō)明,則可以多次出現(xiàn)在需要的地方,這時(shí)必須用extern進(jìn)行說(shuō)明。
- ② 在多文件的程序中聲明外部變量
- 當(dāng)一個(gè)程序由多個(gè)單獨(dú)編譯的源文件組成,并且在每個(gè)文件中均需要引用同一個(gè)全局變量時(shí),若在每個(gè)文件中都定義了所需的同名全局變量,則在“連接”時(shí)將會(huì)產(chǎn)生“重復(fù)定義”的錯(cuò)誤。在這種情況下,單獨(dú)編譯每個(gè)文件時(shí)并無(wú)異常,編譯程序?qū)炊x分別給它們開(kāi)辟存儲(chǔ)空間,而當(dāng)進(jìn)行連接時(shí),就會(huì)顯示出錯(cuò)信息。解決的方法是:在其中一個(gè)文件中定義所有全局變量,而在其他用到這些全局變量的文件中用extern對(duì)這些變量進(jìn)行說(shuō)明。
- ① 在一個(gè)文件內(nèi)聲明外部變量
- 定義
- 2.2.1分類 基本類型
- 2.3構(gòu)造類型
- 2.3.1? 數(shù)組
- 2.3.1.1? 一維數(shù)組的定義和引用
- (一)數(shù)組的概念
- 數(shù)組是由屬于同一個(gè)數(shù)據(jù)類型的有序數(shù)據(jù)集構(gòu)成的。數(shù)組中的每一個(gè)數(shù)據(jù)稱為“元素“。可以用一個(gè)統(tǒng)一的數(shù)組名和下標(biāo)來(lái)唯一地標(biāo)識(shí)數(shù)組中的元素。
- (二)一維數(shù)組的定義
- 一維數(shù)組的定義方式為:
- 類型說(shuō)明符??數(shù)組名[常量表達(dá)式];
- 如:
- char c[20];
- c是數(shù)組名,此數(shù)組共有20個(gè)元素,并且每個(gè)元素的類型都為字符型。
- (三)一維數(shù)組元素的引用
- 數(shù)組元素的表示形式為:
- 數(shù)組名[下標(biāo)];
- 引用數(shù)組元素時(shí),數(shù)組的下標(biāo)可以是整型常量,也可以是整型表達(dá)式。
- 和變量一樣,數(shù)組必須先定義后使用。數(shù)組元素只能逐個(gè)引用而不能把數(shù)組當(dāng)做一個(gè)整體一次引用。
- 數(shù)組名[下標(biāo)];
- 數(shù)組元素的表示形式為:
- (四)一維數(shù)組的初始化
- 當(dāng)數(shù)組定義后,系統(tǒng)會(huì)為該數(shù)組在內(nèi)存中開(kāi)辟一串連續(xù)的存儲(chǔ)單元,但這些存儲(chǔ)單元中并沒(méi)有確定的值。可以在定義數(shù)組時(shí)為所包含的數(shù)組元素賦初值,如:
- int a[6]={ 0,1,2,3,4,5 };
- 所賦初值放在一對(duì)花括號(hào)中,數(shù)值類型必須與所說(shuō)明類型一致。所賦初值之間用逗號(hào)隔開(kāi),系統(tǒng)將按這些數(shù)值的排列順序,從a[0]元素開(kāi)始依次給a數(shù)組中的元素賦初值。以上語(yǔ)句將a[0]賦值0,a[1]賦值1, …… ,a[5]賦值5。在指定初值時(shí),第一個(gè)初值必定賦給下標(biāo)為0的元素。也就是說(shuō)數(shù)組元素的下標(biāo)是從0開(kāi)始的。同時(shí),不可能跳過(guò)前面的元素給后面的元素賦初值,但是允許為前面元素賦值為0。當(dāng)所賦初值個(gè)數(shù)少于所定義數(shù)組的元素個(gè)數(shù)時(shí),將自動(dòng)給后面的其他元素補(bǔ)以初值0;當(dāng)所賦初值個(gè)數(shù)多于所定義數(shù)組的元素個(gè)數(shù)時(shí),也就是說(shuō)超出了數(shù)組已經(jīng)定義的范圍,在編譯時(shí)系統(tǒng)將給出出錯(cuò)信息。
- C語(yǔ)言規(guī)定可以通過(guò)賦初值來(lái)定義數(shù)組的大小,這時(shí)一對(duì)方括號(hào)中可以不指定數(shù)組大小。
- 當(dāng)數(shù)組定義后,系統(tǒng)會(huì)為該數(shù)組在內(nèi)存中開(kāi)辟一串連續(xù)的存儲(chǔ)單元,但這些存儲(chǔ)單元中并沒(méi)有確定的值。可以在定義數(shù)組時(shí)為所包含的數(shù)組元素賦初值,如:
- (一)數(shù)組的概念
- 2.3.1.1? 一維數(shù)組的定義和引用
- 2.3.1.2? 一維數(shù)組與函數(shù)
- 一、 一維數(shù)組元素作為實(shí)參
- 無(wú)論是一維數(shù)組元素或者二維數(shù)組元素,和普通變量的使用沒(méi)有任何區(qū)別,他們之間僅僅是變量名不同,一維數(shù)組元素作為實(shí)參傳遞給形參,形參數(shù)據(jù)改變不會(huì)影響實(shí)參變化。
- 二、一維數(shù)組元素地址作為實(shí)參
- 一維數(shù)組元素的地址作為實(shí)參,對(duì)應(yīng)的形參必須是與實(shí)參基類型相同的指針變量。此時(shí)可以通過(guò)被調(diào)用函數(shù)改變調(diào)用函數(shù)中的數(shù)據(jù)。
- 例 有以下程序段
- #include<stdio.h>
- voidfun(int x,int *p)
- {
- x*=2;
- p[0]=p[-1]+p[1];
- }
- main()
- {
- int a[10]={1,2,3,4,5,6,7,8,9,10};
- fun(a[2],&a[6]);
- printf("%d? %d\n",a[2],a[6]);
- }
- 程序運(yùn)行后的輸出結(jié)果是 3? 14
- 本題主函數(shù)中有函數(shù)調(diào)用 fun (a[2],&a[6]);
- 第一個(gè)傳遞的實(shí)參是a[2]的值3,對(duì)原數(shù)不影響
- 第二個(gè)傳遞的實(shí)參是&a[6] (a[6]的地址),指針變量p存儲(chǔ)a[6]的地址,根據(jù)指針變量加下標(biāo)表示數(shù)據(jù)的方法,p[0]存儲(chǔ)的是a[6]的值,p[-1]存儲(chǔ)的是a[5]的值6,p[1]存儲(chǔ)的是a[7]的值8。經(jīng)過(guò)p[0]=p[-1]+p[1]計(jì)算;值為14。
- 例 有以下程序段
- 一維數(shù)組元素的地址作為實(shí)參,對(duì)應(yīng)的形參必須是與實(shí)參基類型相同的指針變量。此時(shí)可以通過(guò)被調(diào)用函數(shù)改變調(diào)用函數(shù)中的數(shù)據(jù)。
- 三、一維數(shù)組名作為實(shí)參
- 一維數(shù)組名為地址常量,表示數(shù)組的首地址,如果一維數(shù)組名作為實(shí)參,對(duì)應(yīng)的形參應(yīng)該是一個(gè)指針變量,此指針變量的基本類型必須與數(shù)組的類型一致。
- 通常被調(diào)用函數(shù)的首部可以有以下3中方式:
- (1)fun(int *a)
- (2)fun(int a[N])
- (3)fun(int a[ ])
- 例? 有以下程序段
- #include<stdio.h>
- int fun(int *x,int n)
- {
- int i , sum = 0 ;
- for (i=0;i<n;i++)
- sum=sum+x[i];
- return sum;
- }
- main()
- {
- int a[]={1,2,3,4,5 },s=0;
- s=fun (a,5);
- printf("%d? \n",s);
- }
- 程序運(yùn)行后的輸出結(jié)果是15
- 本題main函數(shù)中定義了一維數(shù)組a,含有5個(gè)int類型的數(shù)組元素,所以地址常量a的基本類型為int類型,對(duì)應(yīng)的形參x的基本類型也是int類型,可以進(jìn)行參數(shù)的傳遞,傳遞后依然用指針變量加下標(biāo)的方式表示數(shù)據(jù)。
- 例? 有以下程序段
- 一、 一維數(shù)組元素作為實(shí)參
- 2.3.1.3 二維數(shù)組的定義和引用
- (一)二維數(shù)組的定義
- 在C語(yǔ)言中,二維數(shù)組中元素排列的順序是:按行存放,即在內(nèi)存中先順序存放第一行的元素,再存放第二行的元素。因此,二維數(shù)組元素的存儲(chǔ)與一維數(shù)組元素存儲(chǔ)相類似,總是占用一塊連續(xù)的內(nèi)存單元。
- 二維數(shù)組的一般形式為:
- 類型說(shuō)明符??數(shù)組名[常量表達(dá)式][常量表達(dá)式];
- 如:int c[3][4]; 定義c為3×4 (3行4列)的數(shù)組。
- 注意:不能寫(xiě)成c[3,4]。C語(yǔ)言對(duì)二維數(shù)組采用這樣的定義方式:我們可以把二維數(shù)組當(dāng)做是一種特殊的一維數(shù)組。
- 例如,可以把c看成是一個(gè)一維數(shù)組,它有3個(gè)元素c[0]、c[1]、c[2],每個(gè)元素又是一個(gè)包含4個(gè)元素的一維數(shù)組。可以把c[0]、c[1]、c[2]看做是3個(gè)一維數(shù)組的名字。
- 注意:不能寫(xiě)成c[3,4]。C語(yǔ)言對(duì)二維數(shù)組采用這樣的定義方式:我們可以把二維數(shù)組當(dāng)做是一種特殊的一維數(shù)組。
- (二)二維數(shù)組的引用
- 二維數(shù)組的表示形式為:
- 數(shù)組名[下標(biāo)][下標(biāo)]
- 數(shù)組的下標(biāo)可以是整型表達(dá)式,如 c[3-1][3×2-2];
- 數(shù)組名[下標(biāo)][下標(biāo)]
- 數(shù)組元素可以出現(xiàn)在表達(dá)式中,也可以被賦值。
- 定義數(shù)組時(shí)用的c[3][4]和引用元素時(shí)的c[3][4]的區(qū)別:前者用來(lái)定義數(shù)組的維數(shù)和各維的大小,共有3行4列;后者中的3和4是下標(biāo)值,c[3][4]代表該數(shù)組中的一個(gè)元素。如果a[3][4]是二維數(shù)組中最后一個(gè)元素,那么該數(shù)組共有4行5列。
- 二維數(shù)組的表示形式為:
- (三)二維數(shù)組的初始化
- 可以在定義二維數(shù)組的同時(shí)給二維數(shù)組的各元素賦初值。
- 如:
- float m[2][2]={{1.5,3.2},{0.8}};
- 如:
- 全部初值放在一對(duì)花括號(hào)中,每一行的初值又分別括在一對(duì)花括號(hào)中,之間用逗號(hào)隔開(kāi)。當(dāng)某行一對(duì)花括號(hào)內(nèi)的初值個(gè)數(shù)少于該行中元素的個(gè)數(shù)時(shí),系統(tǒng)將自動(dòng)地給后面的元素補(bǔ)初值0。同樣,不能跳過(guò)每行前面的元素而給后面的元素賦初值。
- 可以在定義二維數(shù)組的同時(shí)給二維數(shù)組的各元素賦初值。
- (四)通過(guò)賦初值定義二維數(shù)組的大小
- 對(duì)于一維數(shù)組,可以在數(shù)組定義語(yǔ)句中省略方括號(hào)中的常量表達(dá)式,通過(guò)所賦初值的個(gè)數(shù)來(lái)確定數(shù)組的大小;對(duì)于二維數(shù)組,只可以省略第一個(gè)方括號(hào)中的常量表達(dá)式,而不能省略第二個(gè)方括號(hào)中的常量表達(dá)式。
- 如:
- int a[][3]={{1,2,3},{4,5},{6},{8}};
- a數(shù)組的第一維方括號(hào)中的常量表達(dá)式省略,在所賦初值中,含有4個(gè)花括號(hào),則第一維的大小由花括號(hào)的個(gè)數(shù)來(lái)決定。因此,該數(shù)組其實(shí)是與a[4][3]等價(jià)的。當(dāng)用以下形式賦初值時(shí):
- int c[][3]={1,2,3,4,5};
- 第一維的大小按以下規(guī)則決定:
- (1)當(dāng)初值的個(gè)數(shù)能被第二維的常量表達(dá)式的值除盡時(shí),所得商數(shù)就是第一維的大小。
- (2)當(dāng)初值的個(gè)數(shù)不能被第二維的常量表達(dá)式的值除盡時(shí),則:
- 第一維的大小 =所得商數(shù) + 1 。
- 因此,按此規(guī)則,以上c數(shù)組第一維的大小應(yīng)該是2,也就是說(shuō)語(yǔ)句等同于
- int c[2][3]={{1,2,3},{4,5}};。
- 2.3.1.4 二維數(shù)組與函數(shù)
- 二維數(shù)組名作為實(shí)參
- 二維數(shù)組元素作為實(shí)參,與普通變量作為實(shí)參沒(méi)有任何區(qū)別,二維數(shù)組名為行指針常量,如果二維數(shù)組名作為實(shí)參,對(duì)應(yīng)的形參必須是一個(gè)行指針變量。
- 例如:有以下定義和函數(shù)調(diào)用語(yǔ)句:
- #define? M? 5
- #define? N? 3
- main()
- {
- int s[M][N];
- …….
- fun(s);
- …….
- }
- 此時(shí),實(shí)參為二維數(shù)組名(即行指針),則fun函數(shù)的首部可以是以下3中形式之一:
- (1)fun ( int? (*a)[N])
- (2) fun ( int ?a[ ][N])
- (3) fun ( int? a[M][N])
- 注意:行下標(biāo)可以省略,列下標(biāo)不可以省略。無(wú)論哪種方式,系統(tǒng)都把a(bǔ)看作一個(gè)行指針變量。
- 二、指針數(shù)組名作為實(shí)參
- 指針數(shù)組名師指向指針的指針常量,因此當(dāng)指針數(shù)組名作為實(shí)參時(shí),對(duì)應(yīng)的形參應(yīng)該為一個(gè)指向指針的指針變量。
- 例如:有以下定義和函數(shù)調(diào)用語(yǔ)句:
- #define? M? 5
- #define? N? 3
- main()
- {
- int??s[M][N],*p[M];
- …….
- for(i=0;i<M;i++)? p[i]=s[i];
- fun(p);
- …….
- }
- 此時(shí),實(shí)參為一維數(shù)組名(即行指針),則fun函數(shù)的首部可以是以下3中形式之一:
- (2)fun ( int? *a[M])
- (2) fun ( int?? *a[ ])
- (3) fun ( int? **a)
- 2.3.1.5? 字符數(shù)組
- 注:C語(yǔ)言無(wú)字符串類型,字符串是存放在字符數(shù)組中的。
- (一)字符數(shù)組的定義
- 字符數(shù)組就是數(shù)組中的每個(gè)元素都是字符,定義方法同普通數(shù)組的定義相同,即逐個(gè)對(duì)數(shù)組元素賦值。如:
- char c[11];
- c為該數(shù)組名,該數(shù)組共有11個(gè)元素,并且每個(gè)元素都為字符型。
- (二)字符數(shù)組的初始化及引用
- 對(duì)字符數(shù)組初始化,可逐個(gè)元素地賦值,即把字符逐個(gè)賦給數(shù)組元素。如:
- char a[9]={ ′T′, ′h′, ′a′, ′n′, ′k′, ′′, ′y′, ′o′,′u′};
- 如果花括號(hào)中提供的初值個(gè)數(shù)(即字符個(gè)數(shù))大于數(shù)組長(zhǎng)度,則按語(yǔ)法錯(cuò)誤處理。
- 如果初值個(gè)數(shù)小于數(shù)組長(zhǎng)度,則將這些字符賦給數(shù)組中前面那些元素,其余的元素自動(dòng)定為空字符(′\0′)。如:
- char c[6]={′G′,′o′,′o′,′d′};
- 字符數(shù)組的引用形式與其他數(shù)組的引用形式相同,采用下標(biāo)引用,
- 即 數(shù)組名[下標(biāo)]。
- 例如:
- #include<stdio.h>
- main()
- { char c[9]={'T','h','a','n','k',',','y','o','u'};
- int i;
- for(i=0; i<9; i++)
- printf(“%c“,c[i]);
- }
- 輸出的結(jié)果為T(mén)hank,you。
- 即 數(shù)組名[下標(biāo)]。
- 對(duì)字符數(shù)組初始化,可逐個(gè)元素地賦值,即把字符逐個(gè)賦給數(shù)組元素。如:
- (三)字符串和字符串結(jié)束標(biāo)志
- C語(yǔ)言中,將字符串作為字符數(shù)組來(lái)處理。為了測(cè)定字符串的實(shí)際長(zhǎng)度,C語(yǔ)言規(guī)定了一個(gè)字符串結(jié)束標(biāo)志,以字符'\0'代表。就是說(shuō),在遇到字符'\0'時(shí),表示字符串結(jié)束,由它前面的字符組成字符串。
- 系統(tǒng)對(duì)字符串常量也自動(dòng)加一個(gè)'\0'作為結(jié)束符。
- 例如:
- char c[]=“c program“;
- 數(shù)組c共有9個(gè)字符,但在內(nèi)存中占10個(gè)字節(jié),最后一個(gè)字節(jié)'\0'是由系統(tǒng)自動(dòng)加上的。有了結(jié)束標(biāo)志'\0'后,在程序中往往依靠檢測(cè) '\0'的位置來(lái)判定字符串是否結(jié)束,而不是根據(jù)數(shù)組的長(zhǎng)度來(lái)決定字符串長(zhǎng)度。
- 說(shuō)明:'\0'代表ASCII碼為0的字符,是一個(gè)“空操作符“,它什么也不干。在輸出時(shí)也不輸出'\0',它只是一個(gè)結(jié)束的標(biāo)志。
- (四)字符數(shù)組的初始化
- 方法:將字符常量以逗號(hào)分隔寫(xiě)在花括號(hào)中
- ①在定義字符數(shù)組時(shí)進(jìn)行初始化
- charch[7]={‘s’,’t’,’u’,’d’,’e’,’n’,’t’};
- ②在對(duì)全部元素指定初值時(shí),可省寫(xiě)數(shù)組長(zhǎng)度。
- char ch[]={‘s’,’t’,’u’,’d’,’e’,’n’,’t’};
- ③如果花括弧內(nèi)提供的初值個(gè)數(shù)大于數(shù)組長(zhǎng)度?
- (五)用字符串來(lái)直接初始化字符數(shù)組
- 可直接把字符串寫(xiě)在花括號(hào)中來(lái)初始化字符數(shù)組.
- 如:charch[9]={“student”};
- 系統(tǒng)將雙引號(hào)括起來(lái)的字符依次賦給字符數(shù)組的各個(gè)元素, 并自動(dòng)在末尾補(bǔ)上字符串結(jié)束標(biāo)志字符'\0'。
- 幾點(diǎn)說(shuō)明:
- (1)字符串結(jié)束標(biāo)志'\0'僅用于判斷字符串是否結(jié)束,輸出字符串時(shí)不會(huì)輸出。
- (2)在對(duì)有確定大小的字符數(shù)組用字符串初始化時(shí),數(shù)組長(zhǎng)度應(yīng)大于字符串長(zhǎng)度。如: char s[7]={"student"};是錯(cuò)誤的.
- (3)在初始化一個(gè)一維字符數(shù)組時(shí),可以省略花括號(hào)。
- 如:? char s[8]="student";
- ( 4 )不能直接將字符串賦值給字符數(shù)組名。下面的操作是錯(cuò)誤的。
- 如:? s=”student”;
- 可直接把字符串寫(xiě)在花括號(hào)中來(lái)初始化字符數(shù)組.
- 2.3.1.6 注意
- 兩種重要的數(shù)組長(zhǎng)度
- char a[]={‘a(chǎn)’,’b’,’c’};?? //不安全,無(wú) \0
- 數(shù)組長(zhǎng)度為3,字符串長(zhǎng)度不定。sizeof(a)為3。
- char a[5]={ ‘a(chǎn)’,’b’,’c’}
- 數(shù)組長(zhǎng)度為5,字符串長(zhǎng)度3。sizeof(a)為5。
-
- #include"stdio.h"
- #include"string.h"
- main()
- {
- char m[] = "abc";
- //???? char n[] = {'a','b','c','\0'};?????? //4 4?3 3
- char n[] = {'a','b','c'};??????????? //4 3? 3 3
- printf("%d %d\n",sizeof(m),sizeof(n));
- printf("%d %d\n",strlen(m),strlen(n));
- return 0;
- }
- char a[]={‘a(chǎn)’,’b’,’c’};?? //不安全,無(wú) \0
- 數(shù)組的重要概念
- 對(duì)a[10]這個(gè)數(shù)組的討論。
- 1、a表示數(shù)組名,是第一個(gè)元素的地址,也就是元素a[0]的地址。
- 2、a是地址常量,所以只要出現(xiàn)a++,或者是a=a+2賦值的都是錯(cuò)誤的。
- 3、a是一維數(shù)組名,所以它是列指針,也就是說(shuō)a+1是跳一列。
- 對(duì)a[3][3]的討論。
- 1、a表示數(shù)組名,是第一個(gè)元素的地址,也就是元素a[0] [0]的地址。
- 2、a是地址常量,所以只要出現(xiàn)a++,或者是a=a+2賦值的都是錯(cuò)誤的。
- 3、a是二維數(shù)組名,所以它是行指針,也就是說(shuō)a+1是跳一行。
- 4、a[0]、a[1]、a[2]也都是地址常量,不可以對(duì)它進(jìn)行賦值操作,同時(shí)它們都是列指針,a[0]+1,a[1]+1,a[2]+1都是跳一列。
- 5、注意a和a[0] 、a[1]、a[2]是不同的,它們的基類型是不同的。前者是一行元素,后三者是一列元素。
- 對(duì)a[10]這個(gè)數(shù)組的討論。
- 數(shù)組的初始化
- 一維和二維的,一維可以不寫(xiě),二維第二個(gè)一定要寫(xiě)
- int a[]={1,2} 合法。??
- int a[][4]={2,3,4}合法。??
- int a[4][]={2,3,4}非法。
- 一維和二維的,一維可以不寫(xiě),二維第二個(gè)一定要寫(xiě)
- 二維數(shù)組中的行指針
- int a[1][2];
- 其中a現(xiàn)在就是一個(gè)行指針,a+1跳一行數(shù)組元素。?搭配(*p)[2]指針
- a[0],a[1]現(xiàn)在就是一個(gè)列指針。a[0]+1 跳一個(gè)數(shù)組元素。搭配*p[2]指針數(shù)組使用
- 脫衣服法則
- a[2]? 變成? *(a+2)
- a[2][3]變成 *(a+2)[3]再可以變成? *(*(a+2)+3)
- 這個(gè)思想很重要!
- 兩種重要的數(shù)組長(zhǎng)度
- 二維數(shù)組名作為實(shí)參
- 2.3.2結(jié)構(gòu)體
- 2.3.2.1? 結(jié)構(gòu)體類型
- 在實(shí)際工作中,當(dāng)我們需要把一些不同類型,但相互之間又存在著聯(lián)系的信息組合應(yīng)用時(shí),就要用到結(jié)構(gòu)體。結(jié)構(gòu)體是一種看似復(fù)雜但卻非常靈活的構(gòu)造型數(shù)據(jù)類型。在通常情況下,一個(gè)結(jié)構(gòu)體類型由若干個(gè)稱為成員(或稱為域)的部分組成。不同的結(jié)構(gòu)體類型可根據(jù)需要由不同的成員組成。但對(duì)于某個(gè)具體的結(jié)構(gòu)體類型,其成員的數(shù)量必須固定,這一點(diǎn)與數(shù)組相同;但該結(jié)構(gòu)體中各個(gè)成員的類型可以不同,這是結(jié)構(gòu)體與數(shù)組的重要區(qū)別。例如,我們常用的“時(shí)間“可以由以下3個(gè)部分描述:小時(shí)(hour)、分(minute)、秒(second)。它們都可以用整型數(shù)表示,可以把這3個(gè)成員組成一個(gè)整體,并給它取名為time,這就是一個(gè)簡(jiǎn)單的結(jié)構(gòu)體。
- 2.3.2.2? 結(jié)構(gòu)體聲明
- 聲明一個(gè)結(jié)構(gòu)體類型的一般形式為:
- struct? 結(jié)構(gòu)體名
- {? 成員表列? };
- struct是C語(yǔ)言中的關(guān)鍵字,是結(jié)構(gòu)體類型的標(biāo)志。“結(jié)構(gòu)體名“用做結(jié)構(gòu)體類型的標(biāo)志,它又稱“結(jié)構(gòu)體標(biāo)記“(structure tag)。大括弧內(nèi)是該結(jié)構(gòu)體中的各個(gè)成員,成員表列是由若干個(gè)變量類型名及變量名組成的。這些成員共同組成一個(gè)結(jié)構(gòu)體。
- 例如,上面提到的“時(shí)間“結(jié)構(gòu)體類型可以說(shuō)明如下:
- structtime
- {
- inthour;
- intminute;
- intsecond;
- };
- 其中,time就是結(jié)構(gòu)體名, hour、minute、second都是成員,并且各成員都應(yīng)進(jìn)行類型聲明,每個(gè)成員也就是結(jié)構(gòu)體中的一個(gè)域。
- 例如,上面提到的“時(shí)間“結(jié)構(gòu)體類型可以說(shuō)明如下:
- 成員名命名規(guī)則與變量名相同。所以結(jié)構(gòu)體類型也可以用以下形式說(shuō)明:
- struct 結(jié)構(gòu)體標(biāo)識(shí)名
- {
- 類型名1??? 結(jié)構(gòu)體成員名表1;
- 類型名2??? 結(jié)構(gòu)體成員名表2;
- ……
- 類型名n??? 結(jié)構(gòu)體成員名表n;
- };
- 說(shuō)明:
- (1)“結(jié)構(gòu)體標(biāo)識(shí)名”和“結(jié)構(gòu)體成員名表”都必須是合法的用戶定義的標(biāo)識(shí)符。
- (2)每個(gè)“結(jié)構(gòu)體成員名表“中都可以含有多個(gè)同類型的成員名,它們之間以逗號(hào)分隔。
- (3)結(jié)構(gòu)體類型說(shuō)明中的“類型名1”~“類型名n”,不僅可以是簡(jiǎn)單數(shù)據(jù)類型,也可以是某種結(jié)構(gòu)體類型。當(dāng)結(jié)構(gòu)體說(shuō)明中又包含結(jié)構(gòu)體時(shí),稱為結(jié)構(gòu)體的嵌套。
- (4)ANSI C標(biāo)準(zhǔn)規(guī)定結(jié)構(gòu)體至多允許嵌套15層,并且允許內(nèi)嵌結(jié)構(gòu)體成員的名字與外層成員的名字相同。
- 聲明一個(gè)結(jié)構(gòu)體類型的一般形式為:
- 2.3.2.3? 結(jié)構(gòu)體類型變量的定義
- 前面只是指定了一個(gè)結(jié)構(gòu)體類型,為了能在程序中使用結(jié)構(gòu)體類型的數(shù)據(jù),就需要定義結(jié)構(gòu)體類型的變量,并在其中存放具體的數(shù)據(jù)。可以用如下方法定義結(jié)構(gòu)體類型變量。
- (一)先聲明結(jié)構(gòu)體類型再定義變量名
- 如上面已經(jīng)定義了一個(gè)結(jié)構(gòu)體類型struct? time,可以如下定義:
- struct time??? time1,time2;
- 結(jié)構(gòu)體類型名??? 結(jié)構(gòu)體變量名;
- time1和time2為struct time類型變量,即它們都具有struct time類型的結(jié)構(gòu)。
- (二)在聲明類型的同時(shí)定義變量
- 其一般形式為:
- struct? 結(jié)構(gòu)體名 { 成員表列 } 變量名表列;
- (三)直接定義結(jié)構(gòu)體類型變量
- 其一般形式為:?struct { 成員表列 } 變量名表列;
- 即不出現(xiàn)結(jié)構(gòu)體名。
- 類型與變量是兩個(gè)不同的概念,使用時(shí)應(yīng)注意區(qū)別。只能對(duì)變量賦值、存取或運(yùn)算,而不能對(duì)一個(gè)類型進(jìn)行賦值、存取或運(yùn)算。可以單獨(dú)使用結(jié)構(gòu)體中的成員,它與普通變量的作用相同。
- (一)先聲明結(jié)構(gòu)體類型再定義變量名
- 前面只是指定了一個(gè)結(jié)構(gòu)體類型,為了能在程序中使用結(jié)構(gòu)體類型的數(shù)據(jù),就需要定義結(jié)構(gòu)體類型的變量,并在其中存放具體的數(shù)據(jù)。可以用如下方法定義結(jié)構(gòu)體類型變量。
- 2.3.2.4? 結(jié)構(gòu)體變量引用
- 在定義了結(jié)構(gòu)體變量以后,當(dāng)然可以引用這個(gè)變量。但應(yīng)注意:
- (1)結(jié)構(gòu)體變量不能作為一個(gè)整體而對(duì)其進(jìn)行任何操作,只能對(duì)結(jié)構(gòu)體變量中的各個(gè)成員分別進(jìn)行輸入和輸出等操作。結(jié)構(gòu)體變量中的成員用以下方式引用:
- 結(jié)構(gòu)體變量名.成員名
- (2)如果結(jié)構(gòu)體的某個(gè)成員本身又是一個(gè)結(jié)構(gòu)體類型,則可以使用若干個(gè)成員運(yùn)算符一級(jí)一級(jí)地找到最低的一級(jí)成員,只能對(duì)最低一級(jí)的成員進(jìn)行賦值或存取及運(yùn)算。
- (3)結(jié)構(gòu)體變量的初始化,是指逐個(gè)對(duì)結(jié)構(gòu)體變量的各個(gè)成員進(jìn)行初始化的過(guò)程。
- 2.3.2.5 ?結(jié)構(gòu)體數(shù)組
- 和普通數(shù)組一樣,結(jié)構(gòu)體數(shù)組中的每個(gè)元素都屬于同一數(shù)據(jù)類型(結(jié)構(gòu)體類型),只不過(guò)各個(gè)元素本身又都包含多個(gè)成員項(xiàng)。例如,一個(gè)結(jié)構(gòu)體變量中存放著一組數(shù)據(jù)(如某產(chǎn)品的名稱、型號(hào)、尺寸、顏色等數(shù)據(jù)),現(xiàn)在如果有10個(gè)這樣產(chǎn)品的數(shù)據(jù)需要參加運(yùn)算,顯然應(yīng)當(dāng)用到結(jié)構(gòu)體數(shù)組。和定義結(jié)構(gòu)體變量的方法相仿,只需說(shuō)明其為數(shù)組即可。
- 其一般形式為:
- struct? 結(jié)構(gòu)體變量名 { 成員表列} 數(shù)組名[常量表達(dá)式];
- 結(jié)構(gòu)體數(shù)組的初始化
- 結(jié)構(gòu)體數(shù)組的初始值應(yīng)順序地放在一對(duì)花括號(hào)中,由于數(shù)組中的每一個(gè)元素都是一個(gè)結(jié)構(gòu)體,因此通常將其成員的值依次放在一對(duì)花括號(hào)中,以便區(qū)分各個(gè)元素。
- 2.3.2.6 指向結(jié)構(gòu)體類型數(shù)據(jù)的指針
- 一個(gè)結(jié)構(gòu)體變量的指針就是用來(lái)指向該結(jié)構(gòu)體類型的存儲(chǔ)單元,并指向結(jié)構(gòu)體變量所占據(jù)的內(nèi)存段的起始地址。
- (一)指向結(jié)構(gòu)體變量的指針
- “結(jié)構(gòu)體變量.成員名”、“(*結(jié)構(gòu)體指針變量名).成員名“和“結(jié)構(gòu)體指針變量名->成員名”這3種形式是等價(jià)的,其中“->“稱為指向運(yùn)算符,它由兩部分組成:“-”減號(hào)和“>”大于號(hào),它們之間不能有空格
- 看下面的例子:
- #include<stdio.h>
- #include<string.h>
- main()
- {
- struct objects
- {
- char name[20];
- int size;
- char color[10];
- float weight;
- float height;
- };
- struct objects obj1;
- struct objects *p;
- p=&obj1;
- strcpy(obj1.name,"pen");
- obj1.size=10;
- strcpy(obj1.color,"black");
- obj1.weight=50.5;
- obj1.height=18.5;
- printf("name: %s\nsize: %d\ncolor:%s\nweight: %f\nheight:%f\n",obj1.name,obj1.size,obj1.color,obj1.weight,obj1.height);?? printf("name: %s\nsize: %d\ncolor: %s\nweight:%f\nheight: %f\n",(*p).name,(*p).size,(*p).color,(*p).weight,(*p).height);
- }
- 我們聲明了一個(gè)struct objects類型,并且定義了一個(gè)該類型的變量obj1,又定義了一個(gè)指向struct objects類型的數(shù)據(jù)的指針p,并且將p指向obj1,接下來(lái)是對(duì)各成員賦值。第一個(gè)printf語(yǔ)句用“.”的方式將obj1的成員的值輸出。第二個(gè)printf語(yǔ)句用(*p)將obj1的成員的值輸出,因?yàn)槌蓡T運(yùn)算符“.”的優(yōu)先級(jí)高于“*”運(yùn)算符,所以(*p)的兩側(cè)的圓括號(hào)不能省略。以上兩個(gè)printf函數(shù)語(yǔ)句的輸出結(jié)果是相同的,我們可用p->name來(lái)代替(*p).name
- (二)指向結(jié)構(gòu)體數(shù)組的指針
- 結(jié)構(gòu)體數(shù)組及其元素也可以用指針變量來(lái)指向。在使用指針變量指向結(jié)構(gòu)體數(shù)組時(shí),只要把該結(jié)構(gòu)體數(shù)組中的每個(gè)元素當(dāng)做普通的結(jié)構(gòu)體變量使用就可以了,例如:
- #include<stdio.h>
- #include<string.h>
- structobjects
- {
- char name[20];
- int size;
- char color[10];
- float weight;
- float height;
- };
- structobjects obj[3]= {{"pen",10,"black",50.5,18.5},
- {"notebook",20,"blue",180,19.5},
- {"bag",50,"red",2000,37.5}};
- main()
- {
- struct objects *p;
- printf("name size color weightheight\n");
- for(p=obj;p<obj+3;p++)
- printf("%10s%d%-20s%6.5f%6.5f\n",p->name,p->size,p->color,p->weight,p->height);
- }
- 這樣就可以利用指針變量來(lái)逐個(gè)把結(jié)構(gòu)體數(shù)組中的元素的各個(gè)域輸出。
- 說(shuō)明:
- 如果p的初值為obj,即指向第一個(gè)元素,則p+1就指向下一個(gè)元素。
- 例如:
- (++p)->name;先使p自加1,然后得到它指向的元素中的name成員值。
- 而(p++)->name;先得到p->name的值,然后使p自加1,指向obj[1];。
- p只能指向一個(gè)structobjects類型的數(shù)據(jù),不能指向obj數(shù)組元素中的某一成員(即p的地址不是成員的地址)。例如,p=&obj[1].name;是不對(duì)的。對(duì)結(jié)構(gòu)體變量中的每個(gè)成員,都可以像普通變量一樣,對(duì)它進(jìn)行同類變量所允許的任何操作。
- 例如:
- 如果p的初值為obj,即指向第一個(gè)元素,則p+1就指向下一個(gè)元素。
- 結(jié)構(gòu)體數(shù)組及其元素也可以用指針變量來(lái)指向。在使用指針變量指向結(jié)構(gòu)體數(shù)組時(shí),只要把該結(jié)構(gòu)體數(shù)組中的每個(gè)元素當(dāng)做普通的結(jié)構(gòu)體變量使用就可以了,例如:
- (三)用結(jié)構(gòu)體變量和指向結(jié)構(gòu)體的指針作為函數(shù)參數(shù)
- 將一個(gè)結(jié)構(gòu)體變量的值傳遞給另一個(gè)函數(shù),有如下方法:
- (1)結(jié)構(gòu)體變量的成員作為實(shí)參傳遞給主調(diào)函數(shù)。
- (2)可以用結(jié)構(gòu)體變量作為一個(gè)整體實(shí)參。
- (3)C語(yǔ)言中,允許將結(jié)構(gòu)體變量的地址作為實(shí)參傳遞,這時(shí),對(duì)應(yīng)的形參應(yīng)該是一個(gè)基類型相同的結(jié)構(gòu)體類型的指針。
- 將一個(gè)結(jié)構(gòu)體變量的值傳遞給另一個(gè)函數(shù),有如下方法:
- 2.3.2.1? 結(jié)構(gòu)體類型
- 2.3.3共用體
- 共用體的類型說(shuō)明和變量的定義方式與結(jié)構(gòu)體的類型說(shuō)明和變量定義的方式完全相同。不同的是,結(jié)構(gòu)體中的成員各自占有自己的存儲(chǔ)空間,而共用體的變量中的所有成員占有同一個(gè)存儲(chǔ)空間。可以把一個(gè)整型變量、一個(gè)字符型變量、一個(gè)實(shí)型變量放在同一個(gè)地址開(kāi)始的內(nèi)存單元中。以上3個(gè)變量在內(nèi)存中所占的字節(jié)數(shù)不同,但都從同一個(gè)起始地址開(kāi)始存放,也就是使用覆蓋技術(shù),幾個(gè)變量相互覆蓋。
- (一)共用體類型的說(shuō)明
- 共用體類型說(shuō)明的一般形式為:
- union 共用體標(biāo)識(shí)名
- {
- 類型名1共用體成員名1;
- 類型名2共用體成員名2;
- .
- 類型名n共用體成員名n;
- };
- 例如:
- unionexample
- {
- int a;
- float b;
- char? c;
- };
- 其中,union是關(guān)鍵字,是共用體類型的標(biāo)志,example是共用體標(biāo)識(shí)名。“共用體標(biāo)識(shí)名“和“共用體成員名“都是由用戶定義的合法標(biāo)識(shí)符,按語(yǔ)法規(guī)定共用體標(biāo)識(shí)名是可選項(xiàng),在說(shuō)明中可以不出現(xiàn)。
- 例如:
- (二)共用體變量的定義
- 和結(jié)構(gòu)體相似,共用體變量的定義也可采用3種方式,一種方法如下:
- union un
- {
- int i;
- float x;
- }s1,s2,*p;
- 說(shuō)明:
- (1)共用體變量在定義的同時(shí)只能用第一個(gè)成員的類型的值進(jìn)行初始化。
- (2)“共用體“與“結(jié)構(gòu)體“的定義形式相似,但它們的含義是不同的。結(jié)構(gòu)體變量所占內(nèi)存長(zhǎng)度是各成員占的內(nèi)存長(zhǎng)度之和,每個(gè)成員分別占有其自己的內(nèi)存單元,而共用體變量所占的內(nèi)存長(zhǎng)度等于變量中所占字節(jié)最長(zhǎng)的成員的長(zhǎng)度。例如,上面的共用體占4字節(jié)(因?yàn)橐粋€(gè)實(shí)型變量占4字節(jié))。
- 和結(jié)構(gòu)體相似,共用體變量的定義也可采用3種方式,一種方法如下:
- (三)共用體變量中成員的引用
- 共用體變量中每個(gè)成員的引用方式與結(jié)構(gòu)體完全相同,可以使用以下3種形式之一:
- (1)共用體變量.成員名
- (2)(*共用體指針變量名).成員名
- (3)共用體指針變量名->成員名
- 共用體中的成員變量同樣可參與其所屬類型允許的任何操作,但在訪問(wèn)共用體成員時(shí)應(yīng)注意:共用體變量中起作用的是最近一次存入的成員變量的值,原有成員變量的值將被覆蓋。
- 另外,ANSIC標(biāo)準(zhǔn)允許在兩個(gè)類型相同的共用體變量之間進(jìn)行賦值操作。同結(jié)構(gòu)體變量一樣,共用體類型的變量可以作為實(shí)參進(jìn)行傳遞,也可以傳遞共用體變量的地址。
- 共用體的考查:
- union TT
- { int a;
- char ch[2];}
- 考點(diǎn)一:sizeof (structTT) = 2;
- 考點(diǎn)二:TT t1 ;? t1=0x1234;
- 那么 ch[0]=0x 34;? ch[1]=0x12
- 共用體變量中每個(gè)成員的引用方式與結(jié)構(gòu)體完全相同,可以使用以下3種形式之一:
- 共用體類型說(shuō)明的一般形式為:
- 2.3.1? 數(shù)組
- 2.4指針類型
- 2.4.1 關(guān)于地址和指針
- 在內(nèi)存區(qū)中每一個(gè)字節(jié)都有一個(gè)編號(hào),這個(gè)編號(hào)就是“地址“,它相當(dāng)于每個(gè)變量的房間號(hào)。變量的數(shù)據(jù)就存放在地址所標(biāo)識(shí)的內(nèi)存單元中,變量中的數(shù)據(jù)其實(shí)就相當(dāng)于倉(cāng)庫(kù)中各個(gè)房間存放的貨物。如果內(nèi)存中沒(méi)有對(duì)字節(jié)進(jìn)行編號(hào),系統(tǒng)將無(wú)法對(duì)內(nèi)存進(jìn)行管理。內(nèi)存的存儲(chǔ)空間是連續(xù)的,因此內(nèi)存中的地址號(hào)也是連續(xù)的,并且用二進(jìn)制數(shù)表示,為了直觀起見(jiàn),在這里我們將用二進(jìn)制數(shù)進(jìn)行描述。
- 一般微機(jī)使用的C系統(tǒng)為整型變量分配4個(gè)字節(jié),為實(shí)型變量分配4個(gè)字節(jié),為字符型變量分配1個(gè)字節(jié),為雙精度類型變量分配8個(gè)字節(jié)。當(dāng)某一變量被定義后,其內(nèi)存中的地址也就確定了。
- 在一般情況下,我們?cè)诔绦蛑兄恍瓒x變量并指出變量名,無(wú)須去知道每個(gè)變量在內(nèi)存中的具體地址,由C編譯系統(tǒng)來(lái)完成每個(gè)變量與其具體地址發(fā)生聯(lián)系的操作。在程序中我們對(duì)變量進(jìn)行存取操作,實(shí)際上也就是對(duì)某個(gè)變量的地址存儲(chǔ)單元進(jìn)行操作。這種直接按變量的地址存取變量的方式稱為“直接存取“方式。
- 在C語(yǔ)言中,還可以用另一種稱為“間接存取“的方式來(lái)完成對(duì)變量進(jìn)行存取的操作,即將變量的地址存放在另一種類型的變量中,從而通過(guò)這種新的變量類型來(lái)得到變量的值。按C語(yǔ)言規(guī)定,可以在程序中定義整型變量、實(shí)型變量、字符變量等,也可以定義這樣一種特殊的變量,它是專門(mén)用來(lái)存放地址的。
- 由于通過(guò)地址能找到所需的變量單元,我們就可以說(shuō):地址“指向“該變量單元。 所謂“指向“就是通過(guò)地址來(lái)體現(xiàn)。
- 在C語(yǔ)言中,將地址形象地稱為“指針“,意思是通過(guò)它能找到以它為地址的內(nèi)存單元,這里包含有一個(gè)方向指向的意思。一個(gè)變量的地址稱為變量的“指針“。一個(gè)專門(mén)用來(lái)存放另一個(gè)變量的地址的變量(即指針),則稱它為“指針變量“。變量的指針就是變量的地址。存放變量地址的變量是指針變量。即在C語(yǔ)言中,允許用一個(gè)變量來(lái)存放指針,這種變量稱為指針變量。因此,一個(gè)指針變量的值就是某個(gè)變量的地址或稱為某變量的指針。
- 為了表示指針變量和它所指向的變量之間的關(guān)系,在程序中用“*”符號(hào)表示“指向”,例如,i_p代表指針變量,而*i_p是i_p所指向的變量。因此,下面兩個(gè)語(yǔ)句作用相同:i=3;? 語(yǔ)句是把3賦值給變量單元i。*i_p=3;? 語(yǔ)句是把3賦值給i_p指向的變量單元。兩者都能正確存儲(chǔ)數(shù)據(jù)。
- 2.4.2 變量的指針和指向變量的指針變量
- (一)指針變量的定義
- 定義指針變量的一般形式如下:
- 類型名? *指針變量名1,*指針變量名2,… ;
- 如:int?*p,*t;
- int *p;和int* p;一樣
- 以上定義語(yǔ)句中,p和t都是合法用戶標(biāo)識(shí)符,在每個(gè)變量前的星號(hào)(*)是一個(gè)類型說(shuō)明符,用來(lái)標(biāo)識(shí)該變量是指針變量。
- 變量前的星號(hào)不可省略,若省略了星號(hào)說(shuō)明符,就變成了把p和t定義為整型變量(int是類型名)。在這里,說(shuō)明了p和t是兩個(gè)指向整型(int 類型)變量的指針,也就是說(shuō)變量p和t中只能存放int類型變量的地址,這時(shí)我們稱int是指針變量p和t的“基類型“。基類型用來(lái)指定該指針變量可以指向的變量的類型。
- 例如:??? int *p1;
- 表示p1是一個(gè)指針變量,它的值是某個(gè)整型變量的地址。或者說(shuō)p1指向一個(gè)整型變量。至于p1究竟指向哪一個(gè)整型變量,應(yīng)由向p1賦予的地址來(lái)決定。
- 再如:
- int*p2;??????? /*p2是指向整型變量的指針變量*/
- float*p3;????? /*p3是指向浮點(diǎn)變量的指針變量*/
- char*p4;?????? /*p4是指向字符變量的指針變量*/
- 應(yīng)該注意的是,一個(gè)指針變量只能指向同類型的變量,如P3 只能指向浮點(diǎn)變量,不能時(shí)而指向一個(gè)浮點(diǎn)變量,時(shí)而又指向一個(gè)字符變量。
- 例如:??? int *p1;
- 定義指針變量的一般形式如下:
- (二)指針變量的引用
- 指針變量中只能存放地址(指針),將一個(gè)整型變量(或任何其他非地址類型的數(shù)據(jù))賦給一個(gè)指針變量是不允許的。
- 如:
- int? *p; /*定義一個(gè)指向整型變量的指針*/
- p=300;? /*300為整數(shù)*/
- 是不合法的賦值。
- 如:
- 與指針相關(guān)的兩個(gè)運(yùn)算符是“&“(取地址運(yùn)算)和“*“(指針運(yùn)算符)。
- 1)?????? &:取地址運(yùn)算符。
- 2)?????? *:指針運(yùn)算符(或稱“間接訪問(wèn)” 運(yùn)算符)。
- C語(yǔ)言中提供了地址運(yùn)算符&來(lái)表示變量的地址。
- 其一般形式為:
- &變量名;
- 如:
- int?? i,*p;
- P=&i;
- 其一般形式為:
- 注意
-
- #include"stdio.h"
- main1()????????? //錯(cuò)誤:運(yùn)行時(shí)出錯(cuò),P沒(méi)有指向明確的單元,p是隨機(jī)數(shù),非常危險(xiǎn),萬(wàn)一是重要地址
- {
- int *p;??????????? //解決方法 int k, *p = &k;??????????????????????? inta, *p; ?????? p = &a;是對(duì)的
- *p = 5;
- printf("%d\n", *p);
- }
- //*p=NULL是將p指向的內(nèi)存賦值為NUll,而p本身不會(huì)變
- //p=NULL是改變了p本身的值,將它指向的地址改為NULL,
- //所以在使用地址指針的時(shí)候出錯(cuò)的時(shí)候,都是將指針變量賦值為NULL的
-
- swap(int*p1, int *p2)?????????? //錯(cuò)誤,運(yùn)行報(bào)錯(cuò),指針變量在使用前必須賦值
- {
- int*p;?????????????????? // 和int *p;?? *p = 5;一個(gè)錯(cuò)誤 ,p指向不明確 ,即不知道5存在哪
- //? int k; p = &k; ??????? //改正
- *p =*p1;
- *p1= *p2;
- *p2= *p;
- }
- main2()
- {
- int a, b;
- int *ip1, *ip2;
- scanf("%d%d",&a, &b);
- ip1 = &a; ip2 = &b;
- if(a < b)
- swap(ip1,ip2);
- printf("%d %d\n", a, b);
- }
-
- main()?????????????????? //錯(cuò)的,指針類型不同,編譯報(bào)錯(cuò) [Error] cannot convert 'float*' to 'int*' in assignment
- {
- int*p;
- floatc;
- p =&c;
- }
-
- /*
- int a[5] = {1, 2, 3, 4, 5}, i; //a地址常量,數(shù)組首地址?? a[i]電腦存儲(chǔ)方式 *(a + i)
- int *p = a;
- 下標(biāo)法??????????????????????????????? 指針?lè)?/span>
- 第1個(gè)元素:
- 地址:??? a? ???????? ?p???????????????? ???? a?????????????????? p
- &a[0]????? &p[0]
- 內(nèi)容:??? a[0]? p[0] ????????????? *a????????????????? *p
- 第i個(gè)元素:
- 地址:??? &a[i]?????? &p[i]?????? ???? ????? a +i?????? p + i
- 內(nèi)容:??? a[i]?? p[i]??????????????? *a????????????????? *(p + i)
- */
-
- inta[10];
- printf("%p\n",&a); ????????????? //0xbff8dd44
- printf("%p\n",a); ? ?????????? //0xbff8dd44
- printf("%p\n",&a[0]); ????????? //0xbff8dd44
- printf("%p\n",&a[1]); ????????? //0xbff8dd48
-
- 指針變量中只能存放地址(指針),將一個(gè)整型變量(或任何其他非地址類型的數(shù)據(jù))賦給一個(gè)指針變量是不允許的。
- (三)指針變量作為函數(shù)參數(shù)
- 前面的章節(jié)中介紹過(guò),函數(shù)參數(shù)可以是整型、實(shí)型、字符型等數(shù)據(jù),指針類型數(shù)據(jù)同樣也可以作為函數(shù)參數(shù)來(lái)進(jìn)行傳遞。它的作用是將一個(gè)變量的地址傳送到另一個(gè)函數(shù)中,參與該函數(shù)的運(yùn)算。
- 如果想通過(guò)函數(shù)調(diào)用從而得到n個(gè)要改變的值,可以采用如下方法:
- (1)在主調(diào)函數(shù)中設(shè)n個(gè)變量,分別用n個(gè)指針變量指向它們。
- (2)然后將各個(gè)指針變量作為實(shí)參,即將這n個(gè)變量的地址傳給所調(diào)用的函數(shù)的形參。
- (3)通過(guò)形參指針變量的改變,從而改變這n個(gè)變量的值。
- (4)主調(diào)函數(shù)中就可以使用這些改變了值的變量。
- 形參指針變量的值的改變不能使實(shí)參指針變量的值發(fā)生改變。
- (一)指針變量的定義
- 2.4.3 數(shù)組與指針
- 一個(gè)數(shù)組包含若干個(gè)元素(變量),在定義時(shí)被分配了一段連續(xù)的內(nèi)存單元。因此,可以用一個(gè)指針變量來(lái)指向數(shù)組的首地址,通過(guò)該首地址就可以依次找到其他數(shù)組元素,同樣指針變量也可以指向數(shù)組中的某一個(gè)元素。所謂數(shù)組的指針是指數(shù)組的起始地址,數(shù)組元素的指針是各個(gè)數(shù)組元素的地址。
- (一)指向數(shù)組元素的指針
- C語(yǔ)言規(guī)定數(shù)組名代表數(shù)組的首地址,也就是數(shù)組中第0號(hào)元素的地址。有如下語(yǔ)句:
- int c[10]={0};
- int *p;
- p=c;
- 則語(yǔ)句p=c;與語(yǔ)句p=&c[0];是等價(jià)的。
- 數(shù)組c不代表整個(gè)數(shù)組。上述“p=c;“的作用是把數(shù)組c的首地址賦值給指針變量p,而不是把數(shù)組c中各元素的值賦給p。
- 定義指向數(shù)組元素的指針變量的方法,與定義指向變量的指針變量相同。例如:
- int c[10],*p;
- p=&c[5];
- 指針變量p指向了數(shù)組c中下標(biāo)為5的那個(gè)元素,即p用來(lái)保存c[5]的地址。
- C語(yǔ)言規(guī)定數(shù)組名代表數(shù)組的首地址,也就是數(shù)組中第0號(hào)元素的地址。有如下語(yǔ)句:
- (二)通過(guò)指針引用數(shù)組元素
- 按C語(yǔ)言的規(guī)定:如果指針變量p已指向數(shù)組中的一個(gè)元素,則p+1指向同一數(shù)組中的下一個(gè)元素(而不是將p的值簡(jiǎn)單加1),這里的加1是指增加一個(gè)長(zhǎng)度單位(與數(shù)組基類型所占存儲(chǔ)單元相同)。例如,數(shù)組元素是浮點(diǎn)型,每個(gè)元素占4個(gè)字節(jié),則p+1意味著使p的值(是一個(gè)地址)加4個(gè)字節(jié),以使它指向下一個(gè)元素。
- 將++和--運(yùn)算符用于指針變量是十分有效的,可以使用指針變量自動(dòng)向前或向后移動(dòng),指向下一個(gè)或上一個(gè)數(shù)組元素。不過(guò)要小心利用,否則會(huì)導(dǎo)致內(nèi)存錯(cuò)誤。
- (三)用數(shù)組名作為函數(shù)參數(shù)
- 數(shù)組名可以用做函數(shù)的形參和實(shí)參。當(dāng)數(shù)組名作為參數(shù)被傳遞時(shí),若形參數(shù)組中各元素發(fā)生了變化,則原實(shí)參數(shù)組各元素的值也隨之變化。因?yàn)閿?shù)組名作為實(shí)參時(shí),在調(diào)用函數(shù)時(shí)是把數(shù)組的首地址傳送給形參,因此實(shí)參數(shù)組與形參數(shù)組共占一段內(nèi)存單元。而如果用數(shù)組元素作為實(shí)參的情況就與用變量作為實(shí)參時(shí)一樣,是“值傳遞“方式,單向傳遞,即使形參數(shù)組元素值發(fā)生了變化,原實(shí)參的數(shù)組元素值也不會(huì)受影響。
- (四)指向多維數(shù)組的指針和指針變量
- 有如下定義:
- int c[3][4],*p;
- c是該二維數(shù)組的數(shù)組名,它代表了整個(gè)數(shù)組的首地址,也就是第0行的首地址,c+1代表第1行的首地址,即c+1是c[1]的地址。c[0]、c[1]、c[2]既然是一維數(shù)組名,而C語(yǔ)言又規(guī)定了數(shù)組名代表數(shù)組的首地址,因此c[0]代表第0行的一維數(shù)組中第0列元素的地址,即&c[0][0]。同樣地,c[1]的值是&c[1][0]。
- 第0行第1列元素的地址怎么表示呢?可以用c[0]+1來(lái)表示。此時(shí)“c[0]+1“中的1代表1個(gè)列元素的字節(jié)數(shù),即兩個(gè)字節(jié)。如c[0]的值是2020,則c[0]+1的值是2022。
- 根據(jù)上面的介紹,c[i]和*(c+i)等價(jià),因此,c[0]+1和*(c+0)+1的值都是&c[0][1],都是用來(lái)表示第0行第1列的元素的地址。c[i]從形式上看是數(shù)組c中第i個(gè)元素。如果c是二維數(shù)組名,則c[i]代表一維數(shù)組名,c[i]本身并不占實(shí)際的內(nèi)存單元,它也不存放數(shù)組中各個(gè)元素的值,它只是一個(gè)地址。c、c+i、c[i]、*(c+i)+j、c[i]+j都是地址,*(c[i]+j)、*(*(c+i)+j)是元素的值。
- 有如下定義:
- 2.4.5 字符串與指針
- (一)字符串的表示形式
- (1)用字符數(shù)組存放一個(gè)字符串,然后輸出該字符串。
- 例如:
- char str[]=“I am a student??“;
- printf(“%s\n“,str);
- 例如:
- (2)用字符指針指向一個(gè)字符串。
- 可以不定義數(shù)組,而定義一個(gè)字符指針,用字符指針指向字符串中的字符。
- 例如:
- char*str=“I am a student??“;
- /*定義str為指針變量,并指向字符串的首地址*/
- printf(“%s\n“,str);
- 在這里沒(méi)有使用字符數(shù)組,而是在程序中定義了一個(gè)字符指針變量str,并使該指針變量指向一個(gè)字符串的首地址。C語(yǔ)言對(duì)字符串常量是按字符數(shù)組進(jìn)行處理的,在內(nèi)存中開(kāi)辟了一個(gè)字符數(shù)組來(lái)存放字符串常量。程序在定義字符指針變量str時(shí),把字符串的首地址賦給str。str只能指向一個(gè)字符變量或其他字符類型數(shù)據(jù),不能同時(shí)指向多個(gè)字符數(shù)據(jù),更不能理解為把字符串中的全部字符存放到str中(指針變量只能存放地址)。在輸出時(shí),利用字符型指針str的移動(dòng)來(lái)控制輸出,直到遇到字符串結(jié)束標(biāo)志'\0'為止。
- 通過(guò)字符數(shù)組名或字符指針變量可以一次性輸出的只有字符數(shù)組(即字符串),而對(duì)一個(gè)數(shù)值型的數(shù)組,是不能企圖用數(shù)組名輸出它的全部元素的,只能借助于循環(huán)逐個(gè)輸出元素。
- 顯然,用%s可以控制對(duì)一個(gè)字符串進(jìn)行整體的輸入輸出。對(duì)字符串中字符的存取,與操作其他數(shù)組的方法相同,既可以用下標(biāo)方法,又可以用指針?lè)椒ā?/span>
- (1)用字符數(shù)組存放一個(gè)字符串,然后輸出該字符串。
- (二)字符串指針作函數(shù)參數(shù)
- 將一個(gè)字符串從一個(gè)函數(shù)傳遞到另一個(gè)函數(shù),可以用地址傳遞的辦法,即用字符數(shù)組名作為參數(shù)或用指向字符串的指針變量作為參數(shù),進(jìn)行傳遞。
- 字符串指針變量作為函數(shù)實(shí)參,形參可以是字符指針變量,同樣也可以是字符數(shù)組名。當(dāng)字符數(shù)組名作為函數(shù)實(shí)參時(shí),形參可以是字符數(shù)組名,同樣也可以是字符指針變量。
- (三)字符指針變量和字符數(shù)組的區(qū)別
- 雖然字符數(shù)組和字符指針變量都能實(shí)現(xiàn)對(duì)字符的存儲(chǔ)和運(yùn)算,但它們兩者之間有如下區(qū)別:
- (1)字符數(shù)組是由若干個(gè)元素組成的,每個(gè)元素中存放一個(gè)字符,而字符指針變量中存放的是地址(字符串的首地址),絕不是將字符串的內(nèi)容存放到字符指針變量中。
- (2)賦值方式。
- 只能對(duì)字符數(shù)組各個(gè)元素賦值,不能用以下方法對(duì)字符數(shù)組賦值:
- char str[20];
- str=“Iam happy“;
- 而對(duì)字符指針變量,可以采用以下方法賦值:
- char *s;
- s=“I amhappy??“;
- 只能對(duì)字符數(shù)組各個(gè)元素賦值,不能用以下方法對(duì)字符數(shù)組賦值:
- (3)字符數(shù)組可以在定義時(shí)對(duì)其整體賦初值(即初始化),但在賦值語(yǔ)句中不能完成整體賦值。下面的做法是不允許的:
- char s[30];
- s[]=“I am so happy“;
- 而字符指針變量既可以在定義時(shí)賦初值,也可以出現(xiàn)在賦值語(yǔ)句中,相對(duì)來(lái)說(shuō)要比字符數(shù)組使用起來(lái)靈活一點(diǎn)。
- (4)如果定義了一個(gè)字符數(shù)組,在編譯時(shí),系統(tǒng)會(huì)為它分配一段連續(xù)的內(nèi)存單元,它的地址是確定的。而當(dāng)定義了一個(gè)字符指針變量后,就要即時(shí)給該指針變量分配內(nèi)存單元,該指針變量中可以存放一個(gè)地址值,也就是說(shuō),該指針變量可以指向一個(gè)字符型數(shù)據(jù),但如果未對(duì)它賦以一個(gè)地址值,則它并未具體指向一個(gè)確定的字符數(shù)據(jù)。如:
- char s[10];
- scanf(“%s“,s);
- 是可以的。但用下面的方法是極其危險(xiǎn)的:
- char *s;
- scanf(“%s“,s);
- 因?yàn)榫幾g時(shí)雖然給指針變量s分配了內(nèi)存單元,s的地址(即&s)已經(jīng)指定了,但s的值并未指定。在s單元中是一個(gè)不可預(yù)料的值,在執(zhí)行scanf()函數(shù)時(shí)要求將一個(gè)字符串輸入到s所指向的一段內(nèi)存單元中,即以s的值(地址)開(kāi)始的一段內(nèi)存單元。而s的值如今卻是不可預(yù)料的,它可能指向內(nèi)存中空白的存儲(chǔ)區(qū)(未用的用戶存儲(chǔ)區(qū)),這樣固然可以,但它也有可能指向內(nèi)存中已存放指令或數(shù)據(jù)的有用內(nèi)存段。這就會(huì)破壞程序,甚至破壞系統(tǒng),造成嚴(yán)重的后果。應(yīng)當(dāng)這樣:
- char*a,s[10];
- a=s;
- scanf(“%s“,a);
- 先使a有確定值,也就是使a指向一個(gè)數(shù)組的首地址,然后輸入一個(gè)字符串,把它存放在以該地址開(kāi)始的若干單元中。
- (5)在程序中指針變量的值可以改變。例如:
- char*s=“china”;
- s=s+2;
- 指針變量s的值可以改變,當(dāng)要輸出字符串時(shí),從s當(dāng)前所指向的單元開(kāi)始輸出各個(gè)字符(本題中從字符i開(kāi)始輸出),直到遇到'\0'為止。而數(shù)組名雖然代表了地址,但它的值是一個(gè)固定的值,是不能改變的。下面是錯(cuò)的:
- char str[]={“china”};
- str=str+2;
- (一)字符串的表示形式
- 2.4.6? 指向函數(shù)的指針
- 用函數(shù)指針變量調(diào)用函數(shù)
- 我們已經(jīng)知道,可以用指針變量指向整型變量、字符型變量、字符串、數(shù)組,同樣指針變量也可以指向一個(gè)函數(shù)。編譯時(shí),一個(gè)函數(shù)將被分配給一個(gè)入口地址,這個(gè)入口地址就稱為該函數(shù)的指針。因此,可以通過(guò)使用一個(gè)指向函數(shù)的指針變量調(diào)用此函數(shù)。
- 說(shuō)明:
- (1)指向函數(shù)的指針變量的一般定義形式為:
- 數(shù)據(jù)類型 (*指針變量名)( );
- 如int(*s)();,“數(shù)據(jù)類型”指該函數(shù)返回值的類型。
- 數(shù)據(jù)類型 (*指針變量名)( );
- (2)(*s)()表示定義了一個(gè)指向函數(shù)的指針變量,但目前它不是固定指向哪一個(gè)函數(shù),而只是表示定義了這樣一個(gè)類型的變量,它的作用是專門(mén)用來(lái)存放函數(shù)的入口地址。在程序中實(shí)現(xiàn)把某一個(gè)函數(shù)的地址賦給它,它就指向那一個(gè)函數(shù),這樣它的值也就確定了。在一個(gè)程序中,一個(gè)指針變量以先后指向不同的函數(shù),也就是說(shuō)指向函數(shù)的指針變量和普通指針變量一樣,可以多次使用。
- (3)在給函數(shù)指針變量賦值時(shí),只需給出函數(shù)名而不必給出參數(shù)。如:
- s=fun;? /*? fun為已有定義的有參函數(shù)*/
- 因?yàn)槭菍⒑瘮?shù)入口地址賦給s,不涉及到參數(shù)的問(wèn)題,不能寫(xiě)成:
- s=fun(a,b);
- (4)用函數(shù)指針變量調(diào)用函數(shù)時(shí),只需將(*s)代替函數(shù)名即可(s為已經(jīng)定義過(guò)的指向函數(shù)的指針變量名),在(*s)之后的括號(hào)中根據(jù)需要寫(xiě)上實(shí)參。
- (5)對(duì)指向函數(shù)的指針變量,有些運(yùn)算,如++s、--s、s+3等都是沒(méi)有意義的。
- (1)指向函數(shù)的指針變量的一般定義形式為:
- 函數(shù)指針的用法(*f)()記住一個(gè)例子:
- intadd(int x, int y)
- {....}
- main()
- {int? (*f)();
- f=add;
- }
- 賦值之后:合法的調(diào)用形式為
- 1、add(2,3);
- 2、f(2,3);
- 3、(*f)(2,3)
- 用函數(shù)指針變量調(diào)用函數(shù)
- 2.4.7 返回指針的函數(shù)
- 返回指針值的函數(shù)
- 一個(gè)函數(shù)的返回值可以是一個(gè)整型值、字符型值、實(shí)型值等,同樣地,函數(shù)的返回值也可以是指針類型的數(shù)據(jù),即地址。這種返回指針值的函數(shù),一般定義形式為:
- 類型名??? *函數(shù)名(參數(shù)表);
- 例如:
- int*fun(int a,int b);
- fun是函數(shù)名,調(diào)用它可以得到一個(gè)指向整型數(shù)據(jù)的指針(地址)。a、b是兩個(gè)整形變量,是函數(shù)fun()的形參。注意:*fun在兩側(cè)沒(méi)有括弧,在fun的兩側(cè)分別為*運(yùn)算符和()運(yùn)算符。而()優(yōu)先級(jí)高于*,因此fun先與()結(jié)合,顯然這是函數(shù)形式。這個(gè)函數(shù)前面有一個(gè)*,表示此函數(shù)是指針型函數(shù)。
- 2.4.8 指針數(shù)組和指向指針的指針
- (一)指針數(shù)組的概念
- 若在一個(gè)數(shù)組中,其元素均為指針類型數(shù)據(jù),這樣的數(shù)組稱為指針數(shù)組,也就是說(shuō),指針數(shù)組中的每一個(gè)元素都相當(dāng)于一個(gè)指針變量。一維指針數(shù)組的定義形式為:
- 類型名? *數(shù)組名[數(shù)組長(zhǎng)度];
- 例如:
- int *a[10];
- 由于[]運(yùn)算符的優(yōu)先級(jí)比*運(yùn)算符的優(yōu)先級(jí)高,因此a先與[10]結(jié)合,形成a[10]形式,然后與前面的“*“結(jié)合,“*“表示此數(shù)組是指針類型的,每個(gè)數(shù)組元素都可指向一個(gè)整型變量。
- 指針數(shù)組的一個(gè)重要用途是可以用來(lái)指向若干個(gè)字符串。例如,在對(duì)庫(kù)房物品進(jìn)行管理時(shí),想把物品名稱放在一個(gè)數(shù)組中,然后對(duì)這些物品進(jìn)行統(tǒng)計(jì)和查詢,我們可以分別定義一些字符串來(lái)存放各物品名稱,然后利用指針數(shù)組中的元素分別指向各字符串。如果還想對(duì)字符串排序,不必改動(dòng)字符串的位置,只需改動(dòng)指針數(shù)組中各元素的指向(即改變各元素的值,這些值是各字符串的首地址)。這樣,各字符串的長(zhǎng)度可以不同,而且移動(dòng)指針變量的值(地址)要比移動(dòng)字符串所花的時(shí)間少。
- (二)指向指針的指針
- 指向指針數(shù)據(jù)的指針變量,簡(jiǎn)稱為指向指針的指針,通常稱為二級(jí)指針。定義一個(gè)指向指針數(shù)據(jù)的指針變量的形式:
- 類型名 **a;
- a前面有兩個(gè)“*“號(hào),*a是指針變量的定義形式,現(xiàn)在它前面又有一個(gè)“*“號(hào),表示指針變量是指向某種類型的指針變量的。
- 指向指針數(shù)據(jù)的指針變量,簡(jiǎn)稱為指向指針的指針,通常稱為二級(jí)指針。定義一個(gè)指向指針數(shù)據(jù)的指針變量的形式:
- (一)指針數(shù)組的概念
- 2.4.9 注意
- 二級(jí)指針和行指針區(qū)別
- #####################################################################################################################################################################################
- 指針變量的本質(zhì)是用來(lái)放地址,而一般的變量是放數(shù)值的
- int? *p 中?? *p和p的差別:
- *p可以當(dāng)做變量來(lái)用;*的作用是取后面地址p里面的數(shù)值
- p是當(dāng)作地址來(lái)使用。
- *p++ 和(*p)++的之間的差別:
- *p++是 地址會(huì)變化。
- (*p)++ 是數(shù)值會(huì)要變化。
- int? *p 中?? *p和p的差別:
- 三名主義:
- 數(shù)組名:表示第一個(gè)元素的地址。數(shù)組名不可以自加,他是地址常量名。
- 函數(shù)名:表示該函數(shù)的入口地址。
- 字符串常量名:表示第一個(gè)字符的地址。
- 指針變量是存放地址的。并且指向哪個(gè)就等價(jià)哪個(gè),所有出現(xiàn)*p的地方都可以用它等價(jià)的代替。
- 例如:int a=2,*p=&a;
- *p=*p+2;
- (由于*p指向變量a,所以指向哪個(gè)就等價(jià)哪個(gè),這里*p等價(jià)于a,可以相當(dāng)于是a=a+2)
- 指針變量?jī)煞N初始化
- 方法一:int a=2,*p=&a;(定義的同時(shí)初始化)
- 方法二:int a=2,*p; p=&a; (定義之后初始化)
- 二級(jí)指針和行指針區(qū)別
- 2.4.10 指針應(yīng)用--鏈表
- (一)鏈表的概念
- 鏈表是一種常見(jiàn)的重要的數(shù)據(jù)結(jié)構(gòu),它是動(dòng)態(tài)地進(jìn)行存儲(chǔ)單元分配的一種結(jié)構(gòu)。
- 鏈表中的各元素在內(nèi)存中不一定是連續(xù)存放的。要找鏈表中某一元素,必須先找到上一個(gè)元素,根據(jù)該元素提供的下一元素的地址才能找到下一個(gè)元素。所以,如果沒(méi)有頭指針(head),則整個(gè)鏈表都無(wú)法訪問(wèn)。另外一點(diǎn),這種鏈表的數(shù)據(jù)結(jié)構(gòu),必須利用指針變量才能實(shí)現(xiàn)。即一個(gè)節(jié)點(diǎn)中應(yīng)包含一個(gè)指針變量,用它存放下一節(jié)點(diǎn)的地址。當(dāng)然也可以不通過(guò)指針變量,用其他方式也可以構(gòu)建簡(jiǎn)單鏈表,請(qǐng)參考有關(guān)數(shù)據(jù)結(jié)構(gòu)的教材。
- 下面通過(guò)一個(gè)例子來(lái)說(shuō)明如何建立和輸出一個(gè)簡(jiǎn)單鏈表。
- #include<stdio.h>
- #include<string.h>
- structnode
- {
- int data;
- struct node *next;
- };
- typedefstruct node NODETYPE;
- main()
- {
- NODETYPE s1,s2,s3,*begin,*p;
- s1.data=100;/*給變量中的data域賦值*/
- s2.data=200;
- s3.data=300;
- begin=&s1;
- s1.next=&s2;/*使s1的域next指向s2*/
- s2.next=&s3;
- s3.next='\0';
- p=begin;/*移動(dòng)p,使之依次指向s1、s2、s3,輸出它們data域中的值*/
- while(p)
- {
- printf("%d",p->data);
- p=p->next;?? /* p順序后移 */
- }
- printf("\n");
- }
- main()函數(shù)中定義的變量s1、s2、s3都是結(jié)構(gòu)體變量,它們都含有data和next兩個(gè)成員。變量begin和p是指向NODETYPE結(jié)構(gòu)體類型的指針變量,它們與結(jié)構(gòu)體變量s1、s2、s3中的成員變量next類型相同。執(zhí)行賦值語(yǔ)句后,begin中存放s1變量的地址,變量s1的成員s1->next中存放變量s2的地址……最后一個(gè)變量s3的成員s3->next置成'\0'(NULL),從而把同一類型的結(jié)構(gòu)體變量s1、s2、s3“鏈接”到一起,形成“鏈表”。
- 在此例中,鏈接到一起的每個(gè)節(jié)點(diǎn)(結(jié)構(gòu)體變量s1、s2、s3)都是通過(guò)定義,由系統(tǒng)在內(nèi)存中開(kāi)辟了固定的存儲(chǔ)單元(不一定連續(xù))。在程序執(zhí)行的過(guò)程中,不可能人為地再產(chǎn)生新的存儲(chǔ)單元,也不可能人為地使已開(kāi)辟的存儲(chǔ)單元消失。從這一角度出發(fā),可稱這種鏈表為“靜態(tài)鏈表“。在實(shí)際中,使用更廣泛的是一種“動(dòng)態(tài)鏈表”。
- (二)建立動(dòng)態(tài)鏈表(主要針對(duì)單向鏈表)
- 建立單向鏈表的主要步驟如下:
- (1)讀取數(shù)據(jù)。
- (2)生成新節(jié)點(diǎn)。
- (3)將數(shù)據(jù)存入節(jié)點(diǎn)的成員變量中。
- (4)將新節(jié)點(diǎn)插入到鏈表中,重復(fù)上述操作直至輸入結(jié)束。
- 編寫(xiě)函數(shù)creatlist(),建立帶有頭節(jié)點(diǎn)的單向鏈表。節(jié)點(diǎn)數(shù)據(jù)域中的數(shù)值從鍵盤(pán)輸入,以-1作為輸入結(jié)束標(biāo)志。鏈表的頭節(jié)點(diǎn)的地址由函數(shù)值返回。
- 我們?cè)诤瘮?shù)中定義了一個(gè)名為begin的指針變量,用于存放頭節(jié)點(diǎn)的地址,另外還定義了兩個(gè)工作指針:current和end。其中指針current用來(lái)指向新生成的節(jié)點(diǎn),指針end總是指向鏈表當(dāng)前的尾節(jié)點(diǎn)。每當(dāng)把current所指的新開(kāi)辟的節(jié)點(diǎn)連接到表尾后,end便移向這一新的表尾節(jié)點(diǎn)。這時(shí)又可以用current去指向下一個(gè)新開(kāi)辟的節(jié)點(diǎn)。鏈表最后一個(gè)節(jié)點(diǎn)的指針域中置'\0'(NULL值)作為單向鏈表的結(jié)束標(biāo)志。
- 鏈表建成后,頭節(jié)點(diǎn)的地址由creatlist()返回,賦給main()函數(shù)中的指針變量head。函數(shù)如下:
- #include<stdio.h>
- #include<string.h>
- #include<stdlib.h>
- structnode
- {
- int data;
- structnode *next;
- };
- typedefstruct node NODETYPE;
- NODETYPE*creatlist()
- {
- int i;
- NODETYPE *begin,*end,*current;
- begin=(NODETYPE*)malloc(sizeof(NODETYPE));/*生成頭節(jié)點(diǎn)*/
- end=begin;
- scanf("%d",&i);/*輸入數(shù)據(jù)*/
- while(i!=-1)/*未讀到數(shù)據(jù)結(jié)束標(biāo)志時(shí)進(jìn)入循環(huán)*/
- {
- current=(NODETYPE*)malloc(sizeof(NODETYPE));/*生成一個(gè)新節(jié)點(diǎn)*/
- current->data=i;/*讀入的數(shù)據(jù)存入新節(jié)點(diǎn)的data域*/
- end->next=current;/*新節(jié)點(diǎn)連到表尾*/
- end=current;/*end指向當(dāng)前表尾*/
- scanf("%d",&i);/*讀入數(shù)據(jù)*/
- }
- end->next='\0';/*置鏈表結(jié)束標(biāo)志*/
- return begin;/*返回表頭指針*/
- }
- main()
- {
- NODETYPE *head;
- head=creatlist();/*調(diào)用鏈表建立函數(shù),得到頭節(jié)點(diǎn)的地址*/
- }
- 以上creatlist()函數(shù)中,當(dāng)一開(kāi)始輸入-1時(shí),并不進(jìn)入while循環(huán),而直接執(zhí)行循環(huán)之后的end->next='\0';語(yǔ)句,這時(shí)建立的是一個(gè)“空鏈表“。由此可見(jiàn),可用條件begin->next=='\0'來(lái)判斷鏈表是否為空。
- 建立單向鏈表的主要步驟如下:
- (三)順序訪問(wèn)鏈表中各節(jié)點(diǎn)的數(shù)據(jù)域
- 所謂“訪問(wèn)“,可以理解為取各節(jié)點(diǎn)的數(shù)據(jù)域中的值進(jìn)行各種運(yùn)算、修改各節(jié)點(diǎn)的數(shù)據(jù)域中的值等一系列的操作。
- 輸出單向鏈表各節(jié)點(diǎn)數(shù)據(jù)域中內(nèi)容的算法比較簡(jiǎn)單,只需利用一個(gè)工作指針(p),從頭到尾依次指向鏈表中的每個(gè)節(jié)點(diǎn),當(dāng)指針指向某個(gè)節(jié)點(diǎn)時(shí),就輸出該節(jié)點(diǎn)數(shù)據(jù)域中的內(nèi)容,直到遇到鏈表結(jié)束標(biāo)志為止。如果是空鏈表,就只輸出提示信息并返回調(diào)用函數(shù)。
- 函數(shù)如下:
- voidprintlist(NODETYPE *head)
- {
- NODETYPE*p;
- p=head->next;/*指向頭節(jié)點(diǎn)后的第一個(gè)節(jié)點(diǎn)*/
- if(p=='\0')/*鏈表為空時(shí)*/
- printf(“Linklistis null\n”);
- else/*鏈表不為空時(shí)*/
- {
- printf(“head”);
- do
- {
- printf(“->%d”,p->data);/*輸出當(dāng)前節(jié)點(diǎn)數(shù)據(jù)域中的值*/
- p=p->next;/*move指向下一個(gè)節(jié)點(diǎn)*/
- }while(p!=′\0′);/*未到鏈表尾,繼續(xù)循環(huán)下去*/
- }
- printf(“->end\n”);
- }
- (四)在鏈表中插入節(jié)點(diǎn)
- 在單向鏈表中插入節(jié)點(diǎn),首先要確定插入的位置插入節(jié)點(diǎn)在指針p所指的節(jié)點(diǎn)之前稱為“前插“,插入節(jié)點(diǎn)在指針p所指的節(jié)點(diǎn)之后稱為“后插“。“前插“操作中各指針的指向
- 當(dāng)進(jìn)行前插操作時(shí),需要3個(gè)工作指針:s指向新開(kāi)辟的節(jié)點(diǎn),用p指向插入的位置,q指向要插入的前趨節(jié)點(diǎn)。
- (五)刪除鏈表中的節(jié)點(diǎn)
- 為了刪除單向鏈表中的某個(gè)節(jié)點(diǎn),首先要找到待刪除的節(jié)點(diǎn)的前趨節(jié)點(diǎn)(即當(dāng)前要?jiǎng)h除節(jié)點(diǎn)的前面一個(gè)節(jié)點(diǎn)),然后將此前趨節(jié)點(diǎn)的指針域去指向待刪除節(jié)點(diǎn)的后續(xù)節(jié)點(diǎn)(即當(dāng)前要?jiǎng)h除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)),最后釋放被刪除節(jié)點(diǎn)所占的存儲(chǔ)空間即可。
- (一)鏈表的概念
- 2.4.1 關(guān)于地址和指針
- 2.5用typedef說(shuō)明一種新類型名
- C語(yǔ)言可以用typedef說(shuō)明一種新類型名,說(shuō)明新類型名的語(yǔ)句一般形式為:
- typedef?? 類型名??? 標(biāo)識(shí)符;
- 其中,“類型名“一定是在此語(yǔ)句之前已有定義的類型標(biāo)識(shí)符。“標(biāo)識(shí)符“是一個(gè)用戶定義標(biāo)識(shí)符,用來(lái)標(biāo)識(shí)新的類型名。typedef語(yǔ)句的作用僅僅是用“標(biāo)識(shí)符“來(lái)代表已存在的“類型名“,并沒(méi)有產(chǎn)生新的數(shù)據(jù)類型,因此,原有的類型名依然有效。
- 聲明一個(gè)新的類型名的具體步驟如下:
- (1)先按定義變量的方法寫(xiě)出定義的主體(如float a;)。
- (2)將變量名換成新類型名(如將a換成FLO)。
- (3)在最左面加上關(guān)鍵字typedef(如 typedef? float FLO;)。
- (4)然后可以用新類型名去定義其他的變量(如FLO? b;)。
- C語(yǔ)言可以用typedef說(shuō)明一種新類型名,說(shuō)明新類型名的語(yǔ)句一般形式為:
- 2.6 sizeof()計(jì)算實(shí)際所占字節(jié)數(shù)
- 概念
- sizeof是C語(yǔ)言的一種單目操作符,如C語(yǔ)言的其他操作符++、--等。它并不是函數(shù)。sizeof操作符以字節(jié)形式給出了其操作數(shù)的存儲(chǔ)大小。操作數(shù)可以是一個(gè)表達(dá)式或括在括號(hào)內(nèi)的類型名。操作數(shù)的存儲(chǔ)大小由操作數(shù)的類型決定。作用就是返回一個(gè)對(duì)象或者類型所占的內(nèi)存字節(jié)數(shù)。
- 2.6.1語(yǔ)法
- sizeof有三種語(yǔ)法形式,如下:
- 1) sizeof( object ); // sizeof( 對(duì)象 );
- 2) sizeof( type_name ); // sizeof( 類型 );
- 3) sizeof object; // sizeof 對(duì)象;
- 舉例
- sizeof(int); ???//64位 4
- int a=3; sizeof(a);????? //64位 4?? 建議使用此方法
- sizeof(3); ?//64位 4
- sizeof 3???? //64位4??? 是對(duì)的,不建議使用
- sizeof int???? //Error
- sizeof有三種語(yǔ)法形式,如下:
- 2.6.2數(shù)組
- 數(shù)組的sizeof值等于數(shù)組所占用的內(nèi)存字節(jié)數(shù),如:
- char a1[] = "abc"; sizeof( a1 ); // 結(jié)果為4,字符末尾還存在一個(gè)NULL終止符
- int a2[3]; sizeof( a2 ); // 結(jié)果為3*4=12(依賴于int)
- sizeof不是求數(shù)組元素的個(gè)數(shù),求數(shù)組元素的個(gè)數(shù),通常有下面兩種寫(xiě)法:
- int c1 = sizeof( a1 ) / sizeof( char ); // 總長(zhǎng)度/單個(gè)元素的長(zhǎng)度
- int c2 = sizeof( a1 ) / sizeof( a1[0] ); // 總長(zhǎng)度/第一個(gè)元素的長(zhǎng)度
- 舉例
- char array[8] = “China”; sizeof(array)?//64位 8??? 數(shù)組實(shí)際長(zhǎng)度
- sizeof(“hi”); ?//64位 3
- char a[5]="CHINA"; ??printf("%d",sizeof(a));??? //64位 5
- char a[5]="CHINAA"; ?printf("%d", sizeof(a));??? //64位 警告 結(jié)果5
- int a[3]; sizeof(a);??//64位 3*4=12??????????????? 數(shù)組實(shí)際長(zhǎng)度,整形一個(gè)元素4個(gè)字節(jié)
- 數(shù)組的sizeof值等于數(shù)組所占用的內(nèi)存字節(jié)數(shù),如:
- 2.6.3字符
- sizeof(char) ???//64位 1 s 字符型變量是1字節(jié)
- sizeof(‘s’) ????//64位 4???? ‘s’轉(zhuǎn)換為一個(gè)數(shù),數(shù)占四個(gè)字節(jié)
- sizeof(‘\101’) ????//64位 4???? ‘\101’為一個(gè)數(shù),數(shù)占四個(gè)字節(jié)
- ‘A’? =? ‘\101’?=? ‘\x41’? =? 65
- char c;? sizeof(c)???????????? //64位 1
- C和C++比較
- C語(yǔ)言環(huán)境下:
- char a = 'a' ;
- sizeof(char) = 1 ;
- sizeof(a) = 1 ;
- sizeof('a') =4? ;
- C++語(yǔ)言環(huán)境下:
- char a = 'a';
- sizeof(char) = 1;
- sizeof(a) = 1 ;
- sizeof('a') =1;
- 字符型變量是1字節(jié)這個(gè)沒(méi)錯(cuò),奇怪就奇怪在C語(yǔ)言認(rèn)為'a'是4字節(jié),而C++語(yǔ)言認(rèn)為'a'是1字節(jié)。
- 原因如下:
- C99標(biāo)準(zhǔn)的規(guī)定,'a'叫做整型字符常量(integer? character constant),被看成是int型,所以在32位機(jī)器上占4字節(jié)。
- ISO C++標(biāo)準(zhǔn)規(guī)定,'a'叫做字符字面量(character literal),被看成是char型,所以占1字節(jié)
- 字符是指計(jì)算機(jī)中使用的字母、數(shù)字、字和符號(hào)。1個(gè)漢字字符存儲(chǔ)需要2個(gè)字節(jié),1個(gè)英文字符存儲(chǔ)需要1個(gè)字節(jié)。ASCII是一個(gè)字節(jié),Unicode是兩個(gè)字節(jié)。Java的字符是Unicode的,所以是兩個(gè)字節(jié)。
- C語(yǔ)言環(huán)境下:
- 2.6.4結(jié)構(gòu)體
- 1.對(duì)齊
- structS1
- {
- char c;
- int i;
- };
- sizeof(s1)為8,字節(jié)對(duì)齊,有助于加快計(jì)算機(jī)的取數(shù)速度,否則就得多花指令周期了。為此,編譯器默認(rèn)會(huì)對(duì)結(jié)構(gòu)體進(jìn)行處理(實(shí)際上其它地方的數(shù)據(jù)變量也是如此),讓寬度為2的基本數(shù)據(jù)類型(short等)都位于能被2整除的地址上,讓寬度為4的基本數(shù)據(jù)類型(int等)都位于能被4整除的地址上,以此類推。這樣,兩個(gè)數(shù)中間就可能需要加入填充字節(jié),所以整個(gè)結(jié)構(gòu)體的sizeof值就增長(zhǎng)了。
- 2.字節(jié)對(duì)齊的細(xì)節(jié)和編譯器實(shí)現(xiàn)相關(guān),但一般而言,滿足三個(gè)準(zhǔn)則:
- 1) 結(jié)構(gòu)體變量的首地址能夠被其最寬基本類型成員的大小所整除;
- 2) 結(jié)構(gòu)體每個(gè)成員相對(duì)于結(jié)構(gòu)體首地址的偏移量(offset)都是成員大小的整數(shù)倍,如有需要編譯器會(huì)在成員之間加上填充字節(jié)(internaladding);
- 3) 結(jié)構(gòu)體的總大小為結(jié)構(gòu)體最寬基本類型成員大小的整數(shù)倍,如有需要編譯器會(huì)在最末一個(gè)成員之后加上填充字節(jié)(trailing padding)。
- 舉例
- struct S3 整除4 一共3*4=12 測(cè)試###############################################################################################################################################################################
- {
- char c1; 整除1
- S1 s; 整除4
- structS1
- {
- char c;
- int i;
- };
- char c2 整除1
- };
- S1的最寬簡(jiǎn)單成員的類型為int,S3在考慮最寬簡(jiǎn)單類型成員時(shí)是將S1“打散”看的,所以S3的最寬簡(jiǎn)單類型為int,這樣,通過(guò)S3定義的變量,其存儲(chǔ)空間首地址需要被4整除,整個(gè)sizeof(S3)的值也應(yīng)該被4整除。
- 3.“空結(jié)構(gòu)體”(不含數(shù)據(jù)成員)的大小不為0,而是1。試想一個(gè)“不占空間”的變量如何被取地址、兩個(gè)不同的“空結(jié)構(gòu)體”變量又如何得以區(qū)分呢于是,“空結(jié)構(gòu)體”變量也得被存儲(chǔ),這樣編譯器也就只能為其分配一個(gè)字節(jié)的空間用于占位了。如下:
- structS5 { };
- sizeof(S5 ); // 結(jié)果為1
- 1.對(duì)齊
- 2.6.5聯(lián)合體
- 結(jié)構(gòu)體在內(nèi)存組織上是順序式的,聯(lián)合體則是重疊式,各成員共享一段內(nèi)存,所以整個(gè)聯(lián)合體的sizeof也就是每個(gè)成員sizeof的最大值。結(jié)構(gòu)體的成員也可以是復(fù)合類型,這里,復(fù)合類型成員是被作為整體考慮的。
- 所以,下面例子中,U的sizeof值等于sizeof(s)。
- structS1
- {
- char f1;
- int f2;
- char*f3;
- };
- union U
- {
- int i;
- char c;
- S1 s;
- };
- 2.6.6表達(dá)式和調(diào)用函數(shù)
- sizeof可以對(duì)一個(gè)表達(dá)式求值,編譯器根據(jù)表達(dá)式的最終結(jié)果類型來(lái)確定大小,一般不會(huì)對(duì)表達(dá)式進(jìn)行計(jì)算
- 1.# include <stdio.h>
- int main()
- {
- int i;
- i = 10;
- printf("i : %d\n",i);
- printf("sizeof(i++) is: %d\n",sizeof(++i));
- printf("i : %d\n",i);
- return 0;
- }
- 結(jié)果:i : 10
- sizeof(i++) is: 4i : 10
- 2.????chara="255";printf("%d",sizeof(a++));
- /*打印的值是1,這一步并不對(duì)表達(dá)式a++進(jìn)行計(jì)算,所以char a="255"*/
- 3.?????sizeof( 2 + 3.14 );
- // 3.14的類型為double,2也會(huì)被提升成double類型,所以等價(jià)于 sizeof( double );但是不計(jì)算,相當(dāng)于比較里面最大類型##########################測(cè)試#################sizeof(i=2+3.14)###########################################################################
- sizeof也可以對(duì)一個(gè)函數(shù)調(diào)用求值,其結(jié)果是函數(shù)返回類型的大小,函數(shù)并不會(huì)被調(diào)用,我們來(lái)看一個(gè)完整的例子:
- charfoo()
- {
- printf("foo()has been called.\n");
- return'a';
- }
- intmain()
- {
- size_tsz = sizeof( foo() );
- /*foo() 的返回值類型為char,所以sz = sizeof(char ),foo()并不會(huì)被調(diào)用*/
- printf("sizeof(foo() ) = %d\n", sz);
- }
- sizeof可以對(duì)一個(gè)表達(dá)式求值,編譯器根據(jù)表達(dá)式的最終結(jié)果類型來(lái)確定大小,一般不會(huì)對(duì)表達(dá)式進(jìn)行計(jì)算
- 2.6.7 不可用
- C99標(biāo)準(zhǔn)規(guī)定,函數(shù)、不能確定類型的表達(dá)式以及位域(bit-field)成員不能被計(jì)算sizeof值,即sizeof操作符不能用于函數(shù)類型,不完全類型或位字段。不完全類型指具有未知存儲(chǔ)大小的數(shù)據(jù)類型,如未知存儲(chǔ)大小的數(shù)組類型、未知內(nèi)容的結(jié)構(gòu)或聯(lián)合類型、void類型等。下面這些寫(xiě)法都是錯(cuò)誤的:
- 1. sizeof(foo );? // error
- 2. void foo2() { } sizeof(foo2() );? // error
- 3. struct S
- {
- unsignedint f1 : 1;? // error 屬于位字段
- unsignedint f2 : 5;
- unsignedint f3 : 12;
- };
- sizeof(S.f1 );? // error
- C99標(biāo)準(zhǔn)規(guī)定,函數(shù)、不能確定類型的表達(dá)式以及位域(bit-field)成員不能被計(jì)算sizeof值,即sizeof操作符不能用于函數(shù)類型,不完全類型或位字段。不完全類型指具有未知存儲(chǔ)大小的數(shù)據(jù)類型,如未知存儲(chǔ)大小的數(shù)組類型、未知內(nèi)容的結(jié)構(gòu)或聯(lián)合類型、void類型等。下面這些寫(xiě)法都是錯(cuò)誤的:
- 2.6.8 sizeof的常量性
- sizeof的計(jì)算發(fā)生在編譯時(shí)刻,所以它可以被當(dāng)作常量表達(dá)式使用,如:
- charary[ sizeof( int ) * 10 ]; // ok
- 最新的C99標(biāo)準(zhǔn)規(guī)定sizeof也可以在運(yùn)行時(shí)刻進(jìn)行計(jì)算,如下面的程序在Dev-C++中可以正確執(zhí)行:
- int n;
- n = 10;// n動(dòng)態(tài)賦值
- charary[n]; // C99也支持?jǐn)?shù)組的動(dòng)態(tài)定義
- printf("%d\n",sizeof(ary)); // ok. 輸出10
- 但在沒(méi)有完全實(shí)現(xiàn)C99標(biāo)準(zhǔn)的編譯器中就行不通了,上面的代碼在VC6中就通不過(guò)編譯。所以我們最好還是認(rèn)為sizeof是在編譯期執(zhí)行的,這樣不會(huì)帶來(lái)錯(cuò)誤,讓程序的可移植性強(qiáng)些。
- sizeof的計(jì)算發(fā)生在編譯時(shí)刻,所以它可以被當(dāng)作常量表達(dá)式使用,如:
- 概念
轉(zhuǎn)載于:https://www.cnblogs.com/ZanderZhao/p/10013860.html
總結(jié)
以上是生活随笔為你收集整理的3012C语言_数据的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Python自动生成10000个java
- 下一篇: 阿里云ACE共创空间——大数据方案体验1