- 相關(guān)推薦
c語言重點知識點總結(jié)
上學(xué)的時候,說起知識點,應(yīng)該沒有人不熟悉吧?知識點是指某個模塊知識的重點、核心內(nèi)容、關(guān)鍵部分。還在苦惱沒有知識點總結(jié)嗎?下面是小編幫大家整理的c語言重點知識點總結(jié),歡迎大家分享。
c語言重點知識點總結(jié) 1
◆知識點1:交換兩個變量值的方法
1)采用第三方變量(最容易想到的方法)
2)采用加減法進行值得交換(面試時常用**)
代碼如下:
b = a - b;
a = a - b;
b = a + b;
3)采用按位異或的位方式
代碼如下:
a = a^b;
b = a^b;
a = a^b;
◆知識點2:取語言重點知識點總結(jié)余運算%的結(jié)果與被除的符號相同,結(jié)果為兩個正數(shù)取余后前面加符號
◆知識點3:sizeof的使用
sizeof是一種運算符不要想當然理解為函數(shù)
sizeof使用時可以不加()
sizeof可以加變量、常量、數(shù)據(jù)類型
跟數(shù)據(jù)類型是必須加()
◆知識點4:static和 extern區(qū)別是能否進行跨文件訪問
、俸瘮(shù)
②變量
1、對函數(shù)的作用:
外部函數(shù):定義的函數(shù)能被本文件和其他文件訪問
內(nèi)部函數(shù):定義的函數(shù)只能被本文件訪問
默認情況下,所有函數(shù)都是外部函數(shù)(相當于帶關(guān)鍵字extern),所以可以省略
extern作用:
完整的定義和引用一個外部函數(shù)都加extern
引用時也是默認是外部函數(shù)所以也省略extern
static作用:定義一個內(nèi)部函數(shù)
使用:static返回類型函數(shù)名(參數(shù)列表)
不能被其他文件調(diào)用
一個項目中,本文件的外部函數(shù)名不能和其他文件的外部函數(shù)同名(error)
本文件中的.內(nèi)部函數(shù)(static)可以和其他文件的函數(shù)名同名的
2、對變量的作用:
全局變量分為兩種:
外部變量:定義的變量可以被其他文件訪問
、倌J情況下所有的全局變量都是外部變量
、诓煌募械耐獠孔兞慷即硗粋
、鄱x一個外部變量不加extern,聲明才加extern
同樣的聲明是沒有錯誤的
內(nèi)部變量:定義的變量不能被其他文件訪問
不同文件的同名內(nèi)部變量互不影響
◆知識點5:數(shù)組的幾種初始化方式如下:
int a[3] = {10, 9, 6};
int a[3] = {10,9};
int a[] = {11, 7, 6};
int a[4] = {[1]=11,[0] = 7};(知道有此種初始化方式即可)
◆知識點6:數(shù)組的內(nèi)存分析和注意點
存儲空間的劃分(內(nèi)存的分配是從高地址到低地址進行的,但一個數(shù)組內(nèi)部元素又是從低到高進行的)【注:對于以后學(xué)習(xí)重要】
數(shù)組名的作用,查看元素地址
注意數(shù)組不要越界
◆知識點7:字符串知識點
"123”其實是由’1’、’2’、’3’、’’組成
字符串的輸出”%s”,’’是不會輸出的
◆知識點8 : 字符串處理函數(shù):strlen()
計算的是字符數(shù),不是字數(shù)
計算的字符不包括’’,一個漢字相當于3個字符
例子:"哈haha" 字符數(shù)為7
從某個地址開始的數(shù)字符個數(shù),知道遇到’’為止
指針部分在C語言中占據(jù)重要地位,所以重點學(xué)習(xí)與整理了指針的知識:
◆知識點9:指針定義的格式
變量類型 *變量名
如:Int *p
◆知識點10:指針作用
能夠根據(jù)一個地址值,訪問對應(yīng)的存儲空間
例:
Int *p;
Int a = 90;
P = &a;
*p = 10;//把10賦值給p所指的存儲空間
◆知識點11:指針使用注意
Int *p只能指向int類型的數(shù)據(jù)
指針變量只能存儲地址
指針變量未經(jīng)初始化不要拿來間接訪問其他存儲空間
◆知識點12:指針與數(shù)組
遍歷數(shù)組
int ages[5] = {10, 4, 9, 44, 99};
for(int i = 0; i<5; i++)
{
printf("%d ", ages[i]);
}
使用指針遍歷數(shù)組:
int *p;
// 指針變量P指向了數(shù)組的首地址
p = &ages[0];
// 使用指針遍歷數(shù)組
for(int i = 0; i<5; I++)
{
printf("ages[%d] = %d ", i, *(p + i));
}
注:指針+ 1取決于指針的類型
注:數(shù)組的訪問方式
數(shù)組名[下標]
指針變量名[下標]
*(p + i)
◆知識點12:指針與字符串
定義字符串的兩種方式:
1、利用數(shù)組
Char name[] = “Andyzhao”
特點:字符串里的字符可以修改
適用場合:字符串內(nèi)容需要經(jīng)常修改
2、利用指針
Char *name = “itcast”
特點:字符串是一個常量,字符串里面的字符不能修改
使用場合:字符串的內(nèi)容不需要修改,而這個字符串經(jīng)常使用
◆知識點13:預(yù)處理指令(三種):
宏定義
條件編譯
文件包含
1、宏定義的配對使用和帶參數(shù)的宏:
#define
#undef
帶參數(shù)的宏:
#define sum(v1,v2) ((v1) + (v2))//括號是必須的
例如:
#define pingfang(a) a*a
#define pingfang(a) (a*a)
調(diào)用時
pingfang(10)/pingfang(2)//不正確
pingfang(5+5)//不正確
帶參數(shù)的宏效率比函數(shù)高
2、條件編譯(一般是判斷宏的值)
#if 條件
#elif 條件
#else
#endif(非常重要)不然后面的代碼全部無效
3、文件包含:
<>表示系統(tǒng)自帶的文件,""表示自定義文件
不允許循環(huán)包含,比如ah包含bh,bh又包含ah
◆知識點14:typedef 只是給類型起了個別名并不是定義新類型
struct Student{
int age;
char *name;
};
typedef struct Student Student;
等價于
typedef struct Student{
int age;
char *name;
}Student;
也等價于
typedef struct {
int age;
char *name;
}Student;
類似的給枚舉類型起名
typedef enum Sex
{
Man,Women
}Sex;
下面這種情況的寫法比較特殊
//下面是函數(shù)指針類型的自定義數(shù)據(jù)類型,返回值類型和參數(shù)類型要匹配
#include
typedef int (*TypeFuncPointer)(int, int);
int add(int a, intb)
{
return a + b;
}
int minus(int a, intb)
{
return a - b;
}
int main()
{
TypeFuncPointer p = add;//使用自定義類型
TypeFuncPointer p2 = minus;//使用自定義類型
printf("add = %d ",p(1, 2));
printf("minus = %d ",p2(1, 2));
return 0;
}
下面是定義結(jié)構(gòu)體的指針類型
typedef struct Student{
int age;
char *name;
}*PtrStu;
//使用方式
Student stu ={18, "zhangsan"};
PtrStu p = &stu;
宏定義也是可以為類型起名的
#define Integer int
相當于
typedef int Integer
注意和typedef的區(qū)別
例如:
typedef char * String
#define String2char *
c語言重點知識點總結(jié) 2
C語言位運算基礎(chǔ)知識
1、程序中的所有數(shù)在計算機內(nèi)存中都是以二進制的形式儲存的。位運算說穿了,就是直接對整數(shù)在內(nèi)存中的二進制位進行操作。
2、與運算:只有前后兩個運算數(shù)都是 1 的時候結(jié)果才是1。
3、或運算:有1位為1,結(jié)果便為1。
4、異或:不相同則為1。
5、取反運算:將1變?yōu)?,將0變?yōu)?。
6、移位運算:左移則乘2,右移則除2。如果超出邊界,則舍棄。
c語言入門知識:位運算
一、位運算符
在計算機中,數(shù)據(jù)都是以二進制數(shù)形式存放的,位運算就是指對存儲單元中二進制位的運算。C語言提供6種位運算符。
二、位運算
位運算符 & |~<< >> ∧ 按優(yōu)先級從高到低排列的順序是:
位運算符中求反運算“~“優(yōu)先級最高,而左移和右移相同,居于第二,接下來的順序是按位與 “&“、按位異或 “∧“和按位或 “|“。順序為~ << >> & ∧ | 。
例1:左移運算符“<<”是雙目運算符。其功能把“<< ”左邊的運算數(shù)的各二進位全部左移若干位,由“<<”右邊的數(shù)指定移動的位數(shù),高位丟棄,低位補0。
例如:
a<<4
指把a的各二進位向左移動4位。如a=00000011(十進制3),左移4位后為00110000(十進制48)。
例2:右移運算符“>>”是雙目運算符。其功能是把“>> ”左邊的運算數(shù)的'各二進位全部右移若干位,“>>”右邊的數(shù)指定移動的位數(shù)。
例如:
設(shè) a=15,a>>2
表示把000001111右移為00000011(十進制3)。
應(yīng)該說明的是,對于有符號數(shù),在右移時,符號位將隨同移動。當為正數(shù)時,最高位補0,而為負數(shù)時,符號位為1,最高位是補0或是補1 取決于編譯系統(tǒng)的規(guī)定。
例3:設(shè)二進制數(shù)a是00101101 ,若通過異或運算a∧b 使a的高4位取反,低4位不變,則二進制數(shù)b是。
解析:異或運算常用來使特定位翻轉(zhuǎn),只要使需翻轉(zhuǎn)的位與1進行異或操作就可以了,因為原數(shù)中值為1的位與1進行異或運算得0 ,原數(shù)中值為0的位與1進行異或運算結(jié)果得1。而與0進行異或的位將保持原值。異或運算還可用來交換兩個值,不用臨時變量。
如 int a=3 , b=4;,想將a與b的值互換,可用如下語句實現(xiàn):
a=a∧b;
b=b∧a;
a=a∧b;
所以本題的答案為: 11110000 。
c語言重點知識點總結(jié) 3
基本問題
在計算機中,所有的數(shù)據(jù)都是存放在存儲器中的,不同的數(shù)據(jù)類型占有的內(nèi)存空間的大小各不相同。內(nèi)存是以字節(jié)為單位的連續(xù)編址空間,每一個字節(jié)單元對應(yīng)著一個獨一的編號,這個編號被稱為內(nèi)存單元的地址。比如:int 類型占 4 個字節(jié),char 類型占 1 個字節(jié)等。系統(tǒng)在內(nèi)存中,為變量分配存儲空間的首個字節(jié)單元的地址,稱之為該變量的地址。地址用來標識每一個存儲單元,方便用戶對存儲單元中的數(shù)據(jù)進行正確的訪問。在高級語言中地址形象地稱為指針。
地址與指針
指針相對于一個內(nèi)存單元來說,指的是單元的地址,該單元的內(nèi)容里面存放的是數(shù)據(jù)。在 C 語言中,允許用指針變量來存放指針,因此,一個指針變量的值就是某個內(nèi)存單元的地址或稱為某內(nèi)存單元的指針。
變量及其定義
指針變量是存放一個內(nèi)存地址的變量,不同于其他類型變量,它是專門用來存放內(nèi)存地址的,也稱為地址變量。定義指針變量的一般形式為:類型說明符*變量名。
類型說明符表示指針變量所指向變量的數(shù)據(jù)類型;*表示這是一個指針變量;變量名表示定義的指針變量名,其值是一個地址,例如:char*p1;表示 p1 是一個指針變量,它的值是某個字符變量的地址。
1.1 指針與指針變量的概念,指針與地址運算符
1.在C語言中,指針是指一個變量的`地址,通過變量的地址″指向″的位置找到變量的值,這種″指向″變量地址可形象地看作″指針″。用來存放指針的變量稱為指針變量,它是一種特殊的變量,它存放的是地址值。
2.定義指針變量的一般形式為:
類型名 *指針變量1,*指針變量2,…;
″類型名″稱為″基類型″它規(guī)定了后面的指針變量中存放的數(shù)據(jù)類型,″*″號表明后面的″指針變量1″,″指針變量2″等是指針變量,″*″號在定義時不能省略,否則就會變成一般變量的定義了。″指針變量1″,″指針變量2″等稱為指針變量名。
3.一個指針變量只能指向同一類型的變量。
4.與指針和指針變量有關(guān)的兩個運算符:
(1)*:指針運算符(或稱″間接訪問″運算符)
(2)&:取地址運算符
通過*號可以引用一個存儲單元,如有如下定義:
int i=123,*p,k;
則 p=&I;或k=*p;或k=*&I;都將變量i中的值賦給k。
*p=10;或*&i=10;都能把整數(shù)10賦給變量i。這里,等號左邊的表達式*p和*&i都代表變量i的存儲單元。
1.2 變量、數(shù)組、字符串、函數(shù)、結(jié)構(gòu)體的指針以及指向它們的指針變量
1.變量的指針和指向變量的指針變量。
2.數(shù)組的指針和指向數(shù)組的指針變量。
所謂數(shù)組的指針是指數(shù)組的起始地址,數(shù)組元素的指針是數(shù)組元素的地址。
C語言規(guī)定數(shù)組名代表數(shù)組的首地址,也就是第一個元素的地址。
3.字符串的指針和指向字符串的指針變量。
我們可以通過定義說明一個指針指向一個字符串。
C語言將字符串隱含處理成一維字符數(shù)組,但數(shù)組的每個元素沒有具體的名字,這一點跟字符數(shù)組不一樣。要引用字符串中的某個字符,只能通過指針來引用:*(s+0),*(s+1),…,*(s+n)。
4.函數(shù)的指針和指向函數(shù)的指針變量。
指向函數(shù)的指針變量的一般形式為 :
數(shù)據(jù)類型標識符 (*指針變量名)();
這里的″數(shù)據(jù)類型標識符″是指函數(shù)返回值的類型。
函數(shù)的調(diào)用可以通過函數(shù)名調(diào)用,也可以通過函數(shù)指針調(diào)用(即用指向函數(shù)的指針變量調(diào)用)。
指向函數(shù)的指針變量表示定義了一個指向函數(shù)的指針變量,它不是固定指向哪一個函數(shù),而只是定義了這樣的一個類型變量,它專門用來存放函數(shù)的入口地址。在程序中把哪一個函數(shù)的地址賦給它,它就指向哪一個函數(shù)。在一個程序中,一個指針變量可以先后指向不同的函數(shù)。
在給函數(shù)指針變量賦值時,只需給出函數(shù)名而不必給出參數(shù)。因為函數(shù)指針賦的值僅是函數(shù)的入口地址,而不涉及到實參與形參的結(jié)合問題。
對指向函數(shù)的指針變量,表達式p+n,p++,p--等都無意義。
5.結(jié)構(gòu)體的指針與指向結(jié)構(gòu)體的指針變量
一個結(jié)構(gòu)體變量的指針就是該變量所占據(jù)的內(nèi)存段的起始地址?梢栽O(shè)一個指針變量,用來指向一個結(jié)構(gòu)體變量,此時該指針變量的值是結(jié)構(gòu)體變量的起始地址。指針變量也可以用來指向結(jié)構(gòu)體數(shù)組中的元素。
1.3 用指針做函數(shù)參數(shù)
函數(shù)的參數(shù)不僅可以是整型、實型、字符型等數(shù)據(jù),還可以是指針類型,它的作用是將一個變量的地址傳送到另一個函數(shù)中。
1.4 返回指針值的指針函數(shù)
一個函數(shù)可以返回一個整型值、字符值、實型值等,也可以返回指針型數(shù)據(jù) ,即地址這種帶回指針值的函數(shù),一般的定義形式為:
類型標識符 *函數(shù)名(形參表);
1.5 指針數(shù)組、指向指針的指針
1.指針數(shù)組指的是一個數(shù)組,其元素均為指針類型數(shù)據(jù),也就是說,指針數(shù)組中的每一個元素都是指針變量。指針數(shù)組的定義形式為:
類型標識 *數(shù)組名[數(shù)組長度說明]
指針數(shù)組可以使字符串處理更加方便。
2.指向指針的指針是指指向指針數(shù)據(jù)的指針變量,一個指向指針數(shù)據(jù)的指針變量的一般形式為:
類型標識 * *p;
1.6 main函數(shù)的命令參數(shù)
指針數(shù)組的一個重要應(yīng)用是作為main函數(shù)的形參,一般來說,main函數(shù)后的括號中是空的,即沒有參數(shù)。實際上main可以有參數(shù),如:
main(argc,argv)
其中,argc和argv就是main函數(shù)的形參。其他函數(shù)形參的值可以通過函數(shù)調(diào)用語句的實參中得到,由于main函數(shù)是由系統(tǒng)調(diào)用的,因而main函數(shù)的形參值不能從程序中得到,但可以在操作系統(tǒng)狀態(tài)下,將實參和命令一起給出,從而使main函數(shù)的形參得到值。命令行的一般形式為:
命令名 參數(shù)1 參數(shù)2…參數(shù)n
命令名和各參數(shù)之間用空格分隔開。
1.7 動態(tài)存儲分配
在C語言中有一種稱為“動態(tài)存儲分配”的內(nèi)存空間分配方式:程序在執(zhí)行期間需要存儲空間時,通過“申請”分配指定的內(nèi)存空間;當閑置不用時,可隨時將其釋放,由系統(tǒng)另作它用。本節(jié)介紹C語言中動態(tài)分配系統(tǒng)的主要函數(shù):malloc()、calloc()、free()及realloc(),使用這些函數(shù)時,必須在程序開頭包含文件stdlib.h。
1.主內(nèi)存分配函數(shù)—malloc()
函數(shù)格式:void*malloc(unsigned size);
函數(shù)功能:從內(nèi)存中分配一大小為size字節(jié)的塊。
參數(shù)說明:size為無符號整型,用于指定需要分配的內(nèi)存空間的字節(jié)數(shù)。
返回值:新分配內(nèi)存的地址,如無足夠的內(nèi)存可分配,則返回NULL。
說明:當size為0時,返回NULL。
2.主內(nèi)存分配函數(shù)——calloc()
函數(shù)格式:void*malloc(unsigned n,unsigned size);
函數(shù)功能:從內(nèi)存中分配n個同一類型數(shù)據(jù)項的連續(xù)存儲空間,每個數(shù)據(jù)項的大小為size字節(jié)。
參數(shù)說明:n為無符號整型,用于指定分配的數(shù)據(jù)項的個數(shù)size為無符號整型,用于指定需要分配的數(shù)據(jù)項所占內(nèi)存空間的字節(jié)數(shù)。
返回值:新分配內(nèi)存的地址,如無足夠的內(nèi)存可分配,則返回NULL。
3.重新分配內(nèi)存空間函數(shù)——realloc()
函數(shù)格式:void*realloc(void *block,unsigned size);
函數(shù)功能:將block所指內(nèi)存區(qū)的大小改為size字節(jié)的塊。
參數(shù)說明:block為void類型的指針,指向內(nèi)存中某塊,size為無符號整型,用于指定需要分配的內(nèi)存空間的字節(jié)數(shù)。
返回值:新分配內(nèi)存的地址,如無足夠的內(nèi)存可分配,則返回NULL。
4.釋放內(nèi)存函數(shù)—free()
函數(shù)格式:void free(void*block);
函數(shù)功能:將calloc()、malloc()及realloc()函數(shù)所分配的內(nèi)存空間釋放為自由空間。
參數(shù)說明:block為void類型的指針,指向要釋放的內(nèi)存空間。
返回值:無。
c語言重點知識點總結(jié) 4
指針簡介
指針是C語言中廣泛使用的一種數(shù)據(jù)類型。運用指針編程是C語言最主要的風(fēng)格之一。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu); 能很方便地使用數(shù)組和字符串; 并能象匯編語言一樣處理內(nèi)存地址,從而編出精練而高效的程序。指針極大地豐富了C語言的功能。 學(xué)習(xí)指針是學(xué)習(xí)C語言中最重要的一環(huán), 能否正確理解和使用指針是我們是否掌握C語言的一個標志。同時, 指針也是C語言中最為困難的一部分,在學(xué)習(xí)中除了要正確理解基本概念,還必須要多編程,上機調(diào)試。只要作到這些,指針也是不難掌握的。
指針的基本概念
在計算機中,所有的數(shù)據(jù)都是存放在存儲器中的。 一般把存儲器中的一個字節(jié)稱為一個內(nèi)存單元, 不同的數(shù)據(jù)類型所占用的內(nèi)存單元數(shù)不等,如整型量占2個單元,字符量占1個單元等, 在第二章中已有詳細的介紹。為了正確地訪問這些內(nèi)存單元, 必須為每個內(nèi)存單元編上號。 根據(jù)一個內(nèi)存單元的編號即可準確地找到該內(nèi)存單元。內(nèi)存單元的編號也叫做地址。 既然根據(jù)內(nèi)存單元的編號或地址就可以找到所需的內(nèi)存單元,所以通常也把這個地址稱為指針。 內(nèi)存單元的指針和內(nèi)存單元的內(nèi)容是兩個不同的概念。 可以用一個通俗的例子來說明它們之間的關(guān)系。我們到銀行去存取款時, 銀行工作人員將根據(jù)我們的帳號去找我們的存款單, 找到之后在存單上寫入存款、取款的金額。在這里,帳號就是存單的指針, 存款數(shù)是存單的內(nèi)容。對于一個內(nèi)存單元來說,單元的地址即為指針, 其中存放的數(shù)據(jù)才是該單元的內(nèi)容。在C語言中, 允許用一個變量來存放指針,這種變量稱為指針變量。因此, 一個指針變量的值就是某個內(nèi)存單元的地址或稱為某內(nèi)存單元的指針。圖中,設(shè)有字符變量C,其內(nèi)容為“K”(ASCII碼為十進制數(shù) 75),C占用了011A號單元(地址用十六進數(shù)表示)。設(shè)有指針變量P,內(nèi)容為011A, 這種情況我們稱為P指向變量C,或說P是指向變量C的指針。 嚴格地說,一個指針是一個地址, 是一個常量。而一個指針變量卻可以被賦予不同的指針值,是變。 但在常把指針變量簡稱為指針。為了避免混淆,我們中約定:“指針”是指地址, 是常量,“指針變量”是指取值為地址的變量。 定義指針的目的是為了通過指針去訪問內(nèi)存單元。
既然指針變量的值是一個地址, 那么這個地址不僅可以是變量的地址, 也可以是其它數(shù)據(jù)結(jié)構(gòu)的地址。在一個指針變量中存放一
個數(shù)組或一個函數(shù)的首地址有何意義呢? 因為數(shù)組或函數(shù)都是連續(xù)存放的。通過訪問指針變量取得了數(shù)組或函數(shù)的首地址, 也就找到了該數(shù)組或函數(shù)。這樣一來, 凡是出現(xiàn)數(shù)組,函數(shù)的地方都可以用一個指針變量來表示, 只要該指針變量中賦予數(shù)組或函數(shù)的首地址即可。這樣做, 將會使程序的概念十分清楚,程序本身也精練,高效。在C語言中, 一種數(shù)據(jù)類型或數(shù)據(jù)結(jié)構(gòu)往往都占有一組連續(xù)的內(nèi)存單元。 用“地址”這個概念并不能很好地描述一種數(shù)據(jù)類型或數(shù)據(jù)結(jié)構(gòu), 而“指針”雖然實際上也是一個地址,但它卻是一個數(shù)據(jù)結(jié)構(gòu)的首地址, 它是“指向”一個數(shù)據(jù)結(jié)構(gòu)的,因而概念更為清楚,表示更為明確。 這也是引入“指針”概念的一個重要原因。
指針變量的類型說明
對指針變量的類型說明包括三個內(nèi)容:
(1)指針類型說明,即定義變量為一個指針變量;
(2)指針變量名;
(3)變量值(指針)所指向的變量的數(shù)據(jù)類型。
其一般形式為: 類型說明符 *變量名;
其中,*表示這是一個指針變量,變量名即為定義的指針變量名,類型說明符表示本指針變量所指向的變量的數(shù)據(jù)類型。
例如: int *p1;表示p1是一個指針變量,它的值是某個整型變量的地址。 或者說p1指向一個整型變量。至于p1究竟指向哪一個整型變量, 應(yīng)由向p1賦予的地址來決定。
再如:
staic int *p2; /*p2是指向靜態(tài)整型變量的指針變量*/
float *p3; /*p3是指向浮點變量的指針變量*/
char *p4; /*p4是指向字符變量的指針變量*/ 應(yīng)該注意的是,一個指針變量只能指向同類型的變量,如P3 只能指向浮點變量,不能時而指向一個浮點變量, 時而又指向一個字符變量。
指針變量的賦值
指針變量同普通變量一樣,使用之前不僅要定義說明, 而且必須賦予具體的值。未經(jīng)賦值的指針變量不能使用, 否則將造成系統(tǒng)混亂,甚至死機。指針變量的賦值只能賦予地址, 決不能賦予任何其它數(shù)據(jù),否則將引起錯誤。在C語言中, 變量的地址是由編譯系統(tǒng)分配的,對用戶完全透明,用戶不知道變量的具體地址。 C語言中提供了地址運算符&來表示變量的地址。其一般形式為: & 變量名; 如&a變示變量a的地址,&b表示變量b的地址。 變量本身必須預(yù)先說明。設(shè)有指向整型變量的指針變量p,如要把整型變量a 的地址賦予p可以有以下兩種方式:
(1)指針變量初始化的方法 int a;
int *p=&a;
(2)賦值語句的方法 int a;
int *p;
p=&a;
不允許把一個數(shù)賦予指針變量,故下面的賦值是錯誤的: int *p;p=1000; 被賦值的指針變量前不能再加“*”說明符,如寫為*p=&a 也是錯誤的
指針變量的運算
指針變量可以進行某些運算,但其運算的種類是有限的。 它只能進行賦值運算和部分算術(shù)運算及關(guān)系運算。
1.指針運算符
(1)取地址運算符&
取地址運算符&是單目運算符,其結(jié)合性為自右至左,其功能是取變量的地址。在scanf函數(shù)及前面介紹指針變量賦值中,我們已經(jīng)了解并使用了&運算符。
(2)取內(nèi)容運算符*
取內(nèi)容運算符*是單目運算符,其結(jié)合性為自右至左,用來表示指針變量所指的變量。在*運算符之后跟的變量必須是指針變量。需要注意的是指針運算符*和指針變量說明中的指針說明符* 不是一回事。在指針變量說明中,“*”是類型說明符,表示其后的變量是指針類型。而表達式中出現(xiàn)的“*”則是一個運算符用以表示指針變量所指的變量。
main(){
int a=5,*p=&a;
printf ("%d",*p);
}
......
表示指針變量p取得了整型變量a的地址。本語句表示輸出變量a的值。
2.指針變量的運算
(1)賦值運算
指針變量的賦值運算有以下幾種形式:
、僦羔樧兞砍跏蓟x值,前面已作介紹。
、诎岩粋變量的地址賦予指向相同數(shù)據(jù)類型的指針變量。例如:
int a,*pa;
pa=&a; /*把整型變量a的地址賦予整型指針變量pa*/
、郯岩粋指針變量的值賦予指向相同類型變量的另一個指針變量。如:
int a,*pa=&a,*pb;
pb=pa; /*把a的地址賦予指針變量pb*/
由于pa,pb均為指向整型變量的指針變量,因此可以相互賦值。 ④把數(shù)組的首地址賦予指向數(shù)組的指針變量。
例如: int a[5],*pa;
pa=a; (數(shù)組名表示數(shù)組的首地址,故可賦予指向數(shù)組的指針變量pa)
也可寫為:
pa=&a[0]; /*數(shù)組第一個元素的地址也是整個數(shù)組的首地址,也可賦予pa*/
當然也可采取初始化賦值的方法:
int a[5],*pa=a;
⑤把字符串的首地址賦予指向字符類型的指針變量。例如: char *pc;pc="c language";或用初始化賦值的方法寫為: char *pc="C Language"; 這里應(yīng)說明的是并不是把整個字符串裝入指針變量, 而是把存放該字符串的字符數(shù)組的首地址裝入指針變量。 在后面還將詳細介紹。
、薨押瘮(shù)的入口地址賦予指向函數(shù)的指針變量。例如: int (*pf)();pf=f; /*f為函數(shù)名*/
(2)加減算術(shù)運算
對于指向數(shù)組的指針變量,可以加上或減去一個整數(shù)n。設(shè)pa是指向數(shù)組a的指針變量,則pa+n,pa-n,pa++,++pa,pa--,--pa 運算都是合法的。指針變量加或減一個整數(shù)n的意義是把指針指向的當前位置(指向某數(shù)組元素)向前或向后移動n個位置。應(yīng)該注意,數(shù)組指針變量向前或向后移動一個位置和地址加1或減1 在概念上是不同的。因為數(shù)組可以有不同的類型, 各種類型的數(shù)組元素所占的字節(jié)長度是不同的。如指針變量加1,即向后移動1 個位置表示指針變量指向下一個數(shù)據(jù)元素的首地址。而不是在原地址基礎(chǔ)上加1。
例如:
int a[5],*pa;
pa=a; /*pa指向數(shù)組a,也是指向a[0]*/
pa=pa+2; /*pa指向a[2],即pa的值為&pa[2]*/ 指針變量的加減運算只能對數(shù)組指針變量進行, 對指向其它類型變量的指針變量作加減運算是毫無意義的。(3)兩個指針變量之間的運算只有指向同一數(shù)組的兩個指針變量之間才能進行運算, 否則運算毫無意義。
、賰芍羔樧兞肯鄿p
兩指針變量相減所得之差是兩個指針所指數(shù)組元素之間相差的元素個數(shù)。實際上是兩個指針值(地址) 相減之差再除以該數(shù)組元素的長度(字節(jié)數(shù))。例如pf1和pf2 是指向同一浮點數(shù)組的兩個指針變量,設(shè)pf1的值為2010H,pf2的值為2000H,而浮點數(shù)組每個元素占4個字節(jié),所以pf1-pf2的結(jié)果為(2000H-2010H)/4=4,表示pf1和 pf2之間相差4個元素。兩個指針變量不能進行加法運算。 例如, pf1+pf2是什么意思呢?毫無實際意義。
、趦芍羔樧兞窟M行關(guān)系運算
指向同一數(shù)組的兩指針變量進行關(guān)系運算可表示它們所指數(shù)組元素之間的關(guān)系。例如:
pf1==pf2表示pf1和pf2指向同一數(shù)組元素
pf1>pf2表示pf1處于高地址位置
pf1 main(){
int a=10,b=20,s,t,*pa,*pb;
pa=&a;
pb=&b;
s=*pa+*pb;
t=*pa**pb;
printf("a=%d b=%d a+b=%d a*b=%d ",a,b,a+b,a*b);
printf("s=%d t=%d ",s,t);
}
......
說明pa,pb為整型指針變量
給指針變量pa賦值,pa指向變量a。
給指針變量pb賦值,pb指向變量b。
本行的意義是求a+b之和,(*pa就是a,*pb就是b)。
本行是求a*b之積。
輸出結(jié)果。
輸出結(jié)果。
......
指針變量還可以與0比較。設(shè)p為指針變量,則p==0表明p是空指針,它不指向任何變量;p!=0表示p不是空指針?罩羔樖怯蓪χ羔樧兞抠x予0值而得到的。例如: #define NULL 0 int *p=NULL; 對指針變量賦0值和不賦值是不同的。指針變量未賦值時,可以是任意值,是不能使用的。否則將造成意外錯誤。而指針變量賦0值后,則可以使用,只是它不指向具體的變量而已。
main(){
int a,b,c,*pmax,*pmin;
printf("input three numbers: ");
scanf("%d%d%d",&a,&b,&c);
if(a>b){
pmax=&a;
pmin=&b;}
else{
pmax=&b;
pmin=&a;}
if(c>*pmax) pmax=&c;
if(c<*pmin) pmin=&c;
printf("max=%d min=%d ",*pmax,*pmin);
}
......
pmax,pmin為整型指針變量。
輸入提示。
輸入三個數(shù)字。
如果第一個數(shù)字大于第二個數(shù)字...
指針變量賦值
指針變量賦值
指針變量賦值
指針變量賦值
判斷并賦值
判斷并賦值
輸出結(jié)果
......
數(shù)組指針變量的說明和使用
指向數(shù)組的指針變量稱為數(shù)組指針變量。 在討論數(shù)組指針變量的說明和使用之前,我們先明確幾個關(guān)系。
一個數(shù)組是由連續(xù)的一塊內(nèi)存單元組成的。 數(shù)組名就是這塊連續(xù)內(nèi)存單元的首地址。一個數(shù)組也是由各個數(shù)組元素(下標變量) 組成的。每個數(shù)組元素按其類型不同占有幾個連續(xù)的內(nèi)存單元。 一個數(shù)組元素的首地址也是指它所占有的幾個內(nèi)存單元的首地址。 一個指針變量既可以指向一個數(shù)組,也可以指向一個數(shù)組元素, 可把數(shù)組名或第一個元素的地址賦予它。如要使指針變量指向第i號元素可以把i元素的首地址賦予它或把數(shù)組名加i賦予它。
設(shè)有實數(shù)組a,指向a的指針變量為pa,從圖6.3中我們可以看出有以下關(guān)系:
pa,a,&a[0]均指向同一單元,它們是數(shù)組a的首地址,也是0 號元素a[0]的首地址。pa+1,a+1,&a[1]均指向1號元素a[1]。類推可知a+i,a+i,&a[i]
指向i號元素a[i]。應(yīng)該說明的是pa是變量,而a,&a[i]都是常量。在編程時應(yīng)予以注意。
main(){
int a[5],i;
for(i=0;i<5;i++){
a[i]=i;
printf("a[%d]=%d ",i,a[i]);
}
printf(" ");
}
主函數(shù)
定義一個整型數(shù)組和一個整型變量
循環(huán)語句
給數(shù)組賦值
打印每一個數(shù)組的值
......
輸出換行
......
數(shù)組指針變量說明的一般形式為:
類型說明符 * 指針變量名
其中類型說明符表示所指數(shù)組的類型。 從一般形式可以看出指向數(shù)組的指針變量和指向普通變量的指針變量的說明是相同的。
引入指針變量后,就可以用兩種方法來訪問數(shù)組元素了。
第一種方法為下標法,即用a[i]形式訪問數(shù)組元素。 在第四章中介紹數(shù)組時都是采用這種方法。
第二種方法為指針法,即采用*(pa+i)形式,用間接訪問的方法來訪問數(shù)組元素。
main(){
int a[5],i,*pa;
pa=a;
for(i=0;i<5;i++){
*pa=i;
pa++;
}
pa=a;
for(i=0;i<5;i++){
printf("a[%d]=%d ",i,*pa);
pa++;
}
}
主函數(shù)
定義整型數(shù)組和指針
將指針pa指向數(shù)組a
循環(huán)
將變量i的值賦給由指針pa指向的a[]的數(shù)組單元
將指針pa指向a[]的下一個單元
......
指針pa重新取得數(shù)組a的首地址
循環(huán)
用數(shù)組方式輸出數(shù)組a中的所有元素
將指針pa指向a[]的下一個單元
......
......
下面,另舉一例,該例與上例本意相同,但是實現(xiàn)方式不同。
main(){
int a[5],i,*pa=a;
for(i=0;i<5;){
*pa=i;
printf("a[%d]=%d ",i++,*pa++);
}
}
主函數(shù)
定義整型數(shù)組和指針,并使指針指向數(shù)組a
循環(huán)
將變量i的值賦給由指針pa指向的a[]的數(shù)組單元
用指針輸出數(shù)組a中的所有元素,同時指針pa指向a[]的下一個單元
......
......
數(shù)組名和數(shù)組指針變量作函數(shù)參數(shù)
在第五章中曾經(jīng)介紹過用數(shù)組名作函數(shù)的實參和形參的問題。在學(xué)習(xí)指針變量之后就更容易理解這個問題了。 數(shù)組名就是數(shù)組的首地址,實參向形參傳送數(shù)組名實際上就是傳送數(shù)組的地址, 形參得到該地址后也指向同一數(shù)組。 這就好象同一件物品有兩個彼此不同的名稱一樣。同樣,指針變量的值也是地址, 數(shù)組指針變量的值即為數(shù)組的首地址,當然也可作為函數(shù)的參數(shù)使用。
float aver(float *pa);
main(){
float sco[5],av,*sp;
int i;
sp=sco;
printf(" input 5 scores: ");
for(i=0;i<5;i++) scanf("%f",&sco[i]);
av=aver(sp);
printf("average score is %5.2f",av);
}
float aver(float *pa)
{
int i;
float av,s=0;
for(i=0;i<5;i++) s=s+*pa++;
av=s/5;
return av;
}
指向多維數(shù)組的指針變量
本小節(jié)以二維數(shù)組為例介紹多維數(shù)組的指針變量。
一、多維數(shù)組地址的表示方法
設(shè)有整型二維數(shù)組a[3][4]如下:
0 1 2 3
4 5 6 7
8 9 10 11
設(shè)數(shù)組a的首地址為1000,各下標變量的首地址及其值如圖所示。在第四章中介紹過, C語言允許把一個二維數(shù)組分解為多個一維數(shù)組來處理。因此數(shù)組a可分解為三個一維數(shù)組,即a[0],a[1],a[2]。每一個一維數(shù)組又含有四個元素。例如a[0]數(shù)組,含有a[0][0],a[0][1],a[0][2],a[0][3]四個元素。 數(shù)組及數(shù)組元素的地址表示如下:a是二維數(shù)組名,也是二維數(shù)組0行的首地址,等于1000。a[0]是第一個一維數(shù)組的數(shù)組名和首地址,因此也為1000。*(a+0)或*a是與a[0]等效的, 它表示一維數(shù)組a[0]0 號元素的首地址。 也為1000。&a[0][0]是二維數(shù)組a的0行0列元素首地址,同樣是1000。因此,a,a[0],*(a+0),*a?amp;a[0][0]是相等的。同理,a+1是二維數(shù)組1行的首地址,等于1008。a[1]是第二個一維數(shù)組的數(shù)組名和首地址,因此也為1008。 &a[1][0]是二維數(shù)組a的1行0列元素地址,也是1008。因此a+1,a[1],*(a+1),&a[1][0]是等同的。 由此可得出:a+i,a[i],*(a+i),&a[i][0]是等同的。 此外,&a[i]和a[i]也是等同的。因為在二維數(shù)組中不能把&a[i]理解為元素a[i]的地址,不存在元素a[i]。
C語言規(guī)定,它是一種地址計算方法,表示數(shù)組a第i行首地址。由此,我們得出:a[i],&a[i],*(a+i)和a+i也都是等同的。另外,a[0]也
可以看成是a[0]+0是一維數(shù)組a[0]的0號元素的首地址, 而a[0]+1則是a[0]的1號元素首地址,由此可得出a[i]+j則是一維數(shù)組a[i]的j號元素首地址,它等于&a[i][j]。由a[i]=*(a+i)得a[i]+j=*(a+i)+j,由于*(a+i)+j是二維數(shù)組a的i行j列元素的首地址。該元素的值等于*(*(a+i)+j)。
[Explain]#define PF "%d,%d,%d,%d,%d, "
main(){
static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
printf(PF,a,*a,a[0],&a[0],&a[0][0]);
printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]);
printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]);
printf("%d,%d ",a[1]+1,*(a+1)+1);
printf("%d,%d ",*(a[1]+1),*(*(a+1)+1));
}
二、多維數(shù)組的指針變量
把二維數(shù)組a 分解為一維數(shù)組a[0],a[1],a[2]之后,設(shè)p為指向二維數(shù)組的指針變量?啥x為: int (*p)[4] 它表示p是一個指針變量,它指向二維數(shù)組a 或指向第一個一維數(shù)組a[0],其值等于a,a[0],或&a[0][0]等。而p+i則指向一維數(shù)組a[i]。從前面的分析可得出*(p+i)+j是二維數(shù)組i行j 列的元素的地址,而*(*(p+i)+j)則是i行j列元素的值。
二維數(shù)組指針變量說明的一般形式為: 類型說明符 (*指針變量名)[長度] 其中“類型說明符”為所指數(shù)組的數(shù)據(jù)類型!*”表示其后的變量是指針類型。 “長度”表示二維數(shù)組分解為多個一維數(shù)組時, 一維數(shù)組的長度,也就是二維數(shù)組的列數(shù)。應(yīng)注意“(*指針變量名)”兩邊的括號不可少,如缺少括號則表示是指針數(shù)組(本章后面介紹),意義就完全不同了。
[Explain]main(){
static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
int(*p)[4];
int i,j;
p=a;
for(i=0;i<3;i++)
for(j=0;j<4;j++) printf("- ",*(*(p+i)+j));
}
Expain字符串指針變量的說明和使用字符串指針變量的定義說明與指向字符變量的指針變量說明是相同的。只能按對指針變量的賦值不同來區(qū)別。 對指向字符變量的指針變量應(yīng)賦予該字符變量的地址。如: char c,*p=&c;表示p是一個指向字符變量c的指針變量。而: char *s="C Language";則表示s是一個指向字符串的指針變量。把字符串的首地址賦予s。
請看下面一例。
main(){
char *ps;
ps="C Language";
printf("%s",ps);
}
運行結(jié)果為:
C Language
上例中,首先定義ps是一個字符指針變量, 然后把字符串的首地址賦予ps(應(yīng)寫出整個字符串,以便編譯系統(tǒng)把該串裝入連續(xù)的一塊內(nèi)存單元),并把首地址送入ps。程序中的: char *ps;ps="C Language";等效于: char *ps="C Language";輸出字符串中n個字符后的所有字符。
main(){
char *ps="this is a book";
int n=10;
ps=ps+n;
printf("%s ",ps);
}
運行結(jié)果為:
book 在程序中對ps初始化時,即把字符串首地址賦予ps,當ps= ps+10之后,ps指向字符“b”,因此輸出為"book"。
main(){
char st[20],*ps;
int i;
printf("input a string: ");
ps=st;
scanf("%s",ps);
for(i=0;ps[i]!=;i++)
if(ps[i]==k){
printf("there is a k in the string ");
break;
}
if(ps[i]==) printf("There is no k in the string ");
}
本例是在輸入的字符串中查找有無‘k’字符。 下面這個例子是將指針變量指向一個格式字符串,用在printf函數(shù)中,用于輸出二維數(shù)組的各種地址表示的值。但在printf語句中用指針變量PF代替了格式串。 這也是程序中常用的方法。
main(){
static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
char *PF;
PF="%d,%d,%d,%d,%d ";
printf(PF,a,*a,a[0],&a[0],&a[0][0]);
printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]);
printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]);
printf("%d,%d ",a[1]+1,*(a+1)+1);
printf("%d,%d ",*(a[1]+1),*(*(a+1)+1));
}
在下例是講解,把字符串指針作為函數(shù)參數(shù)的使用。要求把一個字符串的內(nèi)容復(fù)制到另一個字符串中,并且不能使用strcpy函數(shù)。函數(shù)cprstr的形參為兩個字符指針變量。pss指向源字符串,pds指向目標字符串。表達式:
(*pds=*pss)!=`
cpystr(char *pss,char *pds){
while((*pds=*pss)!=){
pds++;
pss++; }
}
main(){
char *pa="CHINA",b[10],*pb;
pb=b;
cpystr(pa,pb);
printf("string a=%s string b=%s ",pa,pb);
}
在上例中,程序完成了兩項工作:一是把pss指向的源字符復(fù)制到pds所指向的目標字符中,二是判斷所復(fù)制的字符是否為`,若是則表明源字符串結(jié)束,不再循環(huán)。否則,pds和pss都加1,指向下一字符。在主函數(shù)中,以指針變量pa,pb為實參,分別取得確定值后調(diào)用cprstr函數(shù)。由于采用的指針變量pa和pss,pb和pds均指向同一字符串,因此在主函數(shù)和cprstr函數(shù)中均可使用這些字符串。也可以把cprstr函數(shù)簡化為以下形式:
cprstr(char *pss,char*pds)
{while ((*pds++=*pss++)!=`);}
即把指針的移動和賦值合并在一個語句中。 進一步分析還可發(fā)現(xiàn)`的ASCⅡ碼為0,對于while語句只看表達式的值為非0就循環(huán),為0則結(jié)束循環(huán),因此也可省去“!=`”這一判斷部分,而寫為以下形式:
cprstr (char *pss,char *pds)
{while (*pdss++=*pss++);}
表達式的意義可解釋為,源字符向目標字符賦值, 移動指針,若所賦值為非0則循環(huán),否則結(jié)束循環(huán)。這樣使程序更加簡潔。簡化后的程序如下所示。
cpystr(char *pss,char *pds){
while(*pds++=*pss++);
}
main(){
char *pa="CHINA",b[10],*pb;
pb=b;
cpystr(pa,pb);
printf("string a=%s string b=%s ",pa,pb);
}
使用字符串指針變量與字符數(shù)組的區(qū)別
用字符數(shù)組和字符指針變量都可實現(xiàn)字符串的存儲和運算。 但是兩者是有區(qū)別的。在使用時應(yīng)注意以下幾個問題:
1. 字符串指針變量本身是一個變量,用于存放字符串的首地址。而字符串本身是存放在以該首地址為首的一塊連續(xù)的內(nèi)存空間中并以‘’作為串的結(jié)束。字符數(shù)組是由于若干個數(shù)組元素組成的,它可用來存放整個字符串。
2. 對字符數(shù)組作初始化賦值,必須采用外部類型或靜態(tài)類型,如: static char st[]={“C Language”};而對字符串指針變量則無此限制,如: char *ps="C Language";
3. 對字符串指針方式 char *ps="C Language";可以寫為: char *ps; ps="C Language";而對數(shù)組方式:
static char st[]={"C Language"};
不能寫為:
char st[20];st={"C Language"};
而只能對字符數(shù)組的各元素逐個賦值。
從以上幾點可以看出字符串指針變量與字符數(shù)組在使用時的區(qū)別,同時也可看出使用指針變量更加方便。前面說過,當一個指針變量在未取得確定地址前使用是危險的,容易引起錯誤。但是對指針變量直接賦值是可以的。因為C系統(tǒng)對指針變量賦值時要給以確定的地址。因此,char *ps="C Langage";
或者 char *ps;
ps="C Language";都是合法的。
函數(shù)指針變量
在C語言中規(guī)定,一個函數(shù)總是占用一段連續(xù)的內(nèi)存區(qū), 而函數(shù)名就是該函數(shù)所占內(nèi)存區(qū)的首地址。 我們可以把函數(shù)的這個首地址(或稱入口地址)賦予一個指針變量, 使該指針變量指向該函數(shù)。然后通過指針變量就可以找到并調(diào)用這個函數(shù)。 我們把這種指向函數(shù)的指針變量稱為“函數(shù)指針變量”。
函數(shù)指針變量定義的一般形式為:
類型說明符 (*指針變量名)();
其中“類型說明符”表示被指函數(shù)的返回值的類型!(* 指針變量名)”表示“*”后面的變量是定義的指針變量。 最后的空括號表示指針變量所指的是一個函數(shù)。
例如: int (*pf)();
表示pf是一個指向函數(shù)入口的指針變量,該函數(shù)的返回值(函數(shù)值)是整型。
下面通過例子來說明用指針形式實現(xiàn)對函數(shù)調(diào)用的方法。
int max(int a,int b){
if(a>b)return a;
else return b;
}
main(){
int max(int a,int b);
int(*pmax)();
int x,y,z;
pmax=max;
printf("input two numbers: ");
scanf("%d%d",&x,&y);
z=(*pmax)(x,y);
printf("maxmum=%d",z);
}
從上述程序可以看出用,函數(shù)指針變量形式調(diào)用函數(shù)的步驟如下:1. 先定義函數(shù)指針變量,如后一程序中第9行 int (*pmax)();定義pmax為函數(shù)指針變量。
2. 把被調(diào)函數(shù)的入口地址(函數(shù)名)賦予該函數(shù)指針變量,如程序中第11行 pmax=max;
3. 用函數(shù)指針變量形式調(diào)用函數(shù),如程序第14行 z=(*pmax)(x,y); 調(diào)用函數(shù)的一般形式為: (*指針變量名) (實參表)使用函數(shù)指針變量還應(yīng)注意以下兩點:
a. 函數(shù)指針變量不能進行算術(shù)運算,這是與數(shù)組指針變量不同的。數(shù)組指針變量加減一個整數(shù)可使指針移動指向后面或前面的數(shù)組元素,而函數(shù)指針的移動是毫無意義的。
b. 函數(shù)調(diào)用中"(*指針變量名)"的兩邊的括號不可少,其中的*不應(yīng)該理解為求值運算,在此處它只是一種表示符號。
指針型函數(shù)
前面我們介紹過,所謂函數(shù)類型是指函數(shù)返回值的類型。 在C語言中允許一個函數(shù)的返回值是一個指針(即地址), 這種返回指針值的函數(shù)稱為指針型函數(shù)。
定義指針型函數(shù)的一般形式為:
類型說明符 *函數(shù)名(形參表)
{
…… /*函數(shù)體*/
}
其中函數(shù)名之前加了“*”號表明這是一個指針型函數(shù),即返回值是一個指針。類型說明符表示了返回的指針值所指向的數(shù)據(jù)類型。
如:
int *ap(int x,int y)
{
...... /*函數(shù)體*/
}
表示ap是一個返回指針值的指針型函數(shù), 它返回的指針指向一個整型變量。下例中定義了一個指針型函數(shù) day-name,它的返回值指向一個字符串。該函數(shù)中定義了一個靜態(tài)指針數(shù)組name。name 數(shù)組初始化賦值為八個字符串,分別表示各個星期名及出錯提示。形參n表示與星期名所對應(yīng)的整數(shù)。在主函數(shù)中, 把輸入的整數(shù)i作為實參, 在printf語句中調(diào)用day-name函數(shù)并把i值傳送給形參 n。day-name函數(shù)中的return語句包含一個條件表達式, n 值若大于7或小于1則把name[0] 指針返回主函數(shù)輸出出錯提示字符串“Illegal day”。否則返回主函數(shù)輸出對應(yīng)的星期名。主函數(shù)中的第7行是個條件語句,其語義是,如輸入為負數(shù)(i<0)則中止程序運行退出程序。exit是一個庫函數(shù),exit(1)表示發(fā)生錯誤后退出程序, exit(0)表示正常退出。
應(yīng)該特別注意的是函數(shù)指針變量和指針型函數(shù)這兩者在寫法和意義上的區(qū)別。如int(*p)()和int *p()是兩個完全不同的量。int(*p)()是一個變量說明,說明p 是一個指向函數(shù)入口的指針變量,該函數(shù)的返回值是整型量,(*p)的兩邊的括號不能少。int *p() 則不是變量說明而是函數(shù)說明,說明p是一個指針型函數(shù),其返回值是一個指向整型量的指針,*p兩邊沒有括號。作為函數(shù)說明, 在括號內(nèi)最好寫入形式參數(shù),這樣便于與變量說明區(qū)別。 對于指針型函數(shù)定義,int *p()只是函數(shù)頭部分,一般還應(yīng)該有函數(shù)體部分。
main(){
int i;
char *day-name(int n);
printf("input Day No: ");
scanf("%d",&i);
if(i<0) exit(1);
printf("Day No:--->%s ",i,day-name(i));
}
char *day-name(int n){
static char *name[]={ "Illegal day","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
return((n<1||n>7) ? name[0] : name[n]);
}
本程序是通過指針函數(shù),輸入一個1~7之間的整數(shù), 輸出對應(yīng)的星期名。指針數(shù)組的說明與使用一個數(shù)組的元素值為指針則是指針數(shù)組。 指針數(shù)組是一組有序的指針的'集合。 指針數(shù)組的所有元素都必須是具有相同存儲類型和指向相同數(shù)據(jù)類型的指針變量。
指針數(shù)組說明的一般形式為: 類型說明符*數(shù)組名[數(shù)組長度]
其中類型說明符為指針值所指向的變量的類型。例如: int *pa[3] 表示pa是一個指針數(shù)組,它有三個數(shù)組元素, 每個元素值都是一個指針,指向整型變量。通?捎靡粋指針數(shù)組來指向一個二維數(shù)組。 指針數(shù)組中的每個元素被賦予二維數(shù)組每一行的首地址, 因此也可理解為指向一個一維數(shù)組。圖6—6表示了這種關(guān)系。
int a[3][3]={1,2,3,4,5,6,7,8,9};
int *pa[3]={a[0],a[1],a[2]};
int *p=a[0];
main(){
int i;
for(i=0;i<3;i++)
printf("%d,%d,%d ",a[i][2-i],*a[i],*(*(a+i)+i));
for(i=0;i<3;i++)
printf("%d,%d,%d ",*pa[i],p[i],*(p+i));
}
本例程序中,pa是一個指針數(shù)組,三個元素分別指向二維數(shù)組a的各行。然后用循環(huán)語句輸出指定的數(shù)組元素。其中*a[i]表示i行0列元素值;*(*(a+i)+i)表示i行i列的元素值;*pa[i]表示i行0列元素值;由于p與a[0]相同,故p[i]表示0行i列的值;*(p+i)表示0行i列的值。讀者可仔細領(lǐng)會元素值的各種不同的表示方法。 應(yīng)該注意指針數(shù)組和二維數(shù)組指針變量的區(qū)別。 這兩者雖然都可用來表示二維數(shù)組,但是其表示方法和意義是不同的。
二維數(shù)組指針變量是單個的變量,其一般形式中"(*指針變量名)"兩邊的括號不可少。而指針數(shù)組類型表示的是多個指針( 一組有序指針)在一般形式中"*指針數(shù)組名"兩邊不能有括號。例如: int (*p)[3];表示一個指向二維數(shù)組的指針變量。該二維數(shù)組的列數(shù)為3或分解為一維數(shù)組的長度為3。 int *p[3] 表示p是一個指針數(shù)組,有三個下標變量p[0],p[1],p[2]均為指針變量。
指針數(shù)組也常用來表示一組字符串, 這時指針數(shù)組的每個元素被賦予一個字符串的首地址。 指向字符串的指針數(shù)組的初始化更為簡單。例如在例6.20中即采用指針數(shù)組來表示一組字符串。 其初始化賦值為:
char *name[]={"Illagal day","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
完成這個初始化賦值之后,name[0]即指向字符串"Illegal day",name[1]指?quot;Monday"......。
指針數(shù)組也可以用作函數(shù)參數(shù)。在本例主函數(shù)中,定義了一個指針數(shù)組name,并對name 作了初始化賦值。其每個元素都指向一個字符串。然后又以name 作為實參調(diào)用指針型函數(shù)day name,在調(diào)用時把數(shù)組名 name 賦予形參變量name,輸入的整數(shù)i作為第二個實參賦予形參n。在day name函數(shù)中定義了兩個指針變量pp1和pp2,pp1被賦予name[0]的值(即*name),pp2被賦予name[n]的值即*(name+ n)。由條件表達式?jīng)Q定返回pp1或pp2指針給主函數(shù)中的指針變量ps。最后輸出i和ps的值。
指針數(shù)組作指針型函數(shù)的參數(shù)
main(){
static char *name[]={ "Illegal day","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
char *ps;
int i;
char *day name(char *name[],int n);
printf("input Day No: ");
scanf("%d",&i);
if(i<0) exit(1);
ps=day name(name,i);
printf("Day No:--->%s ",i,ps);
}
char *day name(char *name[],int n)
{
char *pp1,*pp2;
pp1=*name;
pp2=*(name+n);
return((n<1||n>7)? pp1:pp2);
}
下例要求輸入5個國名并按字母順序排列后輸出。在以前的例子中采用了普通的排序方法, 逐個比較之后交換字符串的位置。交換字符串的物理位置是通過字符串復(fù)制函數(shù)完成的。 反復(fù)的交換將使程序執(zhí)行的速度很慢,同時由于各字符串(國名) 的長度不同,又增加了存儲管理的負擔。 用指針數(shù)組能很好地解決這些問題。把所有的字符串存放在一個數(shù)組中, 把這些字符數(shù)組的首地址放在一個指針數(shù)組中,當需要交換兩個字符串時, 只須交換指針數(shù)組相應(yīng)兩元素的內(nèi)容(地址)即可,而不必交換字符串本身。程序中定義了兩個函數(shù),一個名為sort完成排序, 其形參為指
針數(shù)組name,即為待排序的各字符串數(shù)組的指針。形參n為字符串的個數(shù)。另一個函數(shù)名為print,用于排序后字符串的輸出,其形參與sort的形參相同。主函數(shù)main中,定義了指針數(shù)組name 并作了初始化賦值。然后分別調(diào)用sort函數(shù)和print函數(shù)完成排序和輸出。值得說明的是在sort函數(shù)中,對兩個字符串比較,采用了strcmp 函數(shù),strcmp函數(shù)允許參與比較的串以指針方式出現(xiàn)。name[k]和name[ j]均為指針,因此是合法的。字符串比較后需要交換時, 只交換指針數(shù)組元素的值,而不交換具體的字符串, 這樣將大大減少時間的開銷,提高了運行效率。
現(xiàn)編程如下:
#include"string.h"
main(){
void sort(char *name[],int n);
void print(char *name[],int n);
static char *name[]={ "CHINA","AMERICA","AUSTRALIA","FRANCE","GERMAN"};
int n=5;
sort(name,n);
print(name,n);
}
void sort(char *name[],int n){
char *pt;
int i,j,k;
for(i=0;i k=i;
for(j=i+1;j if(strcmp(name[k],name[j])>0) k=j;
if(k!=i){
pt=name[i];
name[i]=name[k];
name[k]=pt;
}
}
}
void print(char *name[],int n){
int i;
for (i=0;i }
main函數(shù)的參數(shù)
前面介紹的main函數(shù)都是不帶參數(shù)的。因此main 后的括號都是空括號。實際上,main函數(shù)可以帶參數(shù),這個參數(shù)可以認為是 main函數(shù)的形式參數(shù)。C語言規(guī)定main函數(shù)的參數(shù)只能有兩個, 習(xí)慣上這兩個參數(shù)寫為argc和argv。因此,main函數(shù)的函數(shù)頭可寫為: main (argc,argv)C語言還規(guī)定argc(第一個形參)必須是整型變量,argv( 第二個形參)必須是指向字符串的指針數(shù)組。加上形參說明后,main函數(shù)的函數(shù)頭應(yīng)寫為:
main (argc,argv)
int argv;
char *argv[];或?qū)懗桑?/p>
main (int argc,char *argv[])
由于main函數(shù)不能被其它函數(shù)調(diào)用, 因此不可能在程序內(nèi)部取得實際值。那么,在何處把實參值賦予main函數(shù)的形參呢? 實際上,main函數(shù)的參數(shù)值是從操作系統(tǒng)命令行上獲得的。當我們要運行一個可執(zhí)行文件時,在DOS提示符下鍵入文件名,再輸入實際參數(shù)即可把這些實參傳送到main的形參中去。
DOS提示符下命令行的一般形式為: C:>可執(zhí)行文件名 參數(shù) 參數(shù)……; 但是應(yīng)該特別注意的是,main 的兩個形參和命令行中的參數(shù)在
位置上不是一一對應(yīng)的。因為,main的形參只有二個,而命令行中的參數(shù)個數(shù)原則上未加限制。argc參數(shù)表示了命令行中參數(shù)的個數(shù)(注意:文件名本身也算一個參數(shù)),argc的值是在輸入命令行時由系統(tǒng)按實際參數(shù)的個數(shù)自動賦予的。例如有命令行為: C:>E6 24 BASIC dbase FORTRAN由于文件名E6 24本身也算一個參數(shù),所以共有4個參數(shù),因此argc取得的值為4。argv參數(shù)是字符串指針數(shù)組,其各元素值為命令行中各字符串(參數(shù)均按字符串處理)的首地址。 指針數(shù)組的長度即為參數(shù)個數(shù)。數(shù)組元素初值由系統(tǒng)自動賦予。其表示如圖6.8所示:
main(int argc,char *argv){
while(argc-->1)
printf("%s ",*++argv);
}
本例是顯示命令行中輸入的參數(shù)如果上例的可執(zhí)行文件名為e24.exe,存放在A驅(qū)動器的盤內(nèi)。
因此輸入的命令行為: C:>a:e24 BASIC dBASE FORTRAN
則運行結(jié)果為:
BASIC
dBASE
FORTRAN
該行共有4個參數(shù),執(zhí)行main時,argc的初值即為4。argv的4個元素分為4個字符串的首地址。執(zhí)行while語句,每循環(huán)一次 argv值減1,當argv等于1時停止循環(huán),共循環(huán)三次, 因此共可輸出三個參數(shù)。在printf函數(shù)中,由于打印項*++argv是先加1再打印, 故第一次打印的是argv[1]所指的字符串BASIC。第二、 三次循環(huán)分別打印后二個字符串。而參數(shù)e24是文件名,不必輸出。
下例的命令行中有兩個參數(shù),第二個參數(shù)20即為輸入的n值。在程序中*++argv的值為字符串“20”,然后用函數(shù)"atoi"把它換為整型作為while語句中的循環(huán)控制變量,輸出20個偶數(shù)。
#include"stdlib.h"
main(int argc,char*argv[]){
int a=0,n;
n=atoi(*++argv);
while(n--) printf("%d ",a++*2);
}
本程序是從0開始輸出n個偶數(shù)。指向指針的指針變量如果一個指針變量存放的又是另一個指針變量的地址, 則稱這個指針變量為指向指針的指針變量。
在前面已經(jīng)介紹過,通過指針訪問變量稱為間接訪問, 簡稱間訪。由于指針變量直接指向變量,所以稱為單級間訪。 而如果通過指向指針的指針變量來訪問變量則構(gòu)成了二級或多級間訪。在C語言程序中,對間訪的級數(shù)并未明確限制, 但是間訪級數(shù)太多時不容易理解解,也容易出錯,因此,一般很少超過二級間訪。 指向指針的指針變量說明的一般形式為:
類型說明符** 指針變量名;
例如: int ** pp; 表示pp是一個指針變量,它指向另一個指針變量, 而這個指針變量指向一個整型量。下面舉一個例子來說明這種關(guān)系。
main(){
int x,*p,**pp;
x=10;
p=&x;
pp=&p;
printf("x=%d ",**pp);
}
上例程序中p 是一個指針變量,指向整型量x;pp也是一個指針變量, 它指向指針變量p。通過pp變量訪問x的寫法是**pp。程序最后輸出x的值為10。通過上例,讀者可以學(xué)習(xí)指向指針的指針變量的說明和使用方法。
下述程序中首先定義說明了指針數(shù)組ps并作了初始化賦值。 又說明了pps是一個指向指針的指針變量。在5次循環(huán)中, pps 分別取得了ps[0],ps[1],ps[2],ps[3],ps[4]的地址值(如圖6.10所示)。再通過這些地址即可找到該字符串。
main(){
static char *ps[]={ "BASIC","DBASE","C","FORTRAN","PASCAL"};
char **pps;
int i;
for(i=0;i<5;i++){
pps=ps+i;
printf("%s ",*pps);
}
}
本程序是用指向指針的指針變量編程,輸出多個字符串。
本章小結(jié)
1. 指針是C語言中一個重要的組成部分,使用指針編程有以下優(yōu)點:
(1)提高程序的編譯效率和執(zhí)行速度。
(2)通過指針可使用主調(diào)函數(shù)和被調(diào)函數(shù)之間共享變量或數(shù)據(jù)結(jié)構(gòu),便于實現(xiàn)雙向數(shù)據(jù)通訊。
(3)可以實現(xiàn)動態(tài)的存儲分配。
(4)便于表示各種數(shù)據(jù)結(jié)構(gòu),編寫高質(zhì)量的程序。
2. 指針的運算
(1)取地址運算符&:求變量的地址
(2)取內(nèi)容運算符*:表示指針所指的變量
(3)賦值運算
·把變量地址賦予指針變量
·同類型指針變量相互賦值
·把數(shù)組,字符串的首地址賦予指針變量
·把函數(shù)入口地址賦予指針變量
(4)加減運算
對指向數(shù)組,字符串的指針變量可以進行加減運算,如p+n,p-n,p++,p--等。對指向同一數(shù)組的兩個指針變量可以相減。對指向其它類型的指針變量作加減運算是無意義的。
(5)關(guān)系運算
指向同一數(shù)組的兩個指針變量之間可以進行大于、小于、 等于比較運算。指針可與0比較,p==0表示p為空指針。
3. 與指針有關(guān)的各種說明和意義見下表。
int *p; p為指向整型量的指針變量
int *p[n]; p為指針數(shù)組,由n個指向整型量的指針元素組成。
int (*p)[n]; p為指向整型二維數(shù)組的指針變量,二維數(shù)組的列數(shù)為n
int *p() p為返回指針值的函數(shù),該指針指向整型量
int (*p)() p為指向函數(shù)的指針,該函數(shù)返回整型量
int **p p為一個指向另一指針的指針變量,該指針指向一個整型量。
4. 有關(guān)指針的說明很多是由指針,數(shù)組,函數(shù)說明組合而成的。
但并不是可以任意組合,例如數(shù)組不能由函數(shù)組成,即數(shù)組元素不能是一個函數(shù);函數(shù)也不能返回一個數(shù)組或返回另一個函數(shù)。例如
int a[5]();就是錯誤的。
5. 關(guān)于括號
在解釋組合說明符時, 標識符右邊的方括號和圓括號優(yōu)先于標識符左邊的“*”號,而方括號和圓括號以相同的優(yōu)先級從左到右結(jié)合。但可以用圓括號改變約定的結(jié)合順序。
6. 閱讀組合說明符的規(guī)則是“從里向外”。
從標識符開始,先看它右邊有無方括號或園括號,如有則先作出解釋,再看左邊有無*號。 如果在任何時候遇到了閉括號,則在繼續(xù)之前必須用相同的規(guī)則處理括號內(nèi)的內(nèi)容。例如:
int*(*(*a)())[10]
↑ ↑↑↑↑↑↑
7 6 4 2 1 3 5
上面給出了由內(nèi)向外的閱讀順序,下面來解釋它:
(1)標識符a被說明為;
(2)一個指針變量,它指向;
(3)一個函數(shù),它返回;
(4)一個指針,該指針指向;
(5)一個有10個元素的數(shù)組,其類型為;
(6)指針型,它指向;
(7)int型數(shù)據(jù)。
因此a是一個函數(shù)指針變量,該函數(shù)返回的一個指針值又指向一個指針數(shù)組,該指針數(shù)組的元素指向整型量。
基本數(shù)據(jù)類型
void:聲明函數(shù)無返回值或無參數(shù),聲明無類型指針,顯示丟棄運算結(jié)果。(C89標準新增)
char:字符型類型數(shù)據(jù),屬于整型數(shù)據(jù)的一種。(K&R時期引入)
int:整型數(shù)據(jù),表示范圍通常為編譯器指定的內(nèi)存字節(jié)長。(K&R時期引入)
float:單精度浮點型數(shù)據(jù),屬于浮點數(shù)據(jù)的一種。(K&R時期引入)
double:雙精度浮點型數(shù)據(jù),屬于浮點數(shù)據(jù)的一種。(K&R時期引入)
-Bool:布爾型(C99標準新增)
-Complex:復(fù)數(shù)的基本類型(C99標準新增)
-Imaginary:虛數(shù),與復(fù)數(shù)基本類型相似,沒有實部的純虛數(shù)(C99標準新增)
-Generic:提供重載的接口入口(C11標準新增)
類型修飾關(guān)鍵字
short:修飾int,短整型數(shù)據(jù),可省略被修飾的int。(K&R時期引入)
long:修飾int,長整型數(shù)據(jù),可省略被修飾的int。(K&R時期引入)
long long:修飾int,超長整型數(shù)據(jù),可省略被修飾的int。(C99標準新增)
signed:修飾整型數(shù)據(jù),有符號數(shù)據(jù)類型。(C89標準新增)
unsigned:修飾整型數(shù)據(jù),無符號數(shù)據(jù)類型。(K&R時期引入)
restrict:用于限定和約束指針,并表明指針是訪問一個數(shù)據(jù)對象的唯一且初始的方式。(C99標準新增)
復(fù)雜類型關(guān)鍵字
struct:結(jié)構(gòu)體聲明。(K&R時期引入)
union:聯(lián)合體聲明。(K&R時期引入)
enum:枚舉聲明。(C89標準新增)
typedef:聲明類型別名。(K&R時期引入)
sizeof:得到特定類型或特定類型變量的大小。(K&R時期引入)
inline:內(nèi)聯(lián)函數(shù)用于取代宏定義,會在任何調(diào)用它的地方展開。(C99標準新增)
存儲級別關(guān)鍵字
auto:指定為自動變量,由編譯器自動分配及釋放。通常在棧上分配。與static相反。當變量未指定時默認為auto。(K&R時期引入)
static:指定為靜態(tài)變量,分配在靜態(tài)變量區(qū),修飾函數(shù)時,指定函數(shù)作用域為文件內(nèi)部。(K&R時期引入)
register:指定為寄存器變量,建議編譯器將變量存儲到寄存器中使用,也可以修飾函數(shù)形參,建議編譯器通過寄存器而不是堆棧傳遞參數(shù)。(K&R時期引入)
extern:指定對應(yīng)變量為外部變量,即標示變量或者函數(shù)的定義在別的文件中,提示編譯器遇到此變量和函數(shù)時在其他模塊中尋找其定義。(K&R時期引入)
const:指定變量不可被當前線程改變(但有可能被系統(tǒng)或其他線程改變)。(C89標準新增)
volatile:指定變量的值有可能會被系統(tǒng)或其他線程改變,強制編譯器每次從內(nèi)存中取得該變量的值,阻止編譯器把該變量優(yōu)化成寄存器變量。(C89標準新增)
流程控制關(guān)鍵字
跳轉(zhuǎn)結(jié)構(gòu)
return:用在函數(shù)體中,返回特定值(如果是void類型,則不返回函數(shù)值)。(K&R時期引入)
continue:結(jié)束當前循環(huán),開始下一輪循環(huán)。(K&R時期引入)
break:跳出當前循環(huán)或switch結(jié)構(gòu)。(K&R時期引入)
goto:無條件跳轉(zhuǎn)語句。(K&R時期引入)
分支結(jié)構(gòu)
if:條件語句,后面不需要放分號。(K&R時期引入)
else:條件語句否定分支(與if連用)。(K&R時期引入)
switch:開關(guān)語句(多重分支語句)。(K&R時期引入)
case:開關(guān)語句中的分支標記,與switch連用。(K&R時期引入)
default:開關(guān)語句中的“其他”分支,可選。(K&R時期引入)
編譯
#define 預(yù)編譯宏
#if 表達式 #else if 表達式 #else #endif 條件編譯
#ifdef 宏 #else #endif 條件編譯
#ifndef 宏 #else #endif 條件編譯與條件編譯
c語言知識易錯點
1.書寫標識符時,忽略了大小寫字母的區(qū)別。
2.忽略了變量的類型,進行了不合法的運算。
3.將字符常量與字符串常量混淆。
4.忽略了“=”與“==”的區(qū)別。
5.忘記加分號。分號是C語句中不可缺少的一部分,語句末尾必須有分號。
6.多加分號。 復(fù)合語句的花括號后不應(yīng)再加分號,否則將會畫蛇添足。
7.輸入變量時忘記加地址運算符“&”。
8.輸入數(shù)據(jù)的方式與要求不符。代碼①scanf("%d%d",&a,&b);輸入時,不能用逗號作兩個數(shù)據(jù)間的分隔符②scanf("%d,%d",&a,&b);C規(guī)定:如果在“格式控制”字符串中除了格式說明以外還有其它字符,則在輸入數(shù)據(jù)時應(yīng)輸入與這些字符相同的字符。
9.輸入字符的格式與要求不一致。在用“%c”格式輸入字符時,“空格字符”和“轉(zhuǎn)義字符”都作為有效字符輸入。
10.輸入輸出的數(shù)據(jù)類型與所用格式說明符不一致。
11.輸入數(shù)據(jù)時,企圖規(guī)定精度。
12.switch語句中漏寫break語句。
13.忽視了while和do-while語句在細節(jié)上的區(qū)別。
14.定義數(shù)組時誤用變量。
15.在定義數(shù)組時,將定義的“元素個數(shù)”誤認為是可使的最大下標值。
16.初始化數(shù)組時,未使用靜態(tài)存儲。
17.在不應(yīng)加地址運算符&的位置加了地址運算符。
18.同時定義了形參和函數(shù)中的局部變量。
【c語言重點知識點總結(jié)】相關(guān)文章:
大學(xué)c語言知識點總結(jié)03-15
兒科重點知識點總結(jié)08-09
稅法重點知識點總結(jié)07-13
初識c語言實驗總結(jié)09-30
高考地理重點知識點總結(jié)11-08
初中數(shù)學(xué)重點知識點總結(jié)10-12
春望重點知識點總結(jié)12-01
c語言練習(xí)試題11-14