c语言 指针详解,指针,数组指针,函数指针,函数指针数组,函数指针数组指针 保姆级教程

目录:

一:1级指针

1.1:内存的使用

1.2:c语言内存中数据的访问

1.3:一级指针的定义方式

1.4:通过指针访问数据。

二:二级指针

2.1二级指针的创建和访问

三:数组 和 指针数组 还有数组指针

3.1数组的创建和访问

3.2指针数组:(本质是一个数组)

3.3数组指针:(本质是一个指针,实现代码如下)

四 :函数指针

五:函数指针数组   (转移表)定义和访问

六: 函数指针数组指针  (本质是一个指针)

一:1级指针

首先在对指针进行理解之前,我们要清楚下面这几个个概念:

1.1:内存的使用

和现实生活对空间的分别方式相似,给不同的地域不同的名称。例如,北京,上海等

而内存也是一块空间,所以对这块空间的不同位置进行不同的编号,用起来也会更加方便。

这些编号就是我们常说的地址了。

我们都知道 ,内存里最小的内存单元就是一个bit位 ,那多大的内存空间可以分配一块地址呢,在c语言的标准中规定,给每个字节大小的空间(8个比特位)配置一个专门的地址。

1.2:c语言内存中数据的访问

在c程序中创建一个变量a(这里我假设它的地址为0xff112233),那么我们通常是用变量名来访问这个数据,但是也可以用地址来访问这个数据 。那么要怎么通过地址来访问数据呢?????

这里就需要指针了。

1.3:一级指针的定义方式

#include<stdio.h>
int main()
{
	//一级指针
	int a = 10;
	int* pa = &a;
	printf("%d\n", a);
	printf("%d\n", *pa);
	return 0;
}

    int a = 10;//定义一个整形变量,变量中存储的数据是10
    int* pa = &a;//* 代表pa是一个指针 最前面的int代表pa指向的变量类型是整形类型

1.4:通过指针访问数据。

*pa=1;//代表对pa中的数据(也就是刚才拿到的a的地址)进行解引用,来访问a中的数据。

总结:指针里只能存放地址,地址也只能放置在指针中,对一级指针进行解引用就能通过他里面的地址来访问原变量a中存储的数据

2:二级指针

通过前面的了解我们知道,指针变量里面放置的是地址,而只要是变量,那肯定就有它自己的地址

    所以我们来看下面这个例子

2.1二级指针的创建和访问

**ppa也可以看成    *(*ppa) 首先*ppa表示对ppa中的数据进行解引用,就能访问pa中存储的数据 所以*ppa就想当于pa,而对pa进行解引用就能访问a了(在上面的例子我们可以看到这两钟形式打印出的数据一样)

所以 * *ppa 也就相当于  a 了

总结:

一级指针pa里存的是整形变量a的地址,二级指针ppa里存的是一级指针变量pa的地址。

以此类推n级指针的定义和访问方式相同。

三:数组 和 指针数组 还有数组指针

3.1数组的创建和访问

int  arr[10];

//这里表示arr是一个数组,【10】表示数组里有10个元素,int表示这个数组里面元素的类型是int型的。

数组的数组名存放的是这个数组首元素的地址。我们在通过数组名来访问数组中的数据的时候,

arr【0】在编译器看来就相当于    *(arr+0)

arr【0】<=>*(arr+0),这两种写法是完全等价的。

3.2指针数组:(本质是一个数组)

创建和访问的方式与普通数组相同

在了解这个之前我们来看一个整形数组的概念

int  arr[10];//这里表示arr是一个数组,【10】表示数组里有10个元素,int表示这个数组里面元素的类型是int型的。

了解这个概念,我们来对比指针数组的概念就很好理解了

int * arr【10】;//这里表示arr是一个数组,【10】表示数组里面有10个元素,*  表示这个数组中存储的数据类型是指针,int 代表这些指针所指向的数据类型是int型的。

3.3数组指针:(本质是一个指针,实现代码如下)

#include<stdio.h>
int main()
{
	//数组指针
	int arr[10] = {0 ,1,2,3,4,5,6,7,8,9};
	int (*parr)[10]=&arr;
	//这里parr就是arr数组的指针,简称数组指针
	for (int i = 0; i < 10; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *((*parr) + i));
	}
	printf("\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", (*parr)[i]);
	}
	printf("\n");
	return 0;
}


运行结果
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9

    int arr[10] = {0 ,1,2,3,4,5,6,7,8,9};//创建一个整形数组,里面有10个元素
    int (*parr)[10]=&arr;

1  &arr  拿出了arr这个整形数组的地址

2 (*parr)因为刚才拿出的是数组的地址,所以我们需要一个指针来接受

3  【10】代表这个指针指向的是一个包含10个数据的数组

4    int 代表这个数组的类型是整形

综上 parr就是这个arr数组的指针,简称为数组指针。(指向数组的指针)

好了 ,有上面的基础,我们可以类比的来写出  ,double *  arr1【5】的数组指针了

1  :要接受一个地址, 那么我们需要一个指针  (*parr1)。

2  :【5】这个指针指向的是一个有五个元素的数组

3  : double *表示这个数组里的元素类型是指向double类元素的指针

           double*(*parr1)【5】=&arr1;

这里parr1就是数组double *  arr1【5】的指针了。

四 :函数指针

他的定义类型和数组指针类似。

 void ment();//函数声明
    void (*p)()=&ment;

&ment 取出函数ment的地址,

(*p)既然是一个地址,那么我需要一个指针来接收

()表示这个指针指向的是一个函数,里面没有参数,函数不需要传参

  void  表示函数的返回类型。

 下面再来一个有参数有返回类型的例子。

当然,还有一种方式来创建函数指针

int (*pa)(int ,int )=ADD;

直接将函数名中的值赋给指针pa,因为对函数来说,函数不像数组,他没有首元素概念,他里面的地址就是函数本身的地址。

五:函数指针数组   (转移表)定义和访问

定义如下:

int((*parr[10]))(int, int) ;

详细解释如下:

 那像这样的复杂数组有什么用呢,这里就要知道他的另一个名称了   转移表 

下面我们通过一个简单的计算器程序来了解一个他的用法

#include<stdio.h>
void ment()
{
	printf("*************************************\n");
	printf("*************************************\n");
	printf("********  1 : ADD  2 : SUB  *********\n");
	printf("********  3 : MLU  4 : ESC  *********\n");
	printf("**********   0 : EXIT    ************\n");
	printf("*************************************\n");
	printf("*************************************\n");
}
int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}
int mlu(int x, int y)
{
	return x * y;
}
int esc(int x, int y)
{
	return x / y;
}
int main()
{
	int((*parr[10]))(int, int) = { NULL,add,sub,mlu,esc };
	//转移表
	int input;
	int x, y;
	do
	{
		ment();
		printf("请选择:\n");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
		    printf("请输入两操作数:");
		    scanf("%d%d", &x, &y);
		    printf("ret = %d\n", (parr[input])(x, y));
		}
		if (input == 0)
		{
			printf("退出程序:\n");
		}
		else
		{
			printf("选择错误,请重新选择:》\n");
		}
	} while (input);
	return 0;
}

int((*parr[10]))(int, int) = { NULL,add,sub,mlu,esc };

这里我们在对各种功能的函数进行调用时,我们可以先设置好函数的位置,然后直接通过数组下标来访问这个函数(这里和switch语句很相似,但是这样编写代码,可以大大减少代码量

六: 函数指针数组指针  (本质是一个指针)

定义方式如下:

int((*parr[10]))(int, int) = { NULL,add,sub,mlu,esc };

int (*((*p)[10]))(int,int) = &parr;

详解如下

这里p先和*结合,代表p是一个指针

【】代表这个指针所指向的类型是一个数组   10  代表这个数组中有10个元素 

((*p)【10】)外面的那个*代表这个数组中的元素类型是指针

(int ,int)代表指针指向的是一个函数,而函数的参数类型是两个int

最前面的那个int代表这个函数的返回类型是int型

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值