一、指针的概念
1. 指针是内存中一个最小的单元编号,也就是地址
2. 我们日常口头说的指针代表的是指针变量
接下来我们来看内存地址和指针变量
字节是最小的编址单位,所以一个字节对应这一个地址,地址通常译十六进制表示,地址从上到下递减,存放变量时先使用高地址再使用低地址。
对于指针变量的理解可以通过整数变量来类比,整数变量是系统分配一块内存来存储整数的变量,则指针变量就是存储指针的变量,指针就是地址,故指针变量是存放地址的变量。我们可以通过&(取地址操作符)取出变量的内存起始地址,存储到该变量中。
了解到上面的概念我们来思考两个问题
- 计算机是如何编码的?
- 计算机分配给指针变量的内存大小是多少?
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。对于32位的机器假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0),那么产生的地址就会是从
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
…
11111111 11111111 11111111 11111111
一共有2^32个地址位。现在我们就知道了一个地址对应32位,也就是4个字节,所以指针变量要存储一个地址就需要4个字节,这是在32位的前提下,如果是64位则是8个字节。
二、指针的类型
我们知道变量的类型有整型、浮点型、字符型,那么指针变量有没有类型呢?答案是有的。
指针变量的写法是(数据类型* 变量名)如:
char* p类型的指针是为了存放 char 类型变量的地址。
short* p 类型的指针是为了存放 short 类型变量的地址。
int* p类型的指针是为了存放 int 类型变量的地址。
我们来思考一个问题,我们都知道像整型、浮点型等等这些不同的变量类型所占的内存大小是不同的,那么不同类型的指针变量所占的内存大小一样吗?
经过我们上面的分析显然是一样的,因为指针变量是存储地址的变量,不管是什么类型变量的地址的大小都是一样的,所以大小是一样的。那么既然是一样的为什么要设计这么多类型的指针变量呢?先带着思考看下去,答案在下面揭晓,不要急。
三、野指针
1.概念
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
2.野指针成因
(1)指针没有初始化
#include <stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;
return 0;
}
(2)指针访问越界
#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = arr; //数组名代表首元素地址
int i = 0;
for(i=0; i<=11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
(3)指向内存已经释放的内存
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = (int*)malloc(sizeof(int)*4); //开辟一段内存
free(p);//释放内存
*p; //野指针
return 0;
}
3.如何避免野指针
野指针是很危险的,所以避免使用野指针是每个程序员的必备技能。
- 指针初始化
- 小心指针越界
- 指针指向空间释放,及时置NULL
- 避免返回局部变量的地址
- 指针使用之前检查有效性
四、指针运算(重点)
1.解引用运算(*)
该运算符,可以让我们找到指针变量的指向的变量。找到之后就能任意的修改它了。
#include <stdio.h>
int main()
{
int a = 20;
int *p = &a; //存放a的地址;
printf("%d %d",*p,a); //打印结果是20 20
*p = 10;
printf("%d %d",*p,a); //打印结果是10 10
//可以理解为*p和a等价
return 0;
}
这里我们解答一下上面为什么要设计这么多类型的指针变量?这个问题。
#include <stdio.h>
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
int *pi = &n;
*pc = 0; //重点在调试的过程中观察内存的变化。
*pi = 0; //重点在调试的过程中观察内存的变化。
return 0;
}
一开始n在内存中的存储
pc = 0; 执行后n在内存中的存储
pi = 0;执行后n在内存中的存储
总结:指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)
比如: char 的指针解引用就只能访问一个字节,而 int 的指针的解引用就能访问四个字节
2.指针加减整数
这也是设计这么多类型的指针变量的原因之一。
#include <stdio.h>
//演示实例
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return 0;
}
总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。
3.指针减指针
指针相减 = (地址1-地址2)/sizeof(类型),放在数组上看的话,就是两个指针之间的元素个数。