目录
🥑🍓Let's go🍓🥑
一:指针是什么?
指针理解的2个点:
1.指针是内存中一个最小单元的编号,也就是地址。
2.平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。
【总结】:指针就是地址,口语中说的指针通常指的是指针变量。
指针变量:可以通过&(取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个变量就是指针变量。
🐶🐶具体举例:
#include <stdio.h>
int main()
{
int a = 10;//内存中开辟一块空间
int* pa = &a;
//变量a,取出它的地址,可以使用&操作符
//a变量占用4个字节的空间,
//这里是将a的4个字节的第一个字节的地址存放在p变量中,
//p就是一个指针变量。
return 0;
}
✍️✍️【注】:指针的大小在32位平台是4个字节,在64位平台是8个字节
二:指针和指针类型
2.1 指针
🐱 🐱具体举例:
#include <stdio.h>
int main()
{
int a = 10;
int* pa = &a;
*pa = 20;
printf("a=%d", a);
return 0;
}
2.2 指针类型
🐱 🐱具体举例:
#include <stdio.h>
int main()
{
int * pa = NULL;
char * pb = NULL;
short * pc = NULL;
long * pd = NULL;
float* pe = NULL;
return 0;
}
等等
2.3 指针+-整数
🐱 🐱具体举例:
#include <stdio.h>
int main()
{
int n = 10;
char* pa = &n;
int* pi = &n;
printf("%p\n", &n);
printf("%p\n", pa);
printf("%p\n", pa+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return 0;
}
🉐🉐:
㊙️㊙️ 分析如下:
✍️✍️【总结】:指针的类型决定了指针向前或者向后走一步有多大(距离)
2.4 指针的解引用
🐱 🐱具体举例:
#include <stdio.h>
int main()
{
int n = 0x11223344;
char* pa = &n;
int* pi = &n;
*pa = 0;
*pi = 0;
return 0;
}
🉐🉐:
n的地址与在内存中存储的内容
*pa=0后得到下图。分析如下:因为pa的类型是char类型,为一个字节。
所以只能改变一个字节的内容。
*pi后得到下图。分析如下:因为pi的类型是int类型,为四个字节。
所以可以改变4个字节的内容。
【总结】:
三:野指针
3.1野指针成因
3.1-1 指针未初始化
🦊🦊具体举例:
#include <stdio.h>
int main()
{
int* p;//局部变量指针未初始化,默认为随机值
*p = 20;//非法访问内存
return 0;
}
3.1-2 指针越界访问
🦊🦊具体举例:
#include <stdio.h>
int main()
{
int arr[10] = {0};
int* pa = arr;
int i = 0;
for (i = 0; i <= 10; i++)
{
*pa = i;
pa++;
}
return 0;
}
☀️☀️分析得:
3.1-3 指针指向的空间释放
🦊🦊具体举例:
#include <stdio.h>
int* test()
{
int a = 10;
return &a;
}
int main()
{
int* p = test();
*p = 20;
return 0;
}
☀️☀️分析得:
3.2如何规避野指针
1. 指针初始化2. 小心指针越界3. 指针指向空间释放,及时置 NULL4. 避免返回局部变量的地址5. 指针使用之前检查有效性
#include <stdio.h>
int main()
{
当前不知道p应该初始化为什么地址的时候,直接初始化为NULL
int* p = NULL;
明确知道初始化的值
int a = 10;
int* p = &a;
注意:
当定义指针变量初始化为NULL后,不可在对其进行赋值
int* pa = NULL;
*pa = 10;
所以在初始化指针时,先判断是否为NULL,在进行初始化
int* pb = 10;
if (pb != NULL)
{
*pb = 20;
}
return 0;
}
[注]:1.空指针可以确保不指向任何对象或函数;而未初始化指针则可能指向任何地方。
2.空指针与任何对象或函数的指针值都不相等
3.任何指针都可以转化未void*
4.void*可以转化为任何指针
5.指针虽然高效、灵活但是可能不安全
四:指针运算
4.1指针+-整数
🐼🐼具体举例:
#define N 5
#include <stdio.h>
int main()
{
float arr[N];
float* vp;
//指针+-整数:指针的关系运算
for (vp = &arr[0]; vp < &arr[N];)
{
*vp++ = 0;
}
return 0;
}
☀️☀️分析得:
4.2指针-指针
🐼🐼具体举例:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
char ch[5];
int ret = &arr[9] - &arr[0];
printf("%d\n",&arr[9]-ch[3]);//这里是错误的
printf("ret=%d\n", ret);
return 0;
}
☀️☀️分析得:
【注】:指针和指针相减的前提是:两个指针指向的是同一块空间。
4.3指针的关系运算
🐼🐼具体举例:
#define N 5
#include <stdio.h>
int main()
{
int arr[N];
int* vp;
for (vp = &arr[5]; vp > &arr[0];)
{
*--vp = 0;
}
return 0;
}
☀️☀️分析得:
代码简化得:
#define N 5
#include <stdio.h>
int main()
{
int arr[5];
int* vp;
for (vp = &arr[N - 1]; vp > &arr[0]; vp--)
{
*vp = 0;
}
return 0;
}
☀️☀️分析得:
【注】:标准规定:
五:指针和数组
🐯 🐯 具体举例:
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);//数组名是数组首元素的地址
printf("%p\n", &arr[0]);
return 0;
}
🉐🉐
【注】:数组名是数组首元素的地址
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%p<==>%p\n", &arr[i], p + i);
}
return 0;
}
🉐🉐
六:二级指针
🐨🐨具体举例:
#include <stdio.h>
int main()
{
int a = 10;
int* pa = &a;//pa是指针变量,一级指针
int** ppa = &pa;//ppa是一个二级指针
//*ppa表示是一个指针变量,int* 表示ppa的类型
* pa == a;
**ppa == a;
return 0;
}
七:指针数组
🐯 🐯具体举例:
#include <stdio.h>
int main()
{
int arr[10];//整形数组 - 存放整形的数组就是整形数组
char ch[5];//字符数组 - 存放的是字符
//指针数组 - 存放指针的数组
int* parr[5];//整形指针的数组
char* pch[5];
return 0;
}
🌈🌈文章结束☀️☀️
这份博客👍如果对你有帮助,给博主一个免费的点赞以示鼓励欢迎各位🔎点赞👍评论收藏⭐️,谢谢!!!
如果有什么疑问或不同的见解,欢迎评论区留言欧👀