C语言(指针详解)

目录

指针的概念

指针变量和地址以及解引⽤操作符(*)

指针的类型

野指针

如何规避野指针

指针和数组

二级指针

指针数组

字符指针变量

数组指针

数组的地址(&arr)和数组首元素(arr)的地址的区别

函数指针变量

函数指针数组


指针的概念

  1. 指针是内存中一个最小单元的编号,也就是地址
  2. 平时说的指针,通常指的是指针变量,是用来存放内存地址的变量
  3. 可以认为:内存单元的编号 == 地址 == 指针

指针变量和地址以及解引⽤操作符(*)

在c语言中创建变量其实就是向内存申请空间

我们可以通过&(取地址操作符)取出变量的内存与实地址,把地址可以存放到一个变量中,这个变量就是指针变量。

我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针) 指向的对象,这⾥就需要用到⼀个操作符叫解引⽤操作符(*)。

比如:

上面的第五行代码就是把a的地址取出来存放到p里面去,这里的p就是指针变量。第六行代码里的*p意思就是通过p中存放的地址,找到指向的空间,所以*p就是10。

指针的类型

指针的类型就跟我们变量的类型一样,不同类型的变量的地址就应该放在对应的指针变量中。

那么指针的大小是多少?

无论哪一种的指针类型的大小在32位平台上是4个字节,在64位上是8个字节,都是一样的。

而我们之所以要区分类型是因为不同类型的指针±整数所跳过的字节数不同。

我们看这张图

会发现

int*类型的+1会跳过四个字节;

char*类型的+1会跳过1个字节;

double *类型的+1会跳过8个字节;

哎,是不是发现了这和变量类型的大小一样,看这张图

char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节。 这就是指针变量的类型差异带来的区别。指针+1,其实跳过1个指针指向的元素。

所以说:指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)。

指针可以+1,那也可 以-1。事实是指针减指针得到的结果就是两个指针之间所隔的元素个数。

野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

造成野指针出现的原因主要有:

1,指针未初始化。

2,指针越界访问。

3,指针指向的空间释放

如何规避野指针

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放,及时置NULL

NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使⽤的,读写该地址 会报错。

指针和数组

我们使⽤ &arr[0] 的⽅式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址,⽽且 是数组⾸元素的地址。

从这可以看出,无论是&arr[0]还是arr,它们都代表这arr数组首个元素的地址

数组名大多数情况都是首元素地址。
但有两种情况除外:

1,sizeof(数组)这里的数组名是数组的地址

2,&(数组),这里的数组名也是数组的地址

二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪⾥?

当然,指针变量也有地址,而存储指针的变量叫做二级指针。

它们大概就是这样的

二级指针存储的是一级指针的地址,而指针解引用可以找到被指针指向的变量。二级指针解引用也可以找到一级指针。

指针数组

顾名思义:就是存放指针的数组。

指针数组的每个元素都是⽤来存放地址(指针)的。

指针数组的每个元素是地址,⼜可以指向⼀块区域。

其它类型也基本如下:

用指针数组模拟二维数组:

arr[i]是访问arr数组的元素,arr[i]找到的数组元素指向了整型⼀维数组,arr[i][j]就是整型⼀维数 组中的元素。

注意:虽然指针数组的使用与二维数组很想,但两者却不能看成一个东西,因为每⼀⾏并⾮是连续的。

字符指针变量

在指针的类型中我们知道有⼀种指针类型为字符指针 char* ;

还有一种情况:

就是创建一个字符指针变量,将字符串的首元素地址赋给他。

注意看:这里是将字符串中的首元素地址存在 ch 中,而非字符串的地址

数组指针

定义:数组指针是用来存放数组地址的指针

pa先和*结合,说明pa是⼀个指针变量,存放的是int类型的变量,然后指针指向的是⼀个⼤⼩为5个整型的数组。所以pa是 ⼀个指针,指向⼀个数组,叫 数组指针。

这⾥要注意:[ ]的优先级要⾼于*号的,所以必须加上()来保证p先和*结合。

数组的地址(&arr)和数组首元素(arr)的地址的区别

这样一看&arr和arr的地址好像都一样,但还是有区别的,接下来把它们都加1看看

可以看到打印出来的第三行和第四行在十六进制下相差了10个字节,相当于十进制的16,而第三行和前两行之间差了20个字节

因为:(1)数组首元素地址 +1 :这里的地址在十六进制的状态下,相比之下地址的大小增加了 4 ,十进制下也是 4 ,数组储存变量是 int 内存大小也是 4 个字节 ,这里我们可以得到数组首元素地址 +1 ,也就是跳过了一个变量大小的字节数。

(2)数组地址 +1 :这里的地址在十六进制的状态下,相比之下地址的大小增加了 28 ,十进制下就是 40 ,数组储存变量是 int 内存大小也是 4 个字节并且数组元素个数是 10 个元素 ,这里我们可以得到数组首元素地址 +1 ,也就是跳过了一个数组大小的字节数。

  • 数组首元素地址 +1 ,跳过一个变量的大小。
  • 数组地址 +1 , 跳过一个数组的大小

函数指针变量

函数指针变量应该是⽤来存放函数地址的,未来通过地址能够调⽤函数的。

格式如下:

int   (*pf3)      (int x, int y)
|       |         -------------
|       |         |
|       |         pf3指向函数的参数类型和个数的交代
|       函数指针变量名
pf3指向函数的返回类型


int (*) (int x, int y) //pf3函数指针变量的类型

例子:

函数指针数组

函数指针数组是一个数组用来存储函数指针的。

int(*pf[])(int ,int) ----方块中的是元素个数

运用函数指针数组写一个计算器:

#include <stdio.h>
int jia(int x, int y)
{
	return x + y;
}
int jian(int x, int y)
{
	return x - y;
}
int cheng(int x, int y)
{
	return x * y;
}
int chu(int x, int y)
{
	return x / y;
}
int main()
{
	int ar = 0;
	int x, y;
	int(*arr[5])(int,int) = {0,jia,jian,cheng,chu};
	do 
	{
		printf("************************\n");
		printf("******* 0.退出  ********\n");
		printf("**** 1,加   2,减   *****\n");
		printf("**** 3.乘   4.除   *****\n");
		printf("************************\n");
		printf("************************\n");
		scanf("%d", &ar);
		if (ar >= 1 && ar <= 4)
		{
			printf("请输入两个数: ");
			scanf("%d %d", &x, &y);
			int aee = (*arr[ar])(x, y);
			printf("%d\n", aee);
		}
		else if (ar == 0)
		{
			printf("退出游戏\n");
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}

	} while (ar);
	return 0;
}

以上就是我对指针的理解,如有错误,请指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值