函數(shù)是任何一門語言中必不可少的部分,正是由這些函數(shù)組成了程序。首先談一下C語言中的函數(shù)指針與指針函數(shù),再了解一下函數(shù)參數(shù)傳遞的相關原理。
1.函數(shù)指針與指針函數(shù)
(1) 函數(shù)指針 即指向這個函數(shù)的指針,定義為 數(shù)據類型 (*fun)(參數(shù)列表) ,()的優(yōu)先級比*高,所以*fun加括號。如 void (*fun)(int*,int*);
(2)指針函數(shù) 即返回值是指針的函數(shù),定義為 數(shù)據類型 * fun(參數(shù)列表). 如 char* fun(int*,int*);即返回值為char*型。
在C語言中,變量有它的地址,同理函數(shù)也是有地址的。那么把函數(shù)的地址賦給函數(shù)指針,再通過函數(shù)指針調用這個函數(shù)就可以了。
第一步: 定義函數(shù)指針,如 int (*pfun)(int*,int*);
第二步: 定義函數(shù) 如 int fun(int*,int*);
第三步: 把函數(shù)的地址賦給函數(shù)指針,即 pfun=fun;
第四步: 通過函數(shù)指針去調用這個函數(shù) (*pfun)(p,q); //pfun是函數(shù)的地址,那么 *pfun當然就是函數(shù)本身了。
2.函數(shù)參數(shù)傳遞問題
在C語言中,有兩種參數(shù)傳遞的方式 ,一種是值傳遞,另一種是指針傳遞。
值傳遞很好理解,即把實參的值傳遞給形參。
而指針傳遞傳的是地址在C語言中,形參值的改變并不能改變實參的值,但形參所指向內容值的改變卻能改變實參,這一點非常的重要,是指針傳遞的精華所在。
3. 指針函數(shù)
當函數(shù)的返回值為指針類型時,應該盡量不要返回局部變量的指針,因為,局部變量是定義在函數(shù)內部,當這個函數(shù)調用結束了,局部變量的棧內存也被釋放了,因此,不能夠正確的得到返回值。實際上,內存已經被釋放了,但這個指針的地址已經返回過去了,但是這個地址已經是無效的了,此時,對這個指針的使用是很危險的。
4. 野指針
野指針并不是NULL,而是指向垃圾內存的指針。
有兩種情況可以導致野指針:
(1) char* p;
(2)malloc,free
第一種情況是定義指針,但沒有給指針賦地址,此時,對指針的使用是很危險的,因為你不知道它指向哪里,是個野指針。
第二種情況,malloc是在堆上分配內存,必須由用戶手動釋放,當釋放之后,指針指向的內存已經釋放掉了,但指針本身的地址還存在,即指向了一個無效的內存,所以這時的指針為野指針,必須把這個指針p=NULL.
5. 下面舉個例子說明上述幾種情況
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
void fun1(int*,int*);
void fun2(int*,int*);
char* fun(char*,char*);//指針函數(shù),即返回值為指針的函數(shù)
int main(){
//定義3個函數(shù)指針
void (*pfun1)(int*,int*);
void(*pfun2)(int*,int*);
char*(*pfun)(char*,char*);//定義返回值為指針的函數(shù)指針
int *p;
int *q;
int a=10;
int b=20;
p=&a;//整形指針變量的初始化
q=&b;
printf("%d\n",*p);
printf("%d\n",*q);
pfun1=fun1;//把函數(shù)fun的地址賦值給函數(shù)指針pfun
pfun2=fun2;
(*pfun1)(p,q);//用函數(shù)指針去調用函數(shù),pfun是fun的地址,那么*pfun當然就是函數(shù)本身了
printf("%d\n",*p);
printf("%d\n",*q);
//當交換兩個指針時,發(fā)現(xiàn)值并沒有發(fā)生改變
//在C語言中,形參的改變并不能改變實參,實參中p指向a的地址,q指向b的地址,在形參中,把兩個地址互換,即形參的p指向b的地址,q指向a的地址,但并不能改變實參的值,除非改變地址中的內容值
(*pfun2)(p,q);
printf("%d\n",*p);
printf("%d\n",*q);
//此時p與q指向的值發(fā)生了變化,由于把地址中的內容交換了,所以交換了p,q
pfun=fun;
char* x="ab";
char* y="bc";
char* s=(*pfun)(x,y);
printf("%s\n",s);
//free(s);//s指向這個堆內存,所以malloc之后要釋放
s=NULL;
if(s!=NULL){//釋放掉這個內存后,指針仍然不為空,此時的指針稱為野指針,所以要把s=NULL
printf("%s\n",s);
}
//對于野指針,有兩種情況
//第一種情況: char* p;只聲明了字符型指針,但沒明確指向的地址,此時,用這個指針是很危險的,因為這個指針是野指針
//第二種情況: malloc()之后,沒有free()之后,沒有把指針設置為空,因為此時指針仍然存有地址,但是這個地址已經是無效的,所以對這個指針的使用是很危險的
return 0;
}
void fun1(int*p,int*q){
int* temp=p;
p=q;
q=temp;
}
void fun2(int*p,int*q){
int temp;
temp=*p;
*p=*q;
*q=temp;
}
char* fun(char*p,char* q){
//char a[]="abc";//定義一個內存空間,局部變量棧上內存
//char* s=a;
//return s;//在這函數(shù)結束之后,char型指針被釋放掉,因此不能正確返回
//因此,最好別返回一個局部變量指針
//(1)解決方法:把數(shù)組變成靜態(tài),即 static char a[]="abc";靜態(tài)內存在函數(shù)結束后不會被釋放
//(2)申請堆內存
//(3)定義為常量區(qū)
//char *s=(char*)malloc(sizeof(char*)*10);
// strcpy(s,"abc");
char* s1="ssss"; //定義一個指針變量指向字符串,在C中,字符串被存放在常量區(qū),靜態(tài)存儲區(qū)域,因此,在這個函數(shù)結束之后,這個地址仍然是有效的,即常量區(qū)的內存沒有被釋放掉,因此能夠返回值
return s1;
}
fun1函數(shù)中交換地址,并不能交換兩個指針指向的值,因為形參的改變不能引起實參的改變。
2. fun2函數(shù)
fun2函數(shù)交換的是地址里面的內容,所以能交換兩個指針指向的值。
3. fun函數(shù)
(1)fun函數(shù)里面定義的a是個局部變量,在函數(shù)返回之后這塊內存會被釋放掉。因此,為了得到返回值,可以聲明為 static char a[]=""abc";
(2)malloc申請的是堆內存,因此,可以得到返回值,但必須free掉這塊內存,同時將p=NULL,避免野指針。
(3)可以定義char* s=字符串,在C語言中,字符串是存放是靜態(tài)常量區(qū),因此,函數(shù)結束后,那塊內存不會被釋放掉??梢缘玫椒祷刂怠?/p>
因此,不能返回局部指針變量。
C語言中,形參只有在傳遞時才分配內存單元,實參到形參的傳遞是單向傳遞,因此,形參的改變并不能引起實參的改變,另外,實參與形參占據著不同的內存單元。
聯(lián)系客服