C語言中指針和引用的區別
最佳回答:
ct9789:
你好。
指針: 其實指針這個概念在譚浩強的<C程序設計>這本書上是這樣說的,指針就是地址,指針值就是地址值。指針變量就是存放指針的
變量,所以一定不要將指針與指針變量搞混淆了。指針僅僅是一個地址值,而指針變量就是存放指針(也就是地址的變量)
指針的定義:
例如整型指針: int *p;p是一個指向int類型數據的指針變量。裡面存放的地址(也就是指針)是一個int類型變量的地址。指針變量時
有類型的,例如p的類型就是int *表示p是一個指向int類型的指針變量。如何知道一個指針變量的類型呢,最簡單的方法就是去掉變
量定義語句中的變量名,剩下的部分就是其類型,這種方法適用於所有的變量定義,例如int a;a的類型是int 。 int b[10];b的類
型是int[]表示是一個數組(關於數組類型這裡不談,因為這個問題很微妙,其實在c、c++中沒有數組類型這個概念,包括函數類型也
是一樣的),int *c;c的類型是int *。int ** d;d的類型就是int **;所以通過這種方法來判斷一個變量的類型是很方便的。
說道指針變量,我們必須說到得有幾個方面。
1.指針類型。
這個很重要,一個指針是有類型的,也就是一個地址是有類型的。具體說是某一個地址會指向不同類型的數據,這是不一樣的,例如
int *p;p是指向int型數據。 double*p1;p1是指向double型數據。但是p和p1本身在內存中占用的空間是4個字節(對於32位的系統來說
),如果是在TC中編譯c程序,應該是2個字節了(dos操作系統是16位的)。有人說地址不就是一個值嗎,類似於0xfffdddcc這樣的地址
數值,為什麼還分什麼類型呢,我要說的是這個關系很大。我們知道指針是有運算的,int *p=&a;那麼p++到底加了多少呢,不要以為
是將p裡面的地址值加了1,這是完全想當然。實際上加了sizeof(int)這麼多個字節。也就是說加了一個int元素應該占用的字節,這
樣在數組中我們可以通過這種方式從上一個元素很方便的讓指針變量指向下一個元素。p+5的話實際上是加了p+sizeof(int)*5這麼多
個字節。 另外一點事指針的類型決定了當指針解引用的時候其所以指向的內存單元中的二進制數據如何解釋的問題。例如int *p=&a;
那麼(*p)取得的數字就是一個整型數據,如果(*((char *)p))得到的就是一個字符型數據了。p本來指向的是int型數據(有4個字節)的
首地址,如果將其強制轉換為一個指向char類型的指針變量,那麼在解引用的時候只取第一個字節的數據,並將其解釋為一個ascii碼
代表的字符。 還有如果是一個指向函數的指針變量,我們可以通過此指針變量直接調用函數。例如int(*function)(int);此時
function指向一個函數,此函數具有一個int參數,返回一個int值。那麼通過指針可以這樣調用該類型的函數了int a=function
(100); 或者int a=(*function)(100);其實要不要解引用都是可以的。不過以前是需要解引用的,現在c標准規定這兩種方法都可以。
總的來說指針的類型很重要。
2.指針與數組。
我們向一個函數傳遞數組的時候一般是傳遞數組名,我們知道數組名是一個代表數組中第一個元素的地址並且數組名是不可以當左值
的。其實你又沒有想過數組名到底是什麼呢。有人說其實數組名就是一個指針常量,是一個不可以改變的指針常量。例如:int a[10]
={1,2,3,4,5,6,7,8,9,10}; 那麼a可能的類型是int * const a;注意const的位置(關於指針常量和常量指針,這個以後說),那麼這種
說法到底對不對呢。我們可以通過sizeof運算符來計算某一種數據類型占用的存儲空間。例如 sizeof(10)的值為4,注意這裡我都假
設在32位的操作系統上面編譯。其實sizeof(10)和sizeof(int)是一樣的,僅僅是求這種類型的數據占用多少內存空間,而不是說具體
的某個數據占用的空間,因為對於10這個文字常量來說根本不會占用內存空間的,其實隨著程序直接編碼到源程序中的,不存在分配
內存的問題。那麼我們這樣計算sizeof(a);是不是如我們所願得到的是4呢。 結果可能會有意外,因為其值是sizeof(int)*10也就是
40個字節,顯然這個字節數是整個數組占用的字節數。而不是int *類型的指針變量占用的字節數,我們知道一個地址只占用4個字節
那麼這說明數組名絕對不是簡單的int*類型。但是數組確實具有int*的特性。例如int*p=a;這是不會報錯的。而且在函數之間傳遞的
時候也是采用這樣的方式:
void print(int b[10]){}
調用函數:
print(a);
或者:
print(&a[0]);
都是一樣的。
注意在某一個函數內對形參進行sizeof:
void print(int c[100])
{
sizeof(c); // 此時表達式的結果是4,而不是100。因為這裡int c[100]與int *c是一樣的,c不是數組名(數組名是不能作為左值
的)
}
3. 指針與函數
一個指針可以指向一個函數,指針可以作為函數參數,函數可以返回一個指針類型的數據。
指向函數的指針: 指向函數的指針,實際上此指針就是函數代碼的入口地址。我們可以通過這樣的方式調用函數。例如:
void print1(int x)
{
cout<<"hello "<<x<<endl;
}
void print2(int y)
{
cout<<"hello "<<y<<endl;
}
那麼在main函數中可以這樣寫:
void (*p)(int)=print1;//函數名代表函數入口地址值,和數組一樣,print1不僅僅是一個地址。
p(10);
p=print2;
p(20);
這都是可以的,另外我們可以通過一個指針數組存放指向函數的指針:
void (*aa[2])(int)={print1,print2};
for(int i=0;i<2;i++)
{
aa[i](i); //通過函數指針循環調用裡面的函數
}
關於各種指向函數指針的聲明,請自己查閱有關資料。
引用:
引用相當於別名,其實你直接將其當做一個別名就可以了。引用與指針的區別: 引用必須初始化,而且初始化之後不可更改,指針
卻可以。