1. 程式人生 > >指針知識梳理3-指針作為參數

指針知識梳理3-指針作為參數

tracking 驗證 由於 ati text {0} fill popu views

一、函數傳參復習

#include <stdio.h>
//指針傳參,函數傳參本質是值傳遞

void  func1(int a)
{
		a = 5;	
}
void  func2(int *p)
{
		*p  = 10;	
		p++;
}
int main()
{
		int a = 0;
		int *p  = &a;
		//a 的值會變麽?
		func1(a);
		printf("%d\n",a);
		func2(&a);
		printf("%d\n",a);
		
		//這裏p的值會變麽?
		printf("p = %p",p);
		func2(p);
		printf("p = %p",p);
}



對於 func1來說,形參為int a,形參a是func1函數的一個局部變量。

在main函數中,也有一個int a,這個a 是main函數中的局部變量。

當調用 fucn1(a)的時候。僅僅是把main函數中的a的值傳遞給了func1函數的a變量。

畫內存圖例如以下:

技術分享圖片

當運行func1函數中 a = 5的時候。是在給func1函數中的變量a 賦值,對main函數中的變量沒有不論什麽影響,因此運行完func1的時候,main函數中的a值不變。

main函數中a的值不變的原因是在func1函數中不能訪問main函數中變量a的內存。

技術分享圖片

二、指針作為參數

func2函數的形參是 int *p ,是一個指針變量。存儲地址。

當函數調用的時候 func2(&a), 相當與int *p = &a。 p存儲的是a的地址,那麽在函數func2中就知道了main函數中a的地址,知道了a的地址就能訪問a的內存。

技術分享圖片

當在函數func2中 *p = 10的時候,是通過p存儲的地址找到main函數中的a ,並賦值。

技術分享圖片

當func2(&a)調用完成以後,main函數中a的值改變。

--------------------------------------------------------------------------------------------------------

再看例如以下:

在main 函數中另一個變量 int *p = &a。當 func2(p)的時候,事實上原理跟 一 分析的情況是一樣的。

在func2函數中有一個局部變量 p ,在 main 函數中也有一個局部變量 p;

當在main 函數中

p = &a;

func2(p);

的時候。我們畫出以下內存圖:

技術分享圖片

當在func2中 運行 *p = 10,p++的時候,改動了兩塊內存

(1)通過func2中的p找到main函數中a,並改動a的額牛才幹

(2)改動func2中p本身的內存。

技術分享圖片

main函數中的 p的內存並沒有改變,p的值並沒有變。

依據以上方法,大家畫以下內存圖,觀察變化。

#include <stdio.h>

void swap1(int a,int b)
{
		int temp  = a;
		a = b;
		b = temp;			
	
}
void swap2(int *pa,int *pb)
{
	
		int temp  = 0;
		temp = *pa;
		*pa = *pb;
		*pb = temp;		
		
		/*
		//錯誤點在哪裏?
		int *ptemp;
		*ptemp  = *pa;
		*pa = *pb;
		*pb = *ptemp;
		
		*/	
}
Int main()
{
	int a = 0;
	int b = 1;
	swap1(a,b);
	printf("a = %d,b = %d\n",a,b);
	swap2(&a,&b);
	printf("a = %d,b = %d\n",a,b);
	
}


三、數組名作為參數

1 、數組名作為參數的時候,本質上數組第一個元素的地址。

曾經在學函數的時候簡單提到:

int func1(int a[10]);

int func2(int a[4]);

int func3(int a[ ]);

中括號中面的數字沒有不論什麽意義。

上面三種寫法等效於

int func4(int *p);

func1 func2 func3 的a就是指針變量。僅僅只是寫法不一樣,記住語法就可以。

可以用例如以下代碼解釋和驗證。

#include <stdio.h>

/*
數組名的含義
*/
int func1(int a[10])
{
	printf("%d\n",sizoef(a));	 //指針,4個字節(32位)
	
}
int func2(int a[])
{
	printf("%d\n",sizoef(a));	 //指針,4個字節(32位)
	
}
int func3(int *p)
{
	printf("%d\n",sizoef(p));	//指針,4個字節(32位)
	
}
int main()
{
		int a[10];
		
		//在這裏 a 是整個數組 大小是 10個int ,sizeof是c語言的keyword。不是函數
		printf("sizeof a = %d\n",sizeof(a));
		
		//在這裏 a 是首元素的地址。
		int *p = a;
		printf("sizeof p = %d\n",sizeof(p));
		
		//在函數中 a 是首元素的地址。
		func1(a);
		func2(a);
		func3(a);
	
}

總結數組名的含義

int a[10];

(1)代表整個數組,sizeof(a),這裏是40。是整個數組的內存, sizeof不是函數。

(2)代表第一個元素的地址 int *p = a, func(a)。



這也就能解釋為什麽傳數組名的時候可以在函數中改動函數外面的數組的值,由於在函數中可以知道數組中每一個元素的地址。

#include <stdio.h>
/*
函數傳數組,數組名是首元素的地址
*/
int func1(int *p) //這裏有沒有漏洞?
{
	for(int i = 0;i<10;i++)
	{
		p[i] = 2;	 //*(p+i) = p[i]
	}	
	return 0;
}
int func2(int a[]) //這裏有沒有漏洞?
{	
	for(int i = 0;i<10;i++)
	{
		a[i] = 1;	
	}	
	return 0;
}


int main()
{
	int a[10] = {0};
	func1(a);
	for(int i = 0;i<10;i++)
	{
		printf("%d\n",a[i]);	
	}	
	func2(a);
	for(int i = 0;i<10;i++)
	{
		printf("%d\n",a[i]);	
	}
	return 0;
}

思考以上代碼:

假設 int a[5];

調用func1(a)還會正確嗎?








指針知識梳理3-指針作為參數