• 熟悉c语言指针


    一. 指针是什么?

    定义:

    指针就是内存中最小单元的编号 也就是地址
    我们平时说的指针 其实是一个指针变量 是用来存放内存地址的变量

    内存
    在这里插入图片描述
    每一块内存都有和它对应的地址

    指针变量 我们可以通过&操作符取出一个地址 把地址可以存放到一个变量中 这个变量就是指针变量

    它用来存放知识 放进里面的值都按照地址来处理
    在这里插入图片描述
    那么这里有两个问题就要被引出来了

    1 一个最小的单元究竟是多大?

    2 如何编译地址

    对于问题一 我们经过研究规定 一个最小的内存单元是一个字节

    对于问题二 我们在三十二位的系统中 假设有三十二根地址线 假设每一根地址线在寻址的时候产生高电平和低电平(1或者0)

    那么它们可能产生的数据就是

    0000 0000 0000 0000 0000 0000 0000

    0000 0000 0000 0000 0000 0000 0001

    1111 1111 1111 1111 1111 1111 1111 1110

    1111 1111 1111 1111 1111 1111 1111 1111

    一共2的32次方个地址

    总结

    那么讲到这里我们就应该明白了 在32位系统上 地址就是32位数 占用四个字节的大小

    在64位系统上 地址就是64位数 占用八个字节的大小

    二. 指针和指针类型

    我们都知道变量有不同的类型

    整型变量

    字符变量

    浮点型变量

    那么指针是否有不同的类型呢?(其实如果阅读过前面的初始指针博客这里就已经可以有答案了)

    这里首先先给出肯定的回答 有的

    我们存放那个类型数据的地址就要使用什么类型的指针

    举个例子 我们要存放int 类型数据的地址 就要使用int * p来存放

    char类型的数据的地址就要使用char * p来存放

    那么指针类型的意义是什么呢?

    让我们带着这个疑问 走进下面的章节

    1. 指针±整数

    举个例子

    在这里插入图片描述

    总结: 从这里我们就能看出来 指针的类型决定了指针向前或者向后走一步有多大的距离

    2. 指针的解引用

    int main()
    {
    	int n = 0;
    	int* p = &n;
    	char* pc = &n;
    	*p = 10;
    	*pc = 10;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    打出上面的一段代码 让我们进入调试模式看看

    在这里插入图片描述

    我们可以发现 它们修改的内容也不一样 这样我们就可以知道

    **指针的类型决定了 对于指针进行解引用时能有多大的权限 **

    综上
    1 指针的类型决定了指针向前或者向后走一步有多大的距离
    2 指针的类型决定了 对于指针进行解引用时能有多大的权限

    三. 野指针

    概念: 野指针就是指针指向的位置是不可知的

    1. 成因

    1 指针未初始化

    int main()
    {
    	int* p;//  局部变量指针未初始化 默认为随机值 
    	*p = 20;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里有个注意的点 指针在使用前初始化就好了

    2 指针越界访问

    int main()
    {
    	int arr[10] = { 0 };
    	int* p = arr;
    	int i = 0;
    	for ( i = 0; i <= 11; i++)
    	{
    		// 当指针指向的范围超出数组arr的范围时 p就是野指针
    		*(p++) = 1;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3 指针指向的空间释放

    int test()
    {
    	int p = 20;
    	return &p;
    }
    
    
    
    int main()
    {
    	int* p = test();
    	// 这里的p就是一个野指针 因为前面向内存申请的空间已经释放了 
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.如何规避

    其实这都是一些套话了 但是还是讲一下吧 大家使用指针的时候注意就好

    1 指针初始化
    2 小心指针越界
    3 指针指向的空间释放 及时防止NULL
    4 避免返回局部变量的地址
    5 指针使用前检查有效性

    
    int main()
    {
    	int* p = NULL;
    	int a = 10;
    	p = &a;
    	if (p!=NULL)
    	{
    		*p = 20;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    四. 指针运算

    1. 指针+ - 整数

    #define N_VALUES 5
    int values[N_VALUES];
    int* vp;//这里其实和指针为初始化不一样 只要指针才使用前初始化就可以了
    for ( vp = &values[0]; vp < &values[N_VALUES]; )
    {
    	*vp++ = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2. 指针 - 指针

    先说定义

    **指针加减指针得到的是元素的个数 可以是一个负数 **

    在这里插入图片描述
    比如这样子

    3. 指针的关系运算

    #define N_VALUES 5
    int values[N_VALUES];
    int* vp;//这里其实和指针为初始化不一样 只要指针才使用前初始化就可以了
    for ( vp = &values[0]; vp < &values[N_VALUES]; )
    {
    	*vp++ = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    还是这样子 和1中的指针±整数的代码意义

    五. 指针和数组

    首先我们来看以下代码

    int main()
    {
    	int arr[10] = { 0 };
    	printf("%p\n", &arr);
    	printf("%p\n", &arr[0]);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    产生的结果如下

    在这里插入图片描述

    数组名表示的是数组首元素的地址

    所以 这样子写代码就是可行的

    int main()
    {
    	int arr[10] = { 0 };
    	int* p = arr; 
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    既然将数组名当成地址存放到一个指针中 我们使用指针来访问一个数组就成为可能

    int main()
    {
    	int arr[10] = { 0 };
    	int* p = arr; 
    	int sz = sizeof(arr) / sizeof(arr[0]);
    	int i = 0;
    	for ( i = 0; i < sz; i++)
    	{
    		printf("%d\n", *(p + i));
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这里我们尝试使用指针数组来模拟一个二维数组的实现

    int main()
    {
    	int arr1[5] = { 1,2,3,4,5 };
    	int arr2[5] = { 1,2,3,4,5 };
    	int arr3[5] = { 1,2,3,4,5 };
    	int arr4[5] = { 1,2,3,4,5 };
    	int* p[4] = { arr1,arr2,arr3,arr4 };
    	int sz = sizeof(arr1) / sizeof(arr1[0]);
    	int i = 0;
    	for ( i = 0; i < 4; i++)
    	{
    		int j = 0;
    		for ( j = 0; j < sz; j++)
    		{
    			printf("%d ", p[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    实现代码如上

    简单介绍下原理

    使用指针数组创建一个数组 里面储存着每个数组的首地址

    然后通过找到这个数组中的元素找到每个数组

    再通过这个数组找到里面的元素

    六. 二级指针

    int a = 10;
    int* pa = &a;
    int** ppa = &pa;
    
    • 1
    • 2
    • 3

    其中pa是一级指针

    ppa是二级指针

    下面我来带大家解读下 int ** ppa的含义

    在这里插入图片描述

    所以说*(*ppa)== *pa ==a

    以上就是本篇博客的全部内容啦 由于博主才疏学浅 所以难免会出现纰漏 希望大佬们看到错误之后能够

    不吝赐教 在评论区或者私信指正 博主一定及时修正

    那么大家下期再见咯

  • 相关阅读:
    学信息系统项目管理师第4版系列30_信息系统管理
    Zephyr-7B论文解析及全量训练、Lora训练
    Doris部署 FS_Broker
    基础:JavaScript的怪癖之一:提升(Hoisting)
    基于JavaSwing开发餐厅点餐系统(购物,购物车,订单) 课程设计 大作业源码 毕业设计
    大模型时代下的自动驾驶研发测试工具链-SimCycle
    java数据结构与算法刷题-----LeetCode1854:人口最多的年份
    IB数学AA/AI应该如何选择?IB数学AA HL有多难?
    Brachistochrone:使用变分法找到最快下降曲线
    【机器学习-西瓜书】-第3章-线性回归-学习笔记-下
  • 原文地址:https://blog.csdn.net/meihaoshy/article/details/126805280