数组与指针的理解

在我们平时写程序的时候,在调用函数传递一个数组时,经常用到的是用一个对应的数组或者指针来接受。那么,是不是就可以理解为数组等于指针,指针就等于数组,我们来做一个小实验来验证一下看是不是数组就等于指针

#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,那是不是呢?我们来看看



指针这一块对于我们这些初学者来说可能会有点困难,但是并不是就是一定不会,只要从拿到的代码一点一点分析,然后一段一段的解剖,最后把每一段连接起来,你就会发现你大概能够看懂是什么模型了!指针这一块一定不要急功求进,一点一点积累方才能弄懂!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值