全國二級C知識點總結4-指針

  • 2019 年 11 月 21 日
  • 筆記

本課重要知識點:

1.知識點:指針的概念與指針變數

l 指針就是地址指針變數是用來存儲地址,而一般變數是用來存儲數值

例1.(09-09-26)有如下程式輸出結果為 1,2,2,1

#include <stdio.h>

main()

{ int m=1,n=2,*p=&m,*q=&n,*r;

r=p ;p=q ;q=r ;

printf(「%d,%d,%d,%dn」,m,n,*p,*q) ;

}

【解析】p、q為指針,初始化時p指向m,q指向n。執行r=p ;p=q ;q=r ;p和q的值交換,從而p指向n,q指向m。指針的改變不會應用m、n的值,最後輸出*p和*q的值分別為n、m的值。

2.知識點:指針的引用

l 指針的引用是通過兩個運算符實現「&」和「*」實現的

&是取地址符號,它的一半格式是:&變數名。例如:int i ; &i表示取i的地址。

*是取值運算符,它的一般格式:*指針變數名。例如:inti=10,*p=&i; *p表示取i的值10

例1.(2011-09-25)若定義語句:intyear=2009,*p=&year;,以下不能使變數year中的值增至2010的語句是 (D)

A.*p+=1; B.(*p)++; C.++(*p); D.*p++;

【解析】*和++同級別,按自左向右的結合方向,因此D選項可轉變為*(p++),從而只是使指針發生移動,而不能將p所指變數增1

例2.(06—04—24)若有說明語句:double *p,a;則能通過scanf語句正確給輸入項讀入數據的程式段是 (D)

A)*p=&a; scanf("%lf",p);

B)*p=&a; scanf("%f",p);

C)p=&a; scanf("%lf",*p);

D)p=&a; scanf("%lf",p);

【解析】對於scanf函數,輸入數據列表必須是合法地址表達式(可以使地

址常量、指針),A選項、B選項*使用錯誤。

例3.(09-03-16)若有定義語句 doule x,y,*px,*py;執行了px=&x;py=&y;之後,正確的輸入語句是(C)

A) scanf("%f%f",x,y); B) scanf("%f%f"&x,&y);

C)scanf("%f%le",px,py); D) scanf("%lf%lf",x,y);

【解析】A,D選項中的x,y缺少取地址符,B項中&x之前缺少逗號,格式不正確。

3.知識點:指針變數的初始化

l 指針變數在使用前必須要初始化,把一個具體的地址賦給它,否則引用時會出錯,如果不指向任何數據就賦「空值」NULL。

l 指針變數兩種初始化方法:方法一:int a=2,*p=&a;(定義的同時初始化)

方法二:int a=2,*p;p=&a;(先定義後初始化)

例1.(07—04—29)設已有定義:float x;則以下對指針變數P進行定義且賦初值的語句中正確的是 (D)

A)float *p=1034; B)int *p=(float)x; C)float p=&x; D)float *p=&x;

【解析】可以給一個指針賦值的只能是一個與該指針同類型的指針(或地址值);故A、B選項錯誤;C選項聲明指針出錯,P前面的指針說明符*不能省略。

4.知識點:指針的運算

l *p++和(*p)++之間的差別:*p++是地址變化,(*p)++是指針變數所指的數據變化。一個指針變數加一個整數不是簡單的數學相加,而是連續移動若干地址。當兩個指針指向同一數組時,它們可以比較大小進行減法運算。

例如:int a[10],*p; p=a; p++;表示p移動一個存儲單元,p指向a[1],只有當指著指向數組元素時,指針的運動才有意義。

5:知識點:指針與數組

l 指針與一維數組

數組名代表數組的首地址。一維數組中,第一個元素的地址即為該數組的起始地址。建立指針變數與一維數組的聯繫:

例如: inta[6],*pa; pa=a;或pa=&a[0];

說明:①數組名a代表該數組的首地址,也即a[0]的地址。

② pa=a;或pa=&a[0];使pa保存了數組a的首地址,pa,a,&a[0]都指向一個地址。

③以上操作可等價於 int a[6],*pa=a;

④如果pa=&a[3];表示*pa的值就是a[3]的地址。

注意:數組a是一個地址常量,它永遠指向數組的首地址,不能重新賦值。因此 a=&i;或a++都是錯誤的。

例1.(08—04—23)有以下程式

#include<stdio.h>

main()

{int a[]={1,2,3,4),y,*p=&a[3];

–p;y=*p;printf("y=%dn",y);

} 程式的運行結果是(D)

A)y=0 B)y=l C)y=2 D)y=3

【解析】程式中定義一個一維數組,並初始化,再一定義了一變數和一個指針(將指針指向數組下標為3的一個元素),執行–p;(注意,當指針指一個元素後,指針變數加上「*」時,表示引用的是元素的值,當不加「*「時表示引用的是地址),向前移動一個位置,指向a[2],y=+p;(將p指針指向的值3賦給變數y),輸出y的值為3。

例2.(11-03-24)設有定義:double x[10],*p=x;,以下能給數組x下標為6的元素讀入數據的正確語句是( C )

A)scanf("%f",&x[6]); B)scanf("%lf",*(x+6));

C)scanf("%lf",p+6); D)scanf("%lf",p[6]);

【解析】數組名是數組的首地址,p=x,指針p指向數組的首地址,要表示數組x下標為6的元素的地址可以有&x[6],x+6,p+6,&p[6],scanf後面的參數列表必須是地址列表,B中*(x+6)D中p[6]都是取數組x下標為6的元素的值,A中格式控制符%f與double類型不匹配,所以選C。

6.知識點:用指針訪問數組元素

l 通過指針引用數組元素

例如:int*p,a[5]; p=&a[0];

說明:①指針變數p指向了數組元素a[0],可以使用訪問運算符「*」來引用變數a[0];

例:*p=18;等價於a[0]=18;

②*(p+1)表示a[1] p+1表示&a[1]

l 通過數組的首地址引用數組元素

例如:int a[5];

說明:①a是數組名,表示收地址,可以把a當做一個指針常量。

②*a等價與a[0],*(a+1)等價與a[1];a等價於&a[0],a+1等價與&a[1];

l 用帶下標的指針變數引用一維數組元素

例如:int*p,a[5]; p=a;

說明:①p[0]表示p指針指向的記憶體單元,p[1]表示p指向的記憶體單元

②a[i]的等價引用方法:a[i]、p[i]、*(a+i)、*(p+i)

③a[i]的地址等價引用方法:&a[i]、&p[i]、a+i、p+i

例1.(09-03—29)若有以下定義

int x[10],*pt=x;

則對x數組元素的正確應用是 B

A)*&x[10] B)*(x+3) C)*(pt+10) D)pt+3

【解析】引用數組元素時,注意取地址運算符&與指針運算符t的作用;指針運算符+用來取得指針變數所指存儲空間的內容,取地址運算符&用來取得變數的地址值;A選項數組下標越界;B選項中+(x+3)等價於元素X[3];C選項中。(pt+10)等價於x[10],數組下標越界;D選項pt+3是元素x[3]的地址,與&x[3]等價;故正確答案是B。正確答案:B

例1.(2011-09-27)有以下程式

#include <stdio.h>

void fun(int *p)

{printf(「%dn」,p[5]);}

main()

{int a[10]={1,2,3,4,5,6,7,8,9,10};

fun(&a[3]);

}程式運行後的輸出結果是 (D)

A.5 B.6 C.8 D.9

【解析】fun函數被調用時將&a[3]通過傳遞付給了形參指針變數p,此時可用*p或p[0]來表示a[3],因此p[5]亦可表示a[8],所以輸出結果為9

7.知識點:指針與二維數組

l 任何一個二維數組均由若干個一維數組組成,a[0]、a[1]和a[2]是一維數組名,數組名代表數組的首地址,因此a[0]就代表數組元素a[0][0]的地址,也即&a[0][0]。

注意:a的值與a[0]相同,但它們的基類型不同,a可以等價於一個二維指針,而a[0]是一維指針。因此 int a[3][4],*p=a;錯誤

取數組元素a[i][j]的地址的幾種方法:&a[i][j];a[i]+j; *(a+i)+j;

l 指針數組的定義方式:

*指針數組名[常量表達式];如:int *p[3];

l 行指針的一般定義形式如下:

類型名(*指針數組名)[常量表達式]; 如:int (*p)[2];

l 指針數組與行指針的區別

1、int *p[3];定義的是指針數組,表示一個數組,含有3個元素p[0]、p[1]、p[2],且這3個元素只能存放整型元素的地址

2、int (*p)[3];定義的是行指針,表示一個指針變數,它僅有一個存儲空間,只能存放一個長度為2的一維數組指針。

例1.(06—09—33)若有定義語句:int k[2][3],*pk[3];則以下語句正確的是(B)

A)pk=k; B)pk[0]=&k[1][2]; C)pk=k[0]; D)pk[1]=k;

【解析】題目中定義了一個二維數組和一個指針數組,pk是指針數組名,不能被賦值,指針數組pk中的元素是指針,並且二維數組名是指向一維數組的指針常量,相當於行指針,二者不可轉換,所以A、C、D選項均有誤,本題答案選B。

例2.(09-09-27) 若有定義語句: int a[4][10],*p,*q[4];且0<=i<4,則錯誤的賦值是 (A)

A)p=a B)q[i]=a[i] C)p=a[i] D)p=&a[2][1]

【解析】p為基類型為int的指針,指向一個整形數據,也就可以指向一個數組元素,所以D正確。指針數組q的每個數組元素q[i]的基類型也為int,所以p、a[i]、a[i]的基類型一致,選項B、C也是正確的。

8.知識點:指針與函數

例1.(08—04—40)設有定義語句int(*f)(int);,則以下敘述正確的是__B_______。

A)f是基類型為int的指針變數

B)f是指向函數的指針變數,該函數具有一個int類型的形態

C)f是指向int類型一維數組的指針變數

D)f是函數名,該函數的返回值是其類型為int類型的地址

【解析】在c語言中,函數名代表此函數的入口地址,所因此,可以定義一種指向函數的指針來存放函數的入口地址,定義方式是:函數返回值類型(*函數指針名)(參數類型列表);本題答案選B。

9.知識點:指針與字元串

l 可以通過字元指針來處理字元串

例如:char *p="China"或者char *p;p="China";把字元串賦值給指針p,實質是把保存字元串"China"的那段記憶體的首地址賦值給指針p,使得指針p指向了字元串,這樣就可以通過指針來操作字元串了。

【注意】char str[10] ; str="China";是錯誤的!數組名是地址常量,不能進行賦值操作!

l 「三名主義」(考試的重點)

數組名:表示第一個元素的地址。數組名是地址常量名,不能進行賦值和自加(減)等運算。(考了很多次)

函數名:表示該函數的入口地址。

字元串常量名:表示第一個字元的地址。

例11.(2011-09-22)有以下程式(註:字元a的ASCII碼值為97)

#include <stdio.h>

main()

{ char *s={「abc」};

do

{printf(「%d」,*s%10);++s;}

while(*s);

}程式運行後的輸出結果是 (B)

A.abc B.789 C.7890 D.979898

例11.(2011-09-30)若有定義語句:char*s1=」OK」;*s2=」ok」;,以下選項中,能夠輸出「OK」的語句是 (D)

A.if(strcmp(s1,s2)==0) puts(s1);

B.if(strcmp(s1,s2)!=0) puts(s2);

C.if(strcmp(s1,s2)==1) puts(s1);

D.if(strcmp(s1,s2)!=0) puts(s1);

【解析】strcmp函數作為字元串比較函數,當s1等於s2所指字元串時結果為0,當s1大於s2所指字元串時結果為 >0,當s1小於s2所指字元串時結果為 <0

例11.(07—04—44)有下列程式:

main()

{char ch[]=「uvwxyz」,*pc;

pc=ch;printf(」%c\n」,*(pc+5));

} 程式運行後的輸出結果是(A)

A)Z B)0 C)元素ch[5]的地址 D)字元Y的地址

【解析】指針P指向了字元數組ch,*(pc+5)–>ch[5]–>』z』,printf函數要求以%c形式輸出,故輸出字元Z。

例12.(09-09-37)設有定義:char *c;.以下選項中能夠使字元型指針c正確指向一個字元串的是(A)

A)char str[]=」string」; c=str; B)scanf(「%s」,c);

C)c=getchar(); D)*c=」string」; 【解析】選項A為正確用法。先將字元串存於字元數組中,然後將數組名賦給字元指針。選項B為無語法錯誤,但運行時可能會出現問題。原因是字元指針沒有被賦值,是一個不確定的值,指向一個不確定的記憶體區域,這個區域可能存放有用的指令或數據。在這個不確定的區域重新存放輸入的字元串,可能會發生無法預知的錯誤。選項C錯誤。getchar()函數輸入一個字元給字元型變數,而不應該是字元指針。選項D錯誤。*c=」string」應該改為c=」string」才是正確的。