学习C语言快两个月啦~~
但是感觉有好多都忘记了,尤其是学到指针进阶这一块无限套娃就开始分不清了
所以开始写备忘录来温故而知新一下
(特别鸣谢@比特鹏哥,虽然我是B站白嫖怪(主要是因为穷))
################################################################################
目录
指针是什么
指针和指针类型
野指针
指针运算
指针和数组
二级指针
指针数组
指针是什么?
指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值
通过地址能找到所需的变量单元 -> 地址指向该变量单元
通过指针可以找到以指针为地址的内存单元
指针是用来存放地址的,地址是唯一标识一块地址空间的
指针的大小在32位平台是4字节,在64位平台是8字节
指针和指针类型
指针类型的意义:
指针类型决定了指针解引用的权限有多大
指针类型决定了指针向前或向后走一步距离是多少(指访问内存的地址)->步长
不同类型的指针都是有其使用的意义的
野指针
指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
int* test()
{
int a = 10;// 仅在test函数内部给a创建了一块地址,出函数则创建的空间销毁
return &a;
}
int main()
{
// 野指针p:指针未初始化
int* p;// p是一个局部变量,局部变量不初始化则默认是随机值
*p = 20;
printf("%d\n", p);
// 野指针p:指针越界访问
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i <= 10; i++)
{
*p = i;
p++;
}
int j = 0;
for (j = 0; j < 10; j++)
{
printf("%d ", arr[j]);
}
// 野指针p:指针指向的空间释放
int* p = test();
*p = 20;
return 0;
// 规避野指针:指针初始化
// 小心指针越界
// 指针指向的空间释放及时置NULL
// 指针使用之前检查有效性
// 不知道p应该初始化成什么地址时,赋初值NULL
int* p = NULL;
// 明确知道初始化初始化的值
int a = 10;
int* p = &a;
}
int main()
{
int a = 10;
int* p = &a;
printf("%d %p\n", *p, p);
int arr[5] = { 1,2,3,4,5 };
int* p2 = arr;
printf("%d %p\n", *p2, p2);
printf("%d %p\n", *(p2+1), p2+1);
printf("%d %p\n", *(p2+2), p2+2);
printf("%d %p\n", *(p2+3), p2+3);
printf("%d %p\n", *(p2+4), p2+4);
return 0;
}
野指针总结:
野指针产生的几种情况:
1、指针未初始化
2、指针越界访问
3、指针指向的空间释放
规避野指针:
指针初始化
小心指针越界
指针指向的空间释放及时置NULL
指针使用之前检查有效性
(不知道p应该初始化成什么地址时,赋初值NULL)
指针运算
·指针 ± 整数
·指针 - 指针
·指针的关系运算
int my_strlen(char* p)
{
int count = 0;
char* start = p;
while (*p != '\0')
{
p++;
count++;
}
printf("%d\n", p - start);
return count;
}
int main()
{
// 指针 ± 整数
// 指针的每一次递增,它其实会指向下一个元素的存储单元
// 指针的每一次递减,它都会指向前一个元素的存储单元
// 指针在递增和递减时跳跃的字节数取决于指针所指向变量数据类型长度,比如int就是4个字节
int arr[5] = { 1,2,3,4,5 };
int* p = arr;
int* pend = arr + 4;
while (p <= pend)
{
printf("%d ", *p);
p++;
}
// 指针 - 指针
// 指针不适合做加法运算,一般用于减法运算 - 非法操作
int arr[5] = { 1,2,3,4,5 };
printf("%d ", &arr[4] - &arr[0]);// 指针1 - 指针2 = 指针1和指针2之间的元素个数(前提:指针1指针2指向同一块空间)
printf("%p ", &arr[4]);
printf("%p ", &arr[0]);
int len = strlen("abc");
int len2 = my_strlen("abcd");
printf("%d\n", len);
printf("%d\n", len2);
// 指针的关系运算
// 标准规定:允许向数组元素的指针与指向最后一个元素后面那个内存位置的指针比较
// 但是不允许与指向第一个元素之前的那个内存位置的指针进行比较
// 指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的关系。例如:
// pf1==pf2表示pf1和pf2指向同一数组元素
// pf1>pf2表示pf1处于高地址位置
// pf1<pf2表示pf2处于低地址位置
return 0;
}
指针和数组
int main()
{
int arr[5] = {1,2,3,4,5};
//arr;// 数组名是数组首元素的首地址
printf("%p\n", arr);
printf("%p\n", &arr[0]);
int* p = arr;
// arr[2] <==> *(arr+2) <==> *(p+2) <==> *(2+p) <==> *(2+arr) == 2[arr] 我不懂但我大受震惊
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d的地址是: 指针: %p,数组: %p\n", *(p + i), p + i,arr + i);
printf("%d\n", p[2]);
}
return 0;
}
二级指针
int main()
{
int a = 0;
int* pa = &a;
// ppa - 二级指针变量
int** ppa = &pa;
printf("*pa的地址是%p *ppa的地址是%p\n", pa, ppa);
return 0;
}
指针数组
本质上是一个数组
int main()
{
int arr[5] = { 0 };// 整型数组
int* parr[5];// 整型指针的数组
char* pch[5];// 字符型指针数组
return 0;
}