C語言二級指針與典型應用(1)
https://blog.csdn.net/ye1223/article/details/79674975
二級指針的定義:
A(即B的地址)是指向指針的指針,稱爲二級指針,用於存放二級指針的變量稱爲二級指針變量.本質:二級指針變量的值是一個地址。
一、概念
在如下的A指向B、B指向C的指向關係中:
首先,默認的編譯器是32位,即int型爲4字節。
C:"一段內容",可是是一個具體的常量、變量、或是用malloc(new)分配了一塊內存。C的起始地址是0x00000008。
B:一個指針變量,其中存放着C的地址。但是B也是變量,因此需要佔空間,所以B也有地址,B的起始地址是0x00000004。因爲B中存放的是C的地址,所以B裏面的內容就是0x00000008。
(備註:當C是一個局部 非static變量或是數組時,系統是在棧中爲變量分配內存;如果是採用malloc,則是在堆中分配內存。當B是一個局部 非static指針變量時,系統是在棧中爲變量分配內存,即B的起始地址是在棧中;但並不限制指針所指向對象的內存位置,即可以指向在堆中的變量,如malloc分配的數組變量。)
[cpp] view plain copy
- B= 0x00000008; //B的值
- *B = "一段內容"; //B取內容,也就是B指針指向的C的值
- &B = 0x00000004; //B取地址,B的地址是0x00000004
A是二級指針變量,其中存放着B的地址0x00000004。A也有地址,是0x00000000;
[cpp] view plain copy
- *A = B= 0x00000008; //A取內容就是B的內容
- **A = *B = "一段內容"; //B取內容,也就是B指針指向的C的值
- A = &B = 0x00000004; //A存的是B的地址,B的地址是0x00000004
- &A = 0x00000000; //A取地址
二、典型使用之一
二級指針作爲函數參數的作用:在函數外部定義一個指針p,在函數內給指針賦值,函數結束後對指針p生效,那麼我們就需要二級指針。
看看下面一段代碼:有兩個變量a,b,指針q,q指向a,我們想讓q指向b,在函數裏面實現。
1.先看看一級指針的實現
-
#include <stdio.h>
-
#include <stdlib.h>
-
int a= 10;
-
int b = 100;
-
int *q = NULL;
-
void func(int *p)
-
{
-
printf("func:&p=%d,p=%d\n",&p,p); //note:3
-
p = &b;
-
printf("func:&p=%d,p=%d\n",&p,p); //note:4
-
}
-
int main()
-
{
-
printf("&a=%d,&b=%d,&q=%d\n",&a,&b,&q); //note:1
-
q = &a;
-
printf("*q=%d,q=%d,&q=%d\n",*q,q,&q); //note:2
-
func(q);
-
printf("*q=%d,q=%d,&q=%d\n",*q,q,&q); //note:5
-
return 0;
-
}
輸出:
note:1->a,b,q都有一個地址.
note:2->q指向a.
note:3->我們發現參數p的地址和q的地址並不相同。
note:4->p重新指向b.
note:5->退出函數,p的修改並不會對q造成影響。
結論:
(1)p的地址和q的地址不同的原因:形參p在函數func被調用時作爲臨時變量,系統會在棧中爲p分配一個獨立內存,而q作爲全局變量,是在靜態內存區分配的內存(參見文檔:《C/C++程序運行時的內存分配》);因此p和q具有不同的地址。但是同時注意:p和q的地址不同,但是值(即保存的數據)相同,均是變量a的地址。
(2)C語言中,實參向形參的數據傳遞分爲3種:值傳遞、地址傳遞和引用傳遞。此處屬於地址傳遞(即實參和形參的均是某變量的地址)。因此,p和q均指向a,對*p進行操作,即對a進行操作。但是注意:不管對p進行何種操作,均不會改變q的值和q的地址(因爲屬於不同的變量),最多隻會改變q指向的變量a的值。
(3)如果想通過操作指針p,對a和q均進行修改,那就需要用到二級指針。
2.二級指針操作
#include <stdio.h>
#include <stdlib.h>
int a= 10;
int b = 100;
int *q = NULL;
void func(int **p)
{
printf("func:\tp=%d\t&p=%d\n",p,&p); //note:3
*p = &b;
printf("func:\tp=%d\t&p=%d\n",p,&p); //note:4
}
int main()
{
printf("&a=%d\t&b=%d\t&q=%d\n",&a,&b,&q); //note:1
q = &a;
printf("*q=%d\tq=%d\t&q=%d\n",*q,q,&q); //note:2
func(q);
printf("*q=%d\tq=%d\t&q=%d\n",*q,q,&q); //note:5
return 0;
}
結論::
(1)p爲二級指針,保存的是q的地址。參見上:p和q保存在不同的內存區域。p=&q,因此當進行*p=&b時,即進行的是q=&b,改變了指針q的指向。
例子:
void my_malloc(char **s)
{
*s=(char*)malloc(100);
}
void main()
{
char *p=NULL;
my_malloc(&p);
free(p);
p=NULL;
}
函數分析:
(1)目的:通過調用子函數,爲主函數指針分配一塊內存空間;
在調用my_malloc時,實參值爲&p,即指針p的地址;my_malloc執行時,分配臨時變量s=&p; *s=(char*)malloc(100)操作等同於:p=(char*)malloc(100);即通過調用子函數,爲主函數指針分配一塊內存空間。
(2)注意:如果malloc函數被調用,則後續函數中一定需要有free將對應的內存釋放,否則可能導致內存泄露;當free(p)後,需要讓p=NULL,否則指針p會成爲野指針!
文章部分參考:http://blog.csdn.net/majianfei1023/article/details/46629065