目录
指针的概念
- 指针是内存中一个最小单元的编号,也就是地址
- 平时说的指针,通常指的是指针变量,是用来存放内存地址的变量
- 可以认为:内存单元的编号 == 地址 == 指针
指针变量和地址以及解引⽤操作符(*)
在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,指针指向的空间释放
如何规避野指针
- 指针初始化
- 小心指针越界
- 指针指向空间释放,及时置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;
}
以上就是我对指针的理解,如有错误,请指正。