亚洲精品中文字幕无乱码_久久亚洲精品无码AV大片_最新国产免费Av网址_国产精品3级片

C語言

C語言基礎(chǔ)知識

時間:2024-10-13 10:45:01 如意 C語言 我要投稿

C語言基礎(chǔ)知識

  C語言是一門面向過程的、抽象化的通用程序設(shè)計語言,廣泛應(yīng)用于底層開發(fā)。C語言能以簡易的方式編譯、處理低級存儲器,下面是小編收集整理的C語言基礎(chǔ)知識,希望對大家有幫助!

C語言基礎(chǔ)知識

  指針簡介

  指針是C語言中廣泛使用的一種數(shù)據(jù)類型。運(yùn)用指針編程是C語言最主要的風(fēng)格之一。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu); 能很方便地使用數(shù)組和字符串; 并能象匯編語言一樣處理內(nèi)存地址,從而編出精練而高效的程序。指針極大地豐富了C語言的功能。 學(xué)習(xí)指針是學(xué)習(xí)C語言中最重要的一環(huán), 能否正確理解和使用指針是我們是否掌握C語言的一個標(biāo)志。同時, 指針也是C語言中最為困難的一部分,在學(xué)習(xí)中除了要正確理解基本概念,還必須要多編程,上機(jī)調(diào)試。只要作到這些,指針也是不難掌握的。

  指針的基本概念

  在計算機(jī)中,所有的數(shù)據(jù)都是存放在存儲器中的。 一般把存儲器中的一個字節(jié)稱為一個內(nèi)存單元, 不同的數(shù)據(jù)類型所占用的內(nèi)存單元數(shù)不等,如整型量占2個單元,字符量占1個單元等, 在第二章中已有詳細(xì)的介紹。為了正確地訪問這些內(nèi)存單元, 必須為每個內(nèi)存單元編上號。 根據(jù)一個內(nèi)存單元的編號即可準(zhǔn)確地找到該內(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碼為十進(jìn)制數(shù) 75),C占用了011A號單元(地址用十六進(jìn)數(shù)表示)。設(shè)有指針變量P,內(nèi)容為011A, 這種情況我們稱為P指向變量C,或說P是指向變量C的指針。 嚴(yán)格地說,一個指針是一個地址, 是一個常量。而一個指針變量卻可以被賦予不同的指針值,是變。 但在常把指針變量簡稱為指針。為了避免混淆,我們中約定:“指針”是指地址, 是常量,“指針變量”是指取值為地址的變量。 定義指針的目的是為了通過指針去訪問內(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是指向浮點(diǎn)變量的指針變量*/

  char *p4; /*p4是指向字符變量的指針變量*/ 應(yīng)該注意的是,一個指針變量只能指向同類型的變量,如P3 只能指向浮點(diǎn)變量,不能時而指向一個浮點(diǎn)變量, 時而又指向一個字符變量。

  指針變量的賦值

  指針變量同普通變量一樣,使用之前不僅要定義說明, 而且必須賦予具體的值。未經(jīng)賦值的指針變量不能使用, 否則將造成系統(tǒng)混亂,甚至死機(jī)。指針變量的賦值只能賦予地址, 決不能賦予任何其它數(shù)據(jù),否則將引起錯誤。在C語言中, 變量的地址是由編譯系統(tǒng)分配的,對用戶完全透明,用戶不知道變量的具體地址。 C語言中提供了地址運(yùn)算符&來表示變量的地址。其一般形式為: & 變量名; 如&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 也是錯誤的

  指針變量的運(yùn)算

  指針變量可以進(jìn)行某些運(yùn)算,但其運(yùn)算的種類是有限的。 它只能進(jìn)行賦值運(yùn)算和部分算術(shù)運(yùn)算及關(guān)系運(yùn)算。

  1.指針運(yùn)算符

  (1)取地址運(yùn)算符&

  取地址運(yùn)算符&是單目運(yùn)算符,其結(jié)合性為自右至左,其功能是取變量的地址。在scanf函數(shù)及前面介紹指針變量賦值中,我們已經(jīng)了解并使用了&運(yùn)算符。

  (2)取內(nèi)容運(yùn)算符*

  取內(nèi)容運(yùn)算符*是單目運(yùn)算符,其結(jié)合性為自右至左,用來表示指針變量所指的變量。在*運(yùn)算符之后跟的變量必須是指針變量。需要注意的是指針運(yùn)算符*和指針變量說明中的指針說明符* 不是一回事。在指針變量說明中,“*”是類型說明符,表示其后的變量是指針類型。而表達(dá)式中出現(xiàn)的“*”則是一個運(yùn)算符用以表示指針變量所指的變量。

  main(){

  int a=5,*p=&a;

  printf ("%d",*p);

  }

  ......

  表示指針變量p取得了整型變量a的地址。本語句表示輸出變量a的值。

  2.指針變量的運(yùn)算

  (1)賦值運(yùn)算

  指針變量的賦值運(yùn)算有以下幾種形式:

 、僦羔樧兞砍跏蓟x值,前面已作介紹。

 、诎岩粋變量的地址賦予指向相同數(shù)據(jù)類型的指針變量。例如:

  int a,*pa;

  pa=&a; /*把整型變量a的地址賦予整型指針變量pa*/

 、郯岩粋指針變量的值賦予指向相同類型變量的另一個指針變量。如:

  int a,*pa=&a,*pb;

  pb=pa; /*把a(bǔ)的地址賦予指針變量pb*/

  由于pa,pb均為指向整型變量的指針變量,因此可以相互賦值。 ④把數(shù)組的首地址賦予指向數(shù)組的指針變量。

  例如: int a[5],*pa;

  pa=a; (數(shù)組名表示數(shù)組的首地址,故可賦予指向數(shù)組的指針變量pa)

  也可寫為:

  pa=&a[0]; /*數(shù)組第一個元素的地址也是整個數(shù)組的首地址,

  也可賦予pa*/

  當(dāng)然也可采取初始化賦值的方法:

  int a[5],*pa=a;

 、莅炎址氖椎刂焚x予指向字符類型的指針變量。例如: char *pc;pc="c language";或用初始化賦值的方法寫為: char *pc="C Language"; 這里應(yīng)說明的是并不是把整個字符串裝入指針變量, 而是把存放該字符串的字符數(shù)組的首地址裝入指針變量。 在后面還將詳細(xì)介紹。

 、薨押瘮(shù)的入口地址賦予指向函數(shù)的指針變量。例如: int (*pf)();pf=f; /*f為函數(shù)名*/

  (2)加減算術(shù)運(yùn)算

  對于指向數(shù)組的指針變量,可以加上或減去一個整數(shù)n。設(shè)pa是指向數(shù)組a的指針變量,則pa+n,pa-n,pa++,++pa,pa--,--pa 運(yùn)算都是合法的。指針變量加或減一個整數(shù)n的意義是把指針指向的當(dāng)前位置(指向某數(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]*/ 指針變量的加減運(yùn)算只能對數(shù)組指針變量進(jìn)行, 對指向其它類型變量的指針變量作加減運(yùn)算是毫無意義的。(3)兩個指針變量之間的運(yùn)算只有指向同一數(shù)組的兩個指針變量之間才能進(jìn)行運(yùn)算, 否則運(yùn)算毫無意義。

 、賰芍羔樧兞肯鄿p

  兩指針變量相減所得之差是兩個指針?biāo)笖?shù)組元素之間相差的元素個數(shù)。實際上是兩個指針值(地址) 相減之差再除以該數(shù)組元素的長度(字節(jié)數(shù))。例如pf1和pf2 是指向同一浮點(diǎn)數(shù)組的兩個指針變量,設(shè)pf1的值為2010H,pf2的值為2000H,而浮點(diǎn)數(shù)組每個元素占4個字節(jié),所以pf1-pf2的結(jié)果為(2000H-2010H)/4=4,表示pf1和 pf2之間相差4個元素。兩個指針變量不能進(jìn)行加法運(yùn)算。 例如, pf1+pf2是什么意思呢?毫無實際意義。

  ②兩指針變量進(jìn)行關(guān)系運(yùn)算

  指向同一數(shù)組的兩指針變量進(jìn)行關(guān)系運(yù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ù)組元素(下標(biāo)變量) 組成的。每個數(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ù)組元素了。

  第一種方法為下標(biāo)法,即用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ù)組的首地址,當(dāng)然也可作為函數(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,各下標(biāo)變量的首地址及其值如圖所示。在第四章中介紹過, 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);

  }

  運(yùn)行結(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);

  }

  運(yùn)行結(jié)果為:

  book 在程序中對ps初始化時,即把字符串首地址賦予ps,當(dāng)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指向目標(biāo)字符串。表達(dá)式:

  (*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所指向的目標(biāo)字符中,二是判斷所復(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++)!=`');}

  即把指針的移動和賦值合并在一個語句中。 進(jìn)一步分析還可發(fā)現(xiàn)`'的ASCⅡ碼為0,對于while語句只看表達(dá)式的值為非0就循環(huán),為0則結(jié)束循環(huán),因此也可省去“!=`'”這一判斷部分,而寫為以下形式:

  cprstr (char *pss,char *pds)

  {while (*pdss++=*pss++);}

  表達(dá)式的意義可解釋為,源字符向目標(biāo)字符賦值, 移動指針,若所賦值為非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)字符串的存儲和運(yù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ù)組的各元素逐個賦值。

  從以上幾點(diǎn)可以看出字符串指針變量與字符數(shù)組在使用時的區(qū)別,同時也可看出使用指針變量更加方便。前面說過,當(dāng)一個指針變量在未取得確定地址前使用是危險的,容易引起錯誤。但是對指針變量直接賦值是可以的。因為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)注意以下兩點(diǎn):

  a. 函數(shù)指針變量不能進(jìn)行算術(shù)運(yùn)算,這是與數(shù)組指針變量不同的。數(shù)組指針變量加減一個整數(shù)可使指針移動指向后面或前面的數(shù)組元素,而函數(shù)指針的移動是毫無意義的。

  b. 函數(shù)調(diào)用中"(*指針變量名)"的兩邊的括號不可少,其中的*不應(yīng)該理解為求值運(yùn)算,在此處它只是一種表示符號。

  指針型函數(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語句包含一個條件表達(dá)式, n 值若大于7或小于1則把name[0] 指針返回主函數(shù)輸出出錯提示字符串“Illegal day”。否則返回主函數(shù)輸出對應(yīng)的星期名。主函數(shù)中的第7行是個條件語句,其語義是,如輸入為負(fù)數(shù)(i<0)則中止程序運(yùn)行退出程序。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列的值。讀者可仔細(xì)領(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ù)組,有三個下標(biāo)變量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)。由條件表達(dá)式?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í)行的速度很慢,同時由于各字符串(國名) 的長度不同,又增加了存儲管理的負(fù)擔(dān)。 用指針數(shù)組能很好地解決這些問題。把所有的字符串存放在一個數(shù)組中, 把這些字符數(shù)組的首地址放在一個指針數(shù)組中,當(dāng)需要交換兩個字符串時, 只須交換指針數(shù)組相應(yīng)兩元素的內(nèi)容(地址)即可,而不必交換字符串本身。程序中定義了兩個函數(shù),一個名為sort完成排序, 其形參為指

  針數(shù)組name,即為待排序的各字符串?dāng)?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ù)組元素的值,而不交換具體的字符串, 這樣將大大減少時間的開銷,提高了運(yùn)行效率。

  現(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ù)可以認(rèn)為是 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)命令行上獲得的。當(dāng)我們要運(yùn)行一個可執(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

  則運(yùn)行結(jié)果為:

  BASIC

  dBASE

  FORTRAN

  該行共有4個參數(shù),執(zhí)行main時,argc的初值即為4。argv的4個元素分為4個字符串的首地址。執(zhí)行while語句,每循環(huán)一次 argv值減1,當(dāng)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)點(diǎn):

  (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. 指針的運(yùn)算

  (1)取地址運(yùn)算符&:求變量的地址

  (2)取內(nèi)容運(yùn)算符*:表示指針?biāo)傅淖兞?/p>

  (3)賦值運(yùn)算

  ·把變量地址賦予指針變量

  ·同類型指針變量相互賦值

  ·把數(shù)組,字符串的首地址賦予指針變量

  ·把函數(shù)入口地址賦予指針變量

  (4)加減運(yùn)算

  對指向數(shù)組,字符串的指針變量可以進(jìn)行加減運(yùn)算,如p+n,p-n,p++,p--等。對指向同一數(shù)組的兩個指針變量可以相減。對指向其它類型的指針變量作加減運(yùn)算是無意義的。

  (5)關(guān)系運(yùn)算

  指向同一數(shù)組的兩個指針變量之間可以進(jìn)行大于、小于、 等于比較運(yùn)算。指針可與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)于括號

  在解釋組合說明符時, 標(biāo)識符右邊的方括號和圓括號優(yōu)先于標(biāo)識符左邊的“*”號,而方括號和圓括號以相同的優(yōu)先級從左到右結(jié)合。但可以用圓括號改變約定的結(jié)合順序。

  6. 閱讀組合說明符的規(guī)則是“從里向外”。

  從標(biāo)識符開始,先看它右邊有無方括號或園括號,如有則先作出解釋,再看左邊有無*號。 如果在任何時候遇到了閉括號,則在繼續(xù)之前必須用相同的規(guī)則處理括號內(nèi)的內(nèi)容。例如:

  int*(*(*a)())[10]

  ↑ ↑↑↑↑↑↑

  7 6 4 2 1 3 5

  上面給出了由內(nèi)向外的閱讀順序,下面來解釋它:

  (1)標(biāo)識符a被說明為;

  (2)一個指針變量,它指向;

  (3)一個函數(shù),它返回;

  (4)一個指針,該指針指向;

  (5)一個有10個元素的數(shù)組,其類型為;

  (6)指針型,它指向;

  (7)int型數(shù)據(jù)。

  因此a是一個函數(shù)指針變量,該函數(shù)返回的一個指針值又指向一個指針數(shù)組,該指針數(shù)組的元素指向整型量。

  基本數(shù)據(jù)類型

  void:聲明函數(shù)無返回值或無參數(shù),聲明無類型指針,顯示丟棄運(yùn)算結(jié)果。(C89標(biāo)準(zhǔn)新增)

  char:字符型類型數(shù)據(jù),屬于整型數(shù)據(jù)的一種。(K&R時期引入)

  int:整型數(shù)據(jù),表示范圍通常為編譯器指定的內(nèi)存字節(jié)長。(K&R時期引入)

  float:單精度浮點(diǎn)型數(shù)據(jù),屬于浮點(diǎn)數(shù)據(jù)的一種。(K&R時期引入)

  double:雙精度浮點(diǎn)型數(shù)據(jù),屬于浮點(diǎn)數(shù)據(jù)的一種。(K&R時期引入)

  -Bool:布爾型(C99標(biāo)準(zhǔn)新增)

  -Complex:復(fù)數(shù)的基本類型(C99標(biāo)準(zhǔn)新增)

  -Imaginary:虛數(shù),與復(fù)數(shù)基本類型相似,沒有實部的純虛數(shù)(C99標(biāo)準(zhǔn)新增)

  -Generic:提供重載的接口入口(C11標(biāo)準(zhǔn)新增)

  類型修飾關(guān)鍵字

  short:修飾int,短整型數(shù)據(jù),可省略被修飾的int。(K&R時期引入)

  long:修飾int,長整型數(shù)據(jù),可省略被修飾的int。(K&R時期引入)

  long long:修飾int,超長整型數(shù)據(jù),可省略被修飾的int。(C99標(biāo)準(zhǔn)新增)

  signed:修飾整型數(shù)據(jù),有符號數(shù)據(jù)類型。(C89標(biāo)準(zhǔn)新增)

  unsigned:修飾整型數(shù)據(jù),無符號數(shù)據(jù)類型。(K&R時期引入)

  restrict:用于限定和約束指針,并表明指針是訪問一個數(shù)據(jù)對象的唯一且初始的方式。(C99標(biāo)準(zhǔn)新增)

  復(fù)雜類型關(guān)鍵字

  struct:結(jié)構(gòu)體聲明。(K&R時期引入)

  union:聯(lián)合體聲明。(K&R時期引入)

  enum:枚舉聲明。(C89標(biāo)準(zhǔn)新增)

  typedef:聲明類型別名。(K&R時期引入)

  sizeof:得到特定類型或特定類型變量的大小。(K&R時期引入)

  inline:內(nèi)聯(lián)函數(shù)用于取代宏定義,會在任何調(diào)用它的地方展開。(C99標(biāo)準(zhǔn)新增)

  存儲級別關(guān)鍵字

  auto:指定為自動變量,由編譯器自動分配及釋放。通常在棧上分配。與static相反。當(dāng)變量未指定時默認(rèn)為auto。(K&R時期引入)

  static:指定為靜態(tài)變量,分配在靜態(tài)變量區(qū),修飾函數(shù)時,指定函數(shù)作用域為文件內(nèi)部。(K&R時期引入)

  register:指定為寄存器變量,建議編譯器將變量存儲到寄存器中使用,也可以修飾函數(shù)形參,建議編譯器通過寄存器而不是堆棧傳遞參數(shù)。(K&R時期引入)

  extern:指定對應(yīng)變量為外部變量,即標(biāo)示變量或者函數(shù)的定義在別的文件中,提示編譯器遇到此變量和函數(shù)時在其他模塊中尋找其定義。(K&R時期引入)

  const:指定變量不可被當(dāng)前線程改變(但有可能被系統(tǒng)或其他線程改變)。(C89標(biāo)準(zhǔn)新增)

  volatile:指定變量的值有可能會被系統(tǒng)或其他線程改變,強(qiáng)制編譯器每次從內(nèi)存中取得該變量的值,阻止編譯器把該變量優(yōu)化成寄存器變量。(C89標(biāo)準(zhǔn)新增)

  流程控制關(guān)鍵字

  跳轉(zhuǎn)結(jié)構(gòu)

  return:用在函數(shù)體中,返回特定值(如果是void類型,則不返回函數(shù)值)。(K&R時期引入)

  continue:結(jié)束當(dāng)前循環(huán),開始下一輪循環(huán)。(K&R時期引入)

  break:跳出當(dāng)前循環(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)語句中的分支標(biāo)記,與switch連用。(K&R時期引入)

  default:開關(guān)語句中的“其他”分支,可選。(K&R時期引入)

  編譯

  #define 預(yù)編譯宏

  #if 表達(dá)式 #else if 表達(dá)式 #else #endif 條件編譯

  #ifdef 宏 #else #endif 條件編譯

  #ifndef 宏 #else #endif 條件編譯與條件編譯

  c語言知識易錯點(diǎn)

  1.書寫標(biāo)識符時,忽略了大小寫字母的區(qū)別。

  2.忽略了變量的類型,進(jìn)行了不合法的運(yùn)算。

  3.將字符常量與字符串常量混淆。

  4.忽略了“=”與“==”的區(qū)別。

  5.忘記加分號。分號是C語句中不可缺少的一部分,語句末尾必須有分號。

  6.多加分號。 復(fù)合語句的花括號后不應(yīng)再加分號,否則將會畫蛇添足。

  7.輸入變量時忘記加地址運(yùn)算符“&”。

  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語句在細(xì)節(jié)上的區(qū)別。

  14.定義數(shù)組時誤用變量。

  15.在定義數(shù)組時,將定義的“元素個數(shù)”誤認(rèn)為是可使的最大下標(biāo)值。

  16.初始化數(shù)組時,未使用靜態(tài)存儲。

  17.在不應(yīng)加地址運(yùn)算符&的位置加了地址運(yùn)算符。

  18.同時定義了形參和函數(shù)中的局部變量。

【C語言基礎(chǔ)知識】相關(guān)文章:

c語言入門基礎(chǔ)知識07-18

C語言基礎(chǔ)知識匯總12-02

C語言字符型基礎(chǔ)知識11-18

c語言之指針基礎(chǔ)知識12-04

C語言位運(yùn)算基礎(chǔ)知識02-20

計算機(jī)c語言基礎(chǔ)知識06-06

C語言基礎(chǔ)知識點(diǎn)集錦05-23

C語言指針和數(shù)組基礎(chǔ)知識12-03

C語言循環(huán)基礎(chǔ)知識附代碼示例04-12