經過c與c++的學習,整理一下關於指針以及引用方面的問題
指針:
指針是什么?
指針本身是一個變量,它存儲的是數據在內存中的地址而不是數據本身的值,指針類型、指針所指向的類型、指針的值或者叫指針所指向的內存區、指針本身所占據的內存區都是我們要考慮的問題
1、int a=0,p; p =&a;
2、int a=0; *p=&a;
第一種定義方法然后將a的地址賦給p。第二種是在定義指針p的同時將a的地址賦給指針p。我理解為 int * 是定義指針的標志
將指針p去掉以后可以看出指針的類型:
(1)char*p;//指針的類型是char*
(2)int*(*ptr)[4];//指針的類型是int*(*)[4]
將*p去掉以后可以看出指針指向區域的內容是什么類型
(1)char*p;//指針的類型是char
(2)int*(*ptr)[4];//指針的類型是int*()[4]
我們可以通過*p來找到指針所指向的變量a的地址,然后對地址中的值操作。
printf("%p",p) 結果是p指向的a的地址 printf("%d",*p) 結果是變量a的值 printf("%d",&p) 結果是指針p的地址
引用了一個看到的例子:
-
int *p; //首先從P 處開始,先與*結合,所以說明P 是一個指針,然后再與int 結合,說明指針所指向的內容的類型為int 型.所以P是一個返回整型數據的指針
-
int p[3]; //首先從P 處開始,先與[]結合,說明P 是一個數組,然后與int 結合,說明數組里的元素是整型的,所以P 是一個由整型數據組成的數組
-
int *p[3]; //首先從P 處開始,先與[]結合,因為其優先級比*高,所以P 是一個數組,然后再與*結合,說明數組里的元素是指針類型,然后再與int 結合,說明指針所指向的內容的類型是整型的,所以P 是一個由返回整型數據的指針所組成的數組
-
int (*p)[3]; //首先從P 處開始,先與*結合,說明P 是一個指針然后再與[]結合(與"()"這步可以忽略,只是為了改變優先級),說明指針所指向的內容是一個數組,然后再與int 結合,說明數組里的元素是整型的.所以P 是一個指向由整型數據組成的數組的指針
-
int **p; //首先從P 開始,先與*結合,說是P 是一個指針,然后再與*結合,說明指針所指向的元素是指針,然后再與int 結合,說明該指針所指向的元素是整型數據.,二級指針一般用在數據結構編程中
-
Int (*p)(int); //從P 處開始,先與指針結合,說明P 是一個指針,然后與()結合,說明指針指向的是一個函數,然后再與()里的int 結合,說明函數有一個int 型的參數,再與最外層的int 結合,說明函數的返回類型是整型,所以P 是一個指向有一個整型參數且返回類型為整型的函數的指針
-
int *(*p(int))[3]; //從P 開始,先與()結合,說明P 是一個函數,然后進入()里面,與int 結合,說明函數有一個整型變量參數,然后再與外面的*結合,說明函數返回的是一個指針,,然后到最外面一層,先與[]結合,說明返回的指針指向的是一個數組,然后再與*結合,說明數組里的元素是指針,然后再與int 結合,說明指針指向的內容是整型數據.所以P 是一個參數為一個整數據且返回一個指向由整型指針變量組成的數組的指針變量的函數.
&是取地址運算符,*是間接運算符。
&a 的運算結果是一個指針,指針的類型是a的類型加個*,指針所指向的類型是a的類型,指針所指向的地址就是a的地址。
*p 的結果是p所指向的東西,這個東西有這些特點:它的類型是p指向的類型,它所占用的地址是p所指向的地址。
這里提一個例子:Int **ptr=&pa; //&pa 在這句中*ptr 就是指針pa,但是*ptr占據了內存,所以被放到右邊
數組的數組名可以看成一種指針
arr[0] == *arr;
arr[3] == *(arr+3)
或者是char *str[3]={"Hehe!","Haha.","Helloworld"};
str 是一個三單元的數組,該數組的每個單元都是一個指針,這些指針各指向一個字符串。
str 當作一個指針的話,它指向數組的第0號單元,它的類型是char **,它指向的類型是char *。
str+1 也是一個指針,它指向數組的第1號單元,它的類型是char**,它指向的類型是char*。
*str 也是一個指針,它的類型是char *,它所指向的類型是char,它指向的地址是字符串"Hehe!"的第一個字符的地址,即'H'的地址。
結構體和指針:
struct NUM
{
int x;
int y;
}
struct NUM num = {20,30};
struct *ptr = # 訪問成員的時候 ptr->x,ptr->y
int *pstr = (int*)# 訪問成員的時候 (*pstr)(*(pstr+1))
引用:
一個變量可取多個別名。
普通引用舉例
答案:
由此可見a,b,c地址是同一個
下面再看一個例子
這道題輸出a == b == 20,此時b的值不能被修改,但是可以通過修改a去修改b,還有,只有常引用可以引用const修飾的變量。
void S(int& a, int& b)//使用引用的話,不做臨時拷貝,&的使用說明此處只是原參數的另一個名字而已,所以修改時直接在原參數的基礎上修改變量的值
void S(int* a_p, int* b_p)//傳入的是地址,因為地址是唯一的,所以指針通過地址的訪問進而可修改其內容。
總結以下幾點:
(1)引用就是起"外號",為一個標識符另外再取一個名字。&在這里不是求地址運算,而是起標識作用。
(2)類型標識符是指目標變量的類型,引用不光可以引用標識符,也可以引用立即數(右值、字面值、常量),但必須加const屬性。
(3)聲明引用時,必須同時對其進行初始化引用,否則編譯錯誤。
(4)引用聲明完畢后,相當於目標變量名有兩個名稱,即該目標原名稱和引用名,且不能再把該引用名作為其他變量名的別名,即引用只能是一次性的,無法再更改(引用一旦成功后,它是個變量了這個身份至死不渝)。
(5)對引用求地址,就是對目標變量求地址。即引用名是目標變量名的一個別名。引用在定義上是說引用不占據任何內存空間,但是編譯器在一般將
其實現為const指針,即指向位置不可變的指針,所以引用實際上與一般指針同樣占用內存。
(6)不能建立引用的數組。因為數組是一個由若干個元素所組成的集合,所以無法建立一個由引用組成的集合,但是可以建立數組的引用。
(7)引用常見的使用用途:作為函數的參數、函數的返回值,但絕不能返回局部變量的引用。
(8)不能定義空引用,但"野引用"或"懸空引用"是存在的(引用了堆內存的數據,當堆內存釋放后就不應該再使用)。
(9)引用可以當作函數的參數,它引用的對象就是函數的實參,所以引用可以達到指針的效果。
a、函數之間共享變量
b、提高參數的傳遞效率(比指針還要高)
c、可以獲取參數
但是引用不可以完全取代指針。
引用和指針的區別和聯系:
不同點:
1. 指針是一個實體,而引用僅是個別名;
2. 引用使用時無需解引用(*),指針需要解引用;
3. 引用只能在定義時被初始化一次,之后不可變;指針可變;
4. 引用沒有 const,指針有 const;const修飾的指針不可變;
5. 引用不能為空,指針可以為空;
6. “sizeof 引用”得到的是所指向的變量(對象)的大小,而“sizeof 指針”得到的是指針本身(所指向的變量或對象的地址)的大小;
7. 指針和引用的自增(++)運算意義不一樣;
8.從內存分配上看:程序為指針變量分配內存區域,而引用不需要分配內存區域。
9.指針通過某個指針變量指向一個對象后,對它所指向的變量間接操作。程序中使用指針,程序的可讀性差;而引用本身就是目標變量的別名,對引用的操作就是對目標變量的操作。
相同點:兩者都是地址的概念,指針指向一塊兒內存,其內容為所指內存的地址;引用是某塊兒內存的別名