1. 程式人生 > >c語言的一級指標和二級指標作為函式引數,連結串列,malloc中的分配等等總結

c語言的一級指標和二級指標作為函式引數,連結串列,malloc中的分配等等總結

主要內容:

1、一級指標和二級指標

2、函式指標傳遞的例子

3、什麼時候需要傳遞二級指標?

4、二級指標在連結串列中的使用

1、一級指標和二級指標

一級指標:即我們一般說的指標,就是記憶體地址;

二級指標:指向指標的指標,就是地址的地址;

如:

int a=1;

int *p=&a;  // p為a變數的地址,通過*p可以得到a的值

int **q=&p;   // q為p指標的地址,通過**q可以得到a的值 

2、函式指標傳遞的例子

程式1:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include<stdio.h>

void  fun(int  *p){

int  b=100;

p=&b;

}

int main(){

int  a=10;

int  *q;

q=&a;

printf("%d\n",*q);

fun(q);

printf("%d\n",*q);

return  0;

}

執行結果:

10

10

程式2:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include<stdio.h>

void  fun(int  **p){

int  b=100;

*p=&b;

}

int main(){

int  a=10;

int  *q;

q=&a;

printf("%d\n",*q);

fun(&q);

printf("%d\n",*q);

return  0;

}

執行結果:

10

100

程式3:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include<stdio.h>

#include<stdlib.h>

void  myMalloc(char  *s){

s=(char*)malloc(100);

}

int main()

{

char  *p=NULL;

myMalloc(p);

if(p==NULL)

printf("P is not changed!\n");

else{

printf("P has been changed!\n");

free(p);

}

return 0;

}

執行結果:

P is not changed!

程式4:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include<stdio.h>

#include<stdlib.h>

void  myMalloc(char  **s){

*s=(char*)malloc(100);

}

int main()

{

char  *p=NULL;

myMalloc(&p);

if(p==NULL)

printf("P is not changed!\n");

else{

printf("P has been changed!\n");

free(p);

}

return 0;

}

執行結果:

P has been changed!

3、什麼時候需要傳遞二級指標?

通過上述例子,我們可以看到,在某些情況下,函式引數傳遞一級指標時,在函式體內對指標做變動,也不會對原始指標產生變化,而傳遞二級指標時,則可以,這是為什麼呢?

在傳遞一級指標時,只有對指標所指向的記憶體變數做操作才是有效的;

在傳遞二級指標時,只有對指標的指向做改變才是有效的;

下面做簡單的分析:

在函式傳遞引數時,編譯器總會為每個函式引數製作一個副本,即拷貝;

例如:

void fun(int *p),指標引數p的副本為_p,編譯器使_p=p,_p和p指向相同的記憶體空間,如果在函式內修改了_p所指向的內容,就會導致p的內容也做相應的改變;

但如果在函式內_p申請了新的記憶體空間或者指向其他記憶體空間,則_p指向了新的記憶體空間,而p依舊指向原來的記憶體空間,因此函式返回後p還是原來的p。

這樣的話,不但沒有實現功能,反而每次都申請新的記憶體空間,而又得不到釋放,因為沒有將該記憶體空間的地址傳遞出來,容易造成記憶體洩露。

void fun(int **p),如果函式引數是指標的地址,則可以通過該引數p將新分配或新指向的記憶體地址傳遞出來,這樣就實現了有效的指標操作。

如果覺得二級指標比較難理解,也可以通過函式返回值的形式來傳遞動態記憶體(切記不能返回棧記憶體),如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#include<stdio.h>

#include<stdlib.h>

char* myMalloc(){

char *s=(char*)malloc(100);

return s;

}

int main()

{

char  *p=NULL;

p=myMalloc();

if(p==NULL)

printf("P is not changed!\n");

else{

printf("P has been changed\n");

free(p);

}

return 0;

}

知道了上述這些,就不難理解上面四個小程式的執行結果了。

4、二級指標在連結串列中的使用

在連結串列或者樹的操作中,也需要用到二級指標,

比如建立連結串列的頭指標:

在初始化連結串列函式中,傳入頭指標,並在函式中為該指標分配空間,此時就應該使用二級指標,如void initLinklist(Node **head);

而在新增刪除結點的過程中,我們並沒有改變函式引數指標的指向,而是通過傳入的指標如Node *head,找到要刪除結點的位置,並未對該指標做改變,因此退出函式後,該指標無影響。