c++指向指針的指針與 c++指針作為函數參數傳遞問題


 一直搞不明白,c++中指針到底是個啥東西,今天遇到到c++,指向指針的指針的問題,突然有點開竅了。

舉個例子:

int main(int argc, char** argv)
{

int a[5]={1,2,3,4,5};
int *p=a;
int **pointer=&p;
std::cout<<"a="<<a<<std::endl;
std::cout<<"p="<<p<<std::endl;
std::cout<<"&a[0]="<<&a[0]<<std::endl;
std::cout<<"*pointer="<<*pointer<<std::endl;
std::cout<<std::endl;

std::cout<<"poiner="<<pointer<<std::endl;
std::cout<<"&p="<<&p<<std::endl;
std::cout<<std::endl;

std::cout<<"**pointer="<<**pointer<<std::endl;
std::cout<<"*p="<<*p<<std::endl;
std::cout<<"a[0]="<<a[0]<<std::endl;
std::cout<<std::endl;

std::cout<<"&pointer="<<&pointer<<std::endl;

}

運行結果:

對於指針來說,用 int *p=a舉例子, 這句代碼:std::cout<<"p="<<p<<std::endl,輸出的是指針p指向的變量的地址,也就是p指針所保存的內容,也就是數組a的首地址,也就是a[0]的地址。所以從運行結果可以看出來,它們的值都是相同的。對於*p來說,這句代碼:std::cout<<"*p="<<*p<<std::endl;輸出的是p指向的變量所保存的內容,也就是a[0]的內容。

 對於&p,則表示的是指針p自身在內存中的地址。這個地址可被指向指針的指針所指。比如,int **pointer=&p;跟上面一樣,pointer指向p指針在內存中的地址,也就是pointer保存p指針在內存中的地址。*pointer則保存p指針所保存的內容,即p指針所指向的a[0]的地址。其實可以這么認為,*pointer也是個地址,這個地址其實就是a[0]的地址。**pointer則是指向a[0] 中的內容。&pointer則是pointer指針在內存中的地址。

 

 

 一句話,對於一個指針符號來說,它表示的是指向的對象的內存地址,*+指針符號,則表示所指向對象保存的內容。

例如:

  

int main(int argc,char* argv[])
{
int *a = new int;
*a = 5;
int **ptr = &a;
cout << "&a: " << &a<<" *a: "<<*a<<" a: "<<a << endl;
cout << "*ptr: " << *ptr << " **ptr " << **ptr << " ptr: "<<ptr<<endl;
system("pause");
}

 

a指向5的內存地址

*a表示a指向的這個地址中的值即5

&a表示a指針的地址
**ptr為指向指針的指針

ptr的值為a指針的地址

*ptr表示表示a指針的這個地址值存放的值,即5的內存地址

**ptr則表示以a指針的這個地址值存放的值為地址的內存中存放的值,即5.

 

 c++指針作為函數參數傳遞問題

作者:清林,博客名:飛空靜渡

 

博客地址:http://blog.csdn.net/fjb2080

 

其實,對於C 或者C++ ,最難的一塊地方估計就是指針了。指針是強大的,但也是很多人載在這里的地方。

 

前段時間寫了一篇文章《C ++之 數組與指針的異同 》對C 和C ++中的指針做了一個初步的講解。這次將講解一下指針作為函數參數傳遞的問題。

 

很多人對於指針的使用是有所了解的,但還是經常會載在指針的問題上,是因為還不夠了解指針的本質,其實如果了解指針的本質,對指針的使用也就一目了然了。

 

作為C 的初學者,經常會遇到指針作為函數參數傳遞的兩個經典的問題。這里,我將透過指針的本質來來講解這兩個問題,這樣以后無論你遇到什么樣的指針問題,如果你以這樣的方法來分析指針也許就迎刃而解了!

 

首先,第一個問題是這樣的:

寫一個函數,交換兩個參數中的值。

 

初學者往往會這樣寫:

 

void exchange(int x, int y)

{

int p=x;

x = y;

y = p;

}

 

之后,你會查找資料了解到應該這樣寫:

void exchange(int *x, int *y)

{

int *p=x;

*x = *y;

*y = *p;

}

 

第二個問題是,寫一個給某個指針分配內存的函數:

初學者往往是這樣寫:

void my_malloc(void* p, int size)

{

p = malloc(sizeof(int)*size);

}

 

然后又查在資料,知道應該這么寫:

void my_malloc(void** p, int size)

{

*p = malloc(sizeof(int)*size);

}

 

雖然,網上很多這樣的討論,也有很多人做過很多的解釋,但始終都無法給出一個令人一目了然,並可以長久記住的說法,這篇文章就是想試圖解決這樣的問題,給初學者一個原理性的了解!

 

首先,一定一定記住一點, 指針和變量一樣,也是有地址的,只不過變量的值被解釋成一個值,而指針的值被解釋成一個地址。

 

下面,我們看一下代碼:

void main()

{

int x;

int *p;

}

 

我們看這個函數的內存結構:

 

這是一個函數的棧結構,我們可以看到,變量和指針都占用了4 個字節。而且,由於我們對它們沒有初始化,所以變量x 和指針p 里的內容都是隨機的,就是說x 的值是不確定的,p 有可能指向某個內存地址,如果現在對p 操作也許會導致程序崩潰。

 

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

其實,我們記住了,指針也是有地址的 這個概念,很多問題就迎刃而解了。

 

下面,我來分析一下,指針作為函數參數傳遞的情況。

 

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

如果,我們的代碼是這樣的,你看會怎么樣:

 

int main(int argc, char* argv[])

{

int *a = new int(10);

func(a);

 

return 0;

}

 

第一個要說的當然是:指針也是有地址的。

第二個要說的是:當給一個函數的參數傳遞一個變量是,這個變量是復制過去的。

 

對於第二點,我們在理解void exchange(int x, int y) 函數想交換這兩個變量的的值時就應該理解了。

例如:

int a;

int b;

exchange(a,b);

不能交換a 和b 的值,因為此時exchange(a,b) 中的a 和b 並不是原來的a 和b 變量,它們只不過是被復制過去了。

 

有了這兩個概念,就不難理解指針作為函數參數傳遞的問題。

 

首先,我們來看下上面的代碼中的a 指針和p 指針的內存結構。

我們看到,當我們以a 作為func 函數的參數傳遞進去的時候,函數復制了這個指針,但這兩個指針的內容是一樣的,也就是說是指向同一個內存,即10 。

 

如果你還不了解的話,我就通過一段代碼和測試再來說明:

 

 

[cpp]  view plain  copy
 
 print?
  1. #include <stdio.h>  
  2. void func(int* p)  
  3. {  
  4.     printf("*p = %d/n", *p);  
  5.     printf("&p = %p/n", &p);  
  6. }  
  7. int main(int argc, char *argv[])  
  8. {  
  9.     int *a = new int(10);  
  10.     printf("*a = %d/n", *a);  
  11.     printf("&a = %p/n", &a);  
  12.     func(a);  
  13.     return 0;  
  14. }  

 

 

 

編譯:g++ -g -Wall test1.cpp

運行:./a.out

輸出:

*a = 10

&a = 0xbfd4447c

*p = 10

&p = 0xbfd44460

 

我們看到輸出,a 指向的地址的值和p 指向的地址里的值是一樣的,都是10 。然而,對於指針a 和p 來說,它們自身的地址是不一樣的,所以我們看到,函數func 復制了指針a 給p ,它們的值一樣,但有不同的地址,是不同的指針。

 

我們再進一步:

 

[cpp]  view plain  copy
 
 print?
  1. #include <stdio.h>  
  2. void func(int* p)  
  3. {  
  4.     printf("*p = %d/n", *p);  
  5.     printf("&p = %p/n", &p);  
  6.     printf("&*p = %p/n", &*p);  
  7. }  
  8. int main(int argc, char *argv[])  
  9. {  
  10.     int *a = new int(10);  
  11.     printf("*a = %d/n", *a);  
  12.     printf("&a = %p/n", &a);  
  13.     printf("&*a = %p/n", &*a);  
  14.     func(a);  
  15.     return 0;  
  16. }  

 

 

 

編譯輸出:

*a = 10

&a = 0xbfe1c77c

&*a = 0x94b6008

*p = 10

&p = 0xbfe1c760

&*p = 0x94b6008

 

我們可以進一步看到,a 指針所指向的值的地址和p 指針所指向的值的地址是一樣的,都是 0x94b6008 ,就如同上圖所示,為了加深印象,再看一下這個圖 ,然后再對比一下程序輸出 ,然后在體會一下我在上面提到的兩點 ,一點是:指針是有地址的 。另一點是:函數的參數是復制過去的 。

 

 

 

說到這里,我們再回到文章開始時提到的兩個問題,一個是交換問題:

 

void exchange(int *x, int *y)

{

int *p=x;

*x = *y;

*y = *p;

}

 

那么這樣為什么可以交換:

int a = 2;

int b = 3;

exchange(&a, &b);

 

上我們以a 和b 的地址傳遞給exchange 函數時,函數復制了這兩個地址,並賦值給x 和y 這個兩個指針,這兩個指針是指向變量a 和b 的,它們的圖形如下:

 

那么,當我們反引用指針時:

int *p=x;

*x = *y;

*y = *p;

 

我們操作的是a 和b 里面的變量的值,所以,我們交換a 和b 的值就成功了。

 

我們再來看下第二個問題:

void my_malloc(void* p, int size)

{

p = malloc(sizeof(int)*size);

}

當這樣時:

int *a;

my_malloc(a, 10);

為什么這個會失敗!

 

下面,我來分析一下:

當我們調用my_malloc(a, 10); 函數,而函數還沒執行到p = malloc(size); 語句時,情況是這樣的:

 

我們看到a 和p 的指針的值都是一樣的,都是指向某個不確定的地址。

這時,我們執行這個語句:

p = malloc(sizeof(int)*size);

我們把這個語句分開兩部分來看,一個是先執行malloc(sizeof(int)*size) ,然后在執行賦值語句,把malloc(sizeof(int)*size) 的返回值付給p 。

第一步:先執行malloc(sizeof(int)*size) ;(這里我們只考慮malloc 分配內存成功的情況)

 

第二步:把執行malloc(sizeof(int)*size) 的返回值付給了p ,如下圖:

 

由上圖,我們可以知道,這就是為什么,我們還是不能給a 分配地址的了。

 

下面我們來分析這個:

void my_malloc(void** p, int size)

{

*p = malloc(sizeof(int)*size);

}

 

int *a;

my_malloc(&a , 10);

這樣執行,為什么會成功!

 

 

我們看到,當執行函數

my_malloc(void** p, int size);

但還沒有執行

*p = malloc(sizeof(int)*size);

語句時,它們的內存結構圖如下所示:

 

其實這里,我們可以把二維指針和一維指針當成和變量一樣,也是有地址的。只不過它的解釋不一樣而已。

變量:里面的值是一個數值。

一維指針:里面的值是個地址,而這個地址里的值是個數值。

二維指針:里面的值是個地址,而這個地址里的值也是個地址。

 

那么,我看着圖來解釋p :

p 里面是一個地址,這個地址是&a ,即是a 指針的地址值,而a 指針地址里面的值也是個地址,這個地址是指向一個不確定的地方,說得坳口,慢慢對比圖來理解就會好了!

 

執行malloc(size) 后的圖如下:

 

然后在執行賦值語句:

*p = malloc(sizeof(int)*size);

后,如下圖所示:

 

然后,我們就給指針a 分配內存成功了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM