數組與指針的理解

在我們平時寫程序的時候,在調用函數傳遞一個數組時,經常用到的是用一個對應的數組或者指針來接受。那麼,是不是就可以理解爲數組等於指針,指針就等於數組,我們來做一個小實驗來驗證一下看是不是數組就等於指針

#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>

#include <stdio.h>

extern int x;
extern char *arr;
extern char p[];

int main()
{
	printf("%d\n",x);
	printf("%s\n",arr);
	printf("%s\n",p);
	system("pause");
	return 0;
}

int x = 10;

char arr[] = "abcdef";
char *p = "abcdef";


在test1裏創建一個整形變量 、數組和指針。然後在另一個test裏用全局變量調用,然後輸出,看一下程序的結果




  第一個結果是整形變量傳過來了,而第二個是程序崩潰了,第三個輸出的是dX?

這就說明整形可以傳過來,函數不能通過指針來輸出,而指針可以通過數組來輸出出來!

那爲什麼數組和指針爲什麼會出錯,我們來分析一下

一個數組如果用指針來引用就是相當於得到了arr數組的地址,那麼當用指針來訪問時,會到這個指針的地址去找,

輸出是不會的到數組的內容的。再看看用數組來聲明指針時,爲什麼得到的dX?

因爲到用數組聲明指針時,數組是得到的是指針的地址,而不是指針指向的地址,不妨我們來看一下指針的地址是什麼然後在內存中查看一些看看地址對應的內容是什麼



前面的博客提到過,在VS裏地址是小端存儲的,而p的地址是00d15864,然後在看面看到對應的內容就是dX?

所以數組和指針不是一回事,不過在平時調用時是可以相互接受的,只是要寫對格式


再來看看指針數組與數組指針


指針數組

指針數組顧名思義意就是一個數組,只不過數組的內容是指針而已,像int* arr[10],char* arr[10],int** arr[10]都是指針數組。

in* arr[10] 由於數組和[]的結合要高於*,所以它是一個數組,然後裏面存放的都是int *類型的元素,所以它是一個指針數組。

char* arr[10] 是一個char*類型元素的指針數組

int** arr[10]是一個int **類型元素的指針數組


以前在進行字符串冒泡時我們會用到arr[][]二維數組來進行字符串的數組存放,那現在是不是就可以直接用指針數組的方式來存放字符串呢?

#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>

#include <stdio.h>


int main()
{	
	int i= 0;
	char *arr[5] = {"ab","cd","ef","gh"};
	for(i=0; i<5; i++)
	{
		printf("%s\n",arr[i]);
	}
	system("pause");
	return 0;
}
程序的運行結果到底對不對呢?



結果沒問題,所以指針指針數組裏存放的元素類型就是地址


數組指針

      數組指針顧名思義就是指向數組的指針,像int (*p)[10]

這裏p先和*結合成(*p)說明它是一個指針,然後它的大小是[10],所以它是一個指向整形數組大小爲10的指針。


先來看一看這段代碼,猜猜看執行*p+1和*parr+1後地址分別有什麼變化?

#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>

#include <stdio.h>


int main()
{
	int arr[10] = {1,2,3,4,5,6};
	int *p = arr;
	int (*parr)[10] = &arr;
	*p+1;
	*parr+1;
	system("pause");
	return 0;
}


在內存中看到再執行了*p+1和*parr+1之後,第一個地址增加了四個字節,第二個增加了40個字節,說明*p是指向數組首元素的地址,在增加1之後指針向後偏移一個,而*parr是一個數組指針在執行了*parr+1後,跳過了這個數組,直接指向了下個數組的首地址

這就是說明,數組指針是一個指向指定類型數組的指針,拿到一個數組指針就是相當於操作了整個數組

那要是訪問一個一維數組指針該怎麼訪問呢?

#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>

#include <stdio.h>


int main()
{
	int arr[10] = {1,2,3,4,5,6};
	int (*parr)[10] = &arr;
	printf("%d\n",*(parr[0])+3);  //訪問第四個元素
	system("pause");
	return 0;
}
我們直接來看一下結果



沒錯,訪問到了第四個元素了,

那就來解剖一下,parr[0]相當於*(parr)+0,就是先訪問parr首地址,然後+0;實際上就是指向第一個元素,然後+3就是相當於指向了第四個元素的地址,然後在解引用一下就是第四個的元素內容了,輸出來的就是4。


那二維數組可不可以用數組指針的形式來訪問呢?

#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>

#include <stdio.h>


int main()
{
	int arr[2][5] = {1,2,3,4,5,6,7,8,9,0};
	int (*p)[5] = arr;	//將arr數組傳個一個數組指針(*p)[5]
	int i = 0;
	int j = 0;
	for(i=0; i<2; i++)
	{
		for(j=0; j<5; j++)
		{
			printf("%d ",*(*(arr+i)+j));  //先給arr+i就是指第i行,解引用拿到第i行的首元素地址,然後+j就是第i行的第j個元素地址,再解引用一下就是拿到了對應的元素內容
		}
		printf("\n");
	}

	system("pause");
	return 0;
}



函數指針

函數指針,首先它是一個指針 ,是指向函數的指針!像char* (*fun)(char* s1,char* s2)

#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>

#include <stdio.h>

void test()
{
	printf("hehe\n");
}
int main()
{
	void (*pfun)();
	pfun = test;
	(*pfun)();
	system("pause");
	return 0;
}
這裏把test函數先賦給pfun,然後pfun先和*結合成一個指針,然後和()結合,說明它是一個指向函數的指針!

結果不明而言,會通過訪問函數指針來訪問test的內容



函數指針數組

看名字可以想到它是一個數組,然後數組的內容是函數指針而已!像(*fun[4])(int , int);

(*fun[4])(int ,int)剖析:先是fun和[4]結合,說明他是一個數組,然後*結合說明是指向數組的指針,然後和後面的形參結合說明是一個指向數組的函數指針,實際上就是數組裏存放的元素是函數指針!

#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>

#include <stdio.h>

int Add(int a,int b)
{
	return a+b;
}

int Sub(int a,int b)
{
	return a-b;
}
int Mul(int a,int b)
{
	return a*b;
}
int Div(int a,int b)
{
	return a/b;
}

int main()
{
	int input = 0;
	int ret = 0;
	int (*pfun[5])(int ,int ) = {NULL,Add,Sub,Mul,Div};//爲了讓Add作爲第一個
	scanf("%d",&input);
	ret = (*pfun[input])(2,3);
	printf("%d\n",ret);
	system("pause");
	return 0;
}
看這段代碼,實際上是爲了更方便的調用不同的函數,(*pfun[5])(int ,int ) = {NULL,Add,Sub,Mul,Div},這句代碼就是將四個函數以指針的形式存放在一個數組裏,然後通過調用不同的數組下標來訪問每一個函數。

這裏如果輸入input爲1,那就是結果應該是5,我們來看一下




指向函數指針數組的指針

我第一次看到這個名字就虛了,這麼長的名字怎麼搞嘛,但是隻要你認真的一點一點解讀這個,你會發現它其實也不是很難,接下來我們就先來解讀一下。

首先,它是一個指針。指針是指向的是一個函數指針數組,而函數指針數組我們上面剛剛分析了,是一個數組,裏面的元素都是函數指針。那這句話完整的意思應該就是有一個指向元素爲函數指針的數組的一個指針。

#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>

#include <stdio.h>

int Add(int a,int b)
{
	return a+b;
}

int Sub(int a,int b)
{
	return a-b;
}
int Mul(int a,int b)
{
	return a*b;
}
int Div(int a,int b)
{
	return a/b;
}

int main()
{
	int (*arr[5])(int ,int) = {NULL,Add,Sub,Mul,Div};
	int (*(*pfun)[5])(int ,int) = &arr;
	int ret = 0;
	ret = (*pfun)[1](2,3);
	printf("%d\n",ret);
	system("pause");
	return 0;
}
來看看這個程序,首先(*arr[5])(int ,int) = {NULL,Add,Sub,Mul,Div},這個是上面的那個函數指針數組。

(*(*pfun)[5])(int ,int) = &arr,先把arr的地址賦給pfun,然後對剛剛的函數指針數組解引用。

對於*pfun就是說得到了pfun這個函數的首地址,[1]拿到的就是第二個元素的地址,第二個元素是Add,(2,3)是將2,3進行Add運算,得到的結果應該就是5,那是不是呢?我們來看看



指針這一塊對於我們這些初學者來說可能會有點困難,但是並不是就是一定不會,只要從拿到的代碼一點一點分析,然後一段一段的解剖,最後把每一段連接起來,你就會發現你大概能夠看懂是什麼模型了!指針這一塊一定不要急功求進,一點一點積累方纔能弄懂!

發佈了43 篇原創文章 · 獲贊 47 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章