C語言指針基礎預習

1.指針的類型與指針所指向的類型的區別

從語法的角度看,你只要把指針聲明語句裏的指針名字去掉,剩下的部


分就是這個指針的類型。這是指針本身所具有的類型。讓我們看看例一中各


個指針的類型:


(1)int*ptr;//指針的類型是int*


(2)char*ptr;//指針的類型是char*


(3)int**ptr;//指針的類型是int**


(4)int(*ptr)[3];//指針的類型是int(*)[3]


(5)int*(*ptr)[4];//指針的類型是int*(*)[4]


指針所指向的類型


當你通過指針來訪問指針所指向的內存區時,指針所指向的類型決定了


編譯器將把那片內存區裏的內容當做什麼來看待。


從語法上看,你只須把指針聲明語句中的指針名字和名字左邊的指針聲


明符*去掉,剩下的就是指針所指向的類型。例如:


(1)int*ptr; //指針所指向的類型是int


(2)char*ptr; //指針所指向的的類型是char


(3)int**ptr; //指針所指向的的類型是int*


(4)int(*ptr)[3]; //指針所指向的的類型是int()[3]


(5)int*(*ptr)[4]; //指針所指向的的類型是int*()[4]


在指針的算術運算中,指針所指向的類型有很大的作用。


指針的類型(即指針本身的類型)和指針所指向的類型是兩個概念。


2.指針的算數運算與關係運算是如何實現的?

第一種形式是:指針+-整數 標準定義這種形式只能用於指向數組中某個元素的指針,並且這類表達式的結果類型也是指針。這種形式也適用於使用malloc函數動態分配獲得的內存。

對一個指針加1使它指向數組中的下一個元素,加5使它向右移動5個元素的位置,依次類推。把一個指針減去3使它向左移動3個元素的位置。


第二種類型的指針運算具有如下的形式:指針—指針

只有當兩個指針都指向同一個數組中的元素時,才允許從一個指針減去另一個指針, 兩個指針相減的結果的類型是ptrdiff_t,它是一種有符合整數類型。減法運算的值是兩個指針在內存中的距離是指針的本身(以數組元素的長度爲單位,而不是以字節爲單位),因爲減法運算的結果將除以數組元素類型的長度。

只有當兩個指針指向同一個數組中的元素時,才能進行關係運算。 
當指針p和指針q指向同一數組中的元素時, 
則: (可以用在if判斷裏面作爲條件)

p<q 當p所指的元素在q所指的元素之前時,表達式的值爲1;反之爲0。 
P>q 當p所指的元素在q所指的元素之後時,表達式的值爲1;反之爲0。 
p==q 當p和q指向同一元素時,表達式的值爲1;反之爲0。 
p!=q 當p和q不指向同一元素時,表達式的值爲1;反之爲0。


3.常量指針與指針常量大的區別

常量指針是指--指向常量的指針,顧名思義,就是指針指向的是常量,即,它不能指向變量,它指向的內容不能被改變,不能通過指針來修改它指向的內容,但是指針自身不是常量,它自身的值可以改變,從而指向另一個常量。
指針常量是指--指針本身是常量。它指向的地址是不可改變的,但地址裏的內容可以通過指針改變。它指向的地址將伴其一生,直到生命週期結束。有一點需要注意的是,指針常量在定義時必須同時賦初值。
注:也有人將這兩個名稱的定義與含義反過來認爲:“指針常量:顧名思義它的中心詞是“常量”這是重點,指針就是一個修飾的作用。所以這裏的指針還是一個變量,它的內容存放的是常量的地址。常量指針:關鍵字是指針,它是不能被改變的,因爲指針總是指向地址的,所以它的意思是它指向的地址是不能被改變的”。但我個人認爲後者不合理,所以使用前者。
使用方法:
使用時寫法上的區別:常量指針:const在*之前   指針常量:const在*之後。
  當然我們也可以定義常量指針常量,那就需要加上兩個const,一前一後!以上只是從定義上給出兩者的本質上的不同,在具體使用上,還有很多變化,但萬變不離其宗,我們可以根據它的原理分析出各種複雜用法的實質。


4.指針數組與數組指針的區別

數組指針(也稱行指針)
定義 int (*p)[n];
()優先級高,首先說明p是一個指針,指向一個整型的一維數組,這個一維數組的長度是n,也可以說是p的步長。也就是說執行p+1時,p要跨過n個整型數據的長度。


如要將二維數組賦給一指針,應這樣賦值:
int a[3][4];
int (*p)[4]; //該語句是定義一個數組指針,指向含4個元素的一維數組。
 p=a;        //將該二維數組的首地址賦給p,也就是a[0]或&a[0][0]
 p++;       //該語句執行過後,也就是p=p+1;p跨過行a[0][]指向了行a[1][]


所以數組指針也稱指向一維數組的指針,亦稱行指針。


指針數組
定義 int *p[n];
[]優先級高,先與p結合成爲一個數組,再由int*說明這是一個整型指針數組,它有n個指針類型的數組元素。這裏執行p+1是錯誤的,這樣賦值也是錯誤的:p=a;因爲p是個不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它們分別是指針變量可以用來存放變量地址。但可以這樣 *p=a; 這裏*p表示指針數組第一個元素的值,a的首地址的值。
如要將二維數組賦給一指針數組:
int *p[3];
int a[3][4];
for(i=0;i<3;i++)
p[i]=a[i];
這裏int *p[3] 表示一個一維數組內存放着三個指針變量,分別是p[0]、p[1]、p[2]
所以要分別賦值。


這樣兩者的區別就豁然開朗了,數組指針只是一個指針變量,似乎是C語言裏專門用來指向二維數組的,它佔有內存中一個指針的存儲空間。指針數組是多個指針變量,以數組形式存在內存當中,佔有多個指針的存儲空間。
還需要說明的一點就是,同時用來指向二維數組時,其引用和用數組名引用都是一樣的。
比如要表示數組中i行j列一個元素:
*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]

優先級:()>[]>*


5.sizeof與strlen的區別

一、sizeof
    sizeof(...)是運算符,在頭文件中typedef爲unsigned int,其值在編譯時即計算好了,參數可以是數組、指針、類型、對象、函數等。
    它的功能是:獲得保證能容納實現所建立的最大對象的字節大小。
    由於在編譯時計算,因此sizeof不能用來返回動態分配的內存空間的大小。實際上,用sizeof來返回類型以及靜態分配的對象、結構或數組所佔的空間,返回值跟對象、結構、數組所存儲的內容沒有關係。
    具體而言,當參數分別如下時,sizeof返回的值表示的含義如下:
    數組——編譯時分配的數組空間大小;
    指針——存儲該指針所用的空間大小(存儲該指針的地址的長度,是長整型,應該爲4);
    類型——該類型所佔的空間大小;
    對象——對象的實際佔用空間大小;
    函數——函數的返回類型所佔的空間大小。函數的返回類型不能是void。
**************
二、strlen
    strlen(...)是函數,要在運行時才能計算。參數必須是字符型指針(char*)。當數組名作爲參數傳入時,實際上數組就退化成指針了。
    它的功能是:返回字符串的長度。該字符串可能是自己定義的,也可能是內存中隨機的,該函數實際完成的功能是從代表該字符串的第一個地址開始遍歷,直到遇到結束符NULL。返回的長度大小不包括NULL。
*****************
三、舉例:
    eg1、char arr[10] = "What?";
              int len_one = strlen(arr);
              int len_two = sizeof(arr); 
              cout << len_one << " and " << len_two << endl; 
    輸出結果爲:5 and 10
    點評:sizeof返回定義arr數組時,編譯器爲其分配的數組空間大小,不關心裏面存了多少數據。strlen只關心存儲的數據內容,不關心空間的大小和類型。
    eg2、char * parr = new char[10];
              int len_one = strlen(parr);
              int len_two = sizeof(parr);
              int len_three = sizeof(*parr);
              cout << len_one << " and " << len_two << " and " << len_three << endl;
    輸出結果:23 and 4 and 1
    點評:第一個輸出結果23實際上每次運行可能不一樣,這取決於parr裏面存了什麼(從parr[0]開始知道遇到第一個NULL結束);第二個結果實際上本意是想計算parr所指向的動態內存空間的大小,但是事與願違,sizeof認爲parr是個字符指針,因此返回的是該指針所佔的空間(指針的存儲用的是長整型,所以爲4);第三個結果,由於*parr所代表的是parr所指的地址空間存放的字符,所以長度爲1。


6.函數指針與指針函數的區別

1、指針函數是指帶指針的函數,即本質是一個函數。函數返回類型是某一類型的指針


     類型標識符    *函數名(參數表)


      int *f(x,y);

首先它是一個函數,只不過這個函數的返回值是一個地址值。函數返回值必須用同類型的指針變量來接受,也就是說,指針函數一定有函數返回值,而且,在主調函數中,函數返回值必須賦給同類型的指針變量。


表示:


float *fun();


float *p;


p = fun(a);


注意指針函數與函數指針表示方法的不同,千萬不要混淆。最簡單的辨別方式就是看函數名前面的指針*號有沒有被括號()包含,如果被包含就是函數指針,反之則是指針函數。


來講詳細一些吧!請看下面


 指針函數:
    當一個函數聲明其返回值爲一個指針時,實際上就是返回一個地址給調用函數,以用於需要指針或地址的表達式中。
    格式:
         類型說明符 * 函數名(參數)
    當然了,由於返回的是一個地址,所以類型說明符一般都是int。
    例如:int *GetDate();
          int * aaa(int,int);
    函數返回的是一個地址值,經常使用在返回數組的某一元素地址上。

函數指針是指向函數的指針變量,即本質是一個指針變量。

 int (*f) (int x); /* 聲明一個函數指針 */

 f=func; /* 將func函數的首地址賦給指針f */

指向函數的指針包含了函數的地址,可以通過它來調用函數。聲明格式如下:
        類型說明符 (*函數名)(參數)
    其實這裏不能稱爲函數名,應該叫做指針的變量名。這個特殊的指針指向一個返回整型值的函數。指針的聲明筆削和它指向函數的聲明保持一致。
        指針名和指針運算符外面的括號改變了默認的運算符優先級。如果沒有圓括號,就變成了一個返回整型指針的函數的原型聲明。


7.comst int *p與int const *p有無區別?如何定義const指針?以及const對指針的作用


無區別,都是定義的int const型的指針。

int * const p可定義int類型的const指針。

對於int const型的指針,*p的值不能改變,即p所指向的內容不能改變;對於const 指針,p的內容不能改變,即p裏保存的地址不能改變,但是*p的值是可以改變的。


8.右左法則的應用

1.      第一次開始閱讀聲明的時候,必須從變量名開始,而不是從最內部的括號開始
2.      最後兩個字是本質
3.      先從變量看起,向右看,碰到小括號後再向左看
4.      確定是變量後就要確定變量中保存的是什麼值;確定是指針變量後就要確定指針保存的是什麼的地址或指針變量指向什麼值;確定是數組後就要確定數組中每一個元素的類型;確定是函數後就要說明函數的形參類型和返回值類型。
 
 
實例說明:
簡單版:
int a ;     整型變量
int *a;    整型指針變量
int **a    整型指針的指針變量
int a[10]   整型數組
int *a[10]  整型指針數組
int (*a)[10]  數組指針變量
int (*a)(int)  函數指針變量
int (*a[10])(int )  函數指針數組
 
加強版:
int  *(*(*fp1)(int))[10];
聲明一個函數指針變量,該指針指向形參是整型,返回值是數組指針的函數,該數組指針指向一個整型指針數組。
int  *(*(*arr[5])())();
聲明一個函數指針數組arr,該數組中的每一個元素指向形參爲空,返回值是函數指針的函數,該函數指針指向一個形參是空返回值是整型指針的函數
float  (*(*b())[])();
聲明一個形參是空,返回值是數組指針的函數,該指針指向一個指針數組,數組中的每一個元素指向一個形參是空,返回值是float 型的函數。
void  *(*c)(char a, int (*b)());
聲明一個函數指針變量,該指針指向返回值是 void * 類型,有兩個形參的函數,該函數的第一個形參是字符變量,第二個形參是函數指針,指向一個形參是空,返回值是 int 型的函數。
float  (*(*e[10])(int*))[5];
聲明一個函數指針數組,該數組中的每一個元素指向一個函數,該函數的形參是 int *類型,返回值是一個數組指針,該指針指向一個float 型數組。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章