行业知识
C语言——指针——第1篇——(第19篇)
坚���就是胜利
文章目录
- 1.指针是什么
- 2.指针和指针类型
- (1)指针 + - 整数
- (2)指针 的 解引用
- 3.野指针
- (1)野指针成因
- 1.指针未初始化
- 2.指针越界访问
- 3.指针指向的空间释放
- (2)如何规避野指针
- 1.指针初始化
- 2.小心指针越界
- 3.指针指向的空间被释放时,及时置NULL
- `NULL 讲解`
- 4.避免返回局部变量的地址
- 5.指针使用之前检查有效性
- 4.指针运算
- (1)指针 + - 整数
- (2)指针 - 指针
- (1) 指针 - 指针 得到的数值的绝对值:是指针和指针之间的元素个数
- (2) 指针 - 指针 相减的前提条件是:指针和指针指向了同一块空间。
- (3)用函数写 计数器
- (3)指针的关系运算
1.指针是什么
在计算机科学中,指针是编程语言中的一个对象,利用指针,它的值直接指向存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为”指针“。意思是:通过它能找到以它为地址的内存单元。
指针是个变量,存放内存单元的地址(编号)。指针 = 地址 = 编号
# include int main(){int a = 10; //在内存中开辟一块空间int* p = &a; //这里我们对变量 a ,取出它的地址,可以使用 & 操作符 //将 a 的地址存放在 p 变量中,p 就是一个指针变量return 0;}总结:指针就是变量,用来存放地址的变量。(存放在 指针中的值 都被当成 地址 处理)
回答以下两个问题:1.一个小的单元到底是多大?答:1 个字节,1 Byte 2.如何编址?答:1 个字节给 1 个对应的地址(见以下内容)
经过仔细的计算和权衡,我们发现 一个字节 给 一个对应的地址 是比较合适的。
对于 32位 的机器,假设有 32根 地址线,那么假设每根地址线在寻址的是产生一个电信号正电/负电(1或者0)。
那么 32 根地址线产生的地址就会是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
…
11111111 11111111 11111111 11111111
这里就有 2 的 32 次方个地址。
每个地址标识 1 个字节,那我们就可以给 4GB的空闲进行编址。
(2^32Byte = 2^32/1024KB= 2^32/1024/1024MB = 2^32/1024/1024/1024GB = 4GB)
同样的方法,那64位机器,就非常非常大了。
这里就知道了:
1.在32位的机器上,地址是32个 0 和 1 组成的二进制序列,那地址就得用 4 个字节的空间来存储,所以一个指针变量的大小就应该是 4 个字节。
2.那如果在64位机器上,如果有 64 个地址线,那一个指针变量的大小是 8 个字节,才能存放一个地址。
总结:
1.指针是用来存放地址的,地址是唯一标示一块空间的。
2.指针的大小在 32 位平台是 4 个字节,在 64 位平台是 8 个字节。
2.指针和指针类型
#include int main(){char* pc = NULL; //用来存放 char 类型变量的地址int* pi = NULL; //用来存放 int 类型变量的地址short* ps = NULL;long* pl = NULL;float* pf = NULL;double* pd = NULL;printf("%d\n", sizeof(pc)); //4printf("%d\n", sizeof(pi)); //4printf("%d\n", sizeof(ps)); //4printf("%d\n", sizeof(pl)); //4 printf("%d\n", sizeof(pf)); //4printf("%d\n", sizeof(pd)); //4return 0;}(1)指针 + - 整数
总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。
#include int main(){int arr[10] = { 0 };int* p = arr;char* pc = arr;printf("%p\n", p); //0095F9C0printf("%p\n", p + 1); //0095F9C4printf("%p\n", pc); //0095F9C0printf("%p\n", pc + 1); //0095F9C1return 0;}#include int main(){int n = 10;char* pc = (char*)&n;int* pi = &n;printf("%p\n", &n); //010FF890printf("%p\n", pc); //010FF890printf("%p\n", pc + 1); //010FF891printf("%p\n", pi); //010FF890printf("%p\n", pi + 1); //010FF894return 0;}(2)指针 的 解引用
总结:
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如:char* 的指针解引用就只能访问 1 个字节,而 int* 的指针的解引用就能访问 4 个字节。
#include int main(){int n = 0x11223344;char* pc = (char*)&n;int* pi = &n; *pc = 0; //重点在调试的过程中,观察内存的变化 //由于是 char* 类型,只能改变 1 个字节的内存大小*pi = 0; //重点在调试的过程中,观察内存的变化 //由于是 int* 类型,则可以改变 4 个字节的内存大小return 0;}由于是 char* 类型,只能改变 1 个字节的内存大小
由于是 int* 类型,则可以改变 4 个字节的内存大小
#include int main(){int arr[10] = { 0 };char* p = arr; //由于 char* ,只能一个字节一个字节去访问内存int i = 0;for (i = 0; i3.野指针
概念:“野指针”就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
(1)野指针成因
1.指针未初始化
#include int main(){int* p; //局部变量指针未初始化,默认为随机的 //局部变量不初始化的时候,内容是随机值*p = 20; return 0;}2.指针越界访问
#include int main(){int arr[10] = { 0 };int* p = arr;int i = 0;for (i = 0; i *(p+i) = i; //这样做不会改变 p 中的地址}int j = 0;for (j = 0; j printf("%d\n", *(p + j));}return 0;}int arr[10] = { 0 };int* p = arr;int i = 0;for (i = 0; i *(p++) = i; //这样做改变了 p 中的地址}p = arr; //所以要将 p 中的地址保存为 arr 的 初始地址int j = 0;for (j = 0; j printf("%d\n", *(p + j));}return 0;}int arr[10] = { 0 };int* p = arr;int i = 0;for (i = 0; i