你是真的“C”——详解指针知识
你是真的“C”——详解指针知识😎
- 前言🙌
- 1、 指针是什么?🙌
- 2、指针和指针类型🙌
- 2 、1指针+-整数
- 2 、 2指针的解引用
- 3、 野指针🙌
- 3、 1野指针成因
- 3、 2如何规避野指针
- 4、指针运算🙌
- 4、1 指针+-整数
- 4、2 指针-指针
- 4、3 指针的关系运算
- 5、指针和数组🙌
- 6 、 二级指针🙌
- 7、指针数组🙌
- 总结撒花💞

😎博客昵称:博客小梦
😊最喜欢的座右铭:全神贯注的上吧!!!
😊作者简介:一名热爱C/C++,算法等技术、喜爱运动、热爱K歌、敢于追梦的小博主!
😘博主小留言:哈喽!😄各位CSDN的uu们,我是你的博客好友小梦,希望我的文章可以给您带来一定的帮助,话不多说,文章推上!欢迎大家在评论区唠嗑指正,觉得好的话别忘了一键三连哦!😘
前言🙌
哈喽各位友友们😊,我今天又学到了很多有趣的知识,现在迫不及待的想和大家分享一下!😘我仅已此文,和大家分享C语言中指针相关的知识点~ 都是精华内容,可不要错过哟!!!😍😍😍
1、 指针是什么?🙌
在学习指针之前,首先要知道指针是什么?,其实,指针理解起来可以概括为一下两个要点:
- 指针是内存中一个最小单元的编号,也就是地址
- 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
总结:指针就是地址,口语中说的指针通常指的是指针变量。 - 指针变量:我们可以通过&(取地址操作符)取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是指针变量 。
举个栗子辅助理解:
#include <stdio.h>
int main()
{int a = 10;//在内存中开辟一块空间int* p = &a;return 0;}
知识点分析:
- 这里我们对变量a,取出它的地址,可以使用&操作符。
- a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量
- 中,p就是一个之指针变量。
小结一下:
指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
那么,一个内存单元要分配多大的空间呢?又是怎么对这些内存进行编地址的呢?无数的先辈对此进行探讨分析,最终认为一个内存单位分配一个字节,并分配一个地址是比较合适的。对于32位的机器,,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0)。那么这里就有2的32次方个地址。同样的方法,那64位机器,如果给64根地址线,那能编址就有2的64次方的地址。
简单的概括来说:
在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以
一个指针变量的大小就应该是4个字节。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地
址。
总结:
- 指针变量是用来存放地址的,地址是唯一标示一个内存单元的。
- 指针的大小在32位平台是4个字节,在64位平台是8个字节
2、指针和指针类型🙌
我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?准确的说是有的。指针的定义方式是: type + * 。
举些栗子大家就知道啦:
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。
那指针类型的意义是什么?
2 、1指针±整数
这里通过画图的方式帮助大家辅助理解正指针加减运算的规律:
总结:指针的类型决定了指针向前或者向后走一步有多大(距离)
2 、 2指针的解引用
那么指针的解引用和指针的类型有没有什么关联呢?这里还是通过画图的方法帮助大家理解:
总结:
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。
3、 野指针🙌
按照教科书上的解释概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。按照我的理解,野指针其实就像是一条没有被绳子拴住的野狗,到处乱串,当使用它时(解引用),就会有危险。
3、 1野指针成因
对于野指针存在的原因分析,比较常见的可以归纳为以下几个:
- 指针未初始化
- 指针越界访问
- 指针指向的空间释放
指针未初始化导致野指针,这里举个栗子分析以下:
#include <stdio.h>
int main()
{ int *p;*p = 20;return 0;
}
小结:局部变量指针未初始化,默认为随机值
指针越界访问造成野指针,这里举一个简单的栗子:
#include <stdio.h>
int main()
{int arr[10] = {0};int *p = arr;int i = 0;for(i=0; i<=11; i++){*(p++) = i;}return 0;
}
小结一下:
这个数组一共只有10个元素,循环却访问到了第11个元素的位置。 当指针指向的范围超出数组arr的范围时,p就是野指针。
指针指向的空间释放,当再次访问原空间时,造成野指针。
int * test()
{int a = 10;return &a;
}int main()
{int* p = test();printf("%d", *p);return 0;
}
小结一下:
变量a是test内的局部变量,当运行的时候出了这个函数时,就会被销毁掉,这里却返回a变量的地址赋值给指针p,p去解引用操作不属于程序的空间,则造成了野指针的问题。
3、 2如何规避野指针
- 指针初始化
- 小心指针越界
- 指针指向空间释放,及时置NULL
- 避免返回局部变量的地址
- 指针使用之前检查有效性
4、指针运算🙌
4、1 指针±整数
上面已经探讨了这个知识点,这里就不做讲解了。
4、2 指针-指针
这里举一个模拟实现strlen函数的代码:
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* p)
{assert(p);char* str = p;while (*p != '\0'){p++;}return p - str;
}int main()
{char arr[] = "Hello bit!";printf("%d", my_strlen(arr));return 0;
}
这里的返回值就是指针 - 指针的典型体现啦。指针减去指针,得到的是两个指针之间元素的个数。
4、3 指针的关系运算
C语言的语法标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
5、指针和数组🙌
指针和数组是不是同一个东西?其实不是的。虽然我们常说数组名是首元素的地址,好像和指针有紧密的关系,但指针和数组是完全不一样的两个东西。
可见数组名和数组首元素的地址是一样的。
结论:数组名表示的是数组首元素的地址
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个数组中的元素就成为可能。所以 p+i 其实计算的是数组 arr 下标为i的地址。
那我们就可以直接通过指针来访问数组,举个栗子:
#include <stdio.h>
int main()
{int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };int* p = arr; int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (i = 0; i < sz; i++){printf("%d ", *(p + i));}return 0;
}
6 、 二级指针🙌
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?其实,还是存放到指针变量中。
这里举个栗子辅助大家理解一下:
#include <stdio.h>
int main()
{int a = 10;//a是要在内存中申请4个字节的空间的//一级指针int* pa = &a;// pa是指针变量,用来存放地址,也得向内存申请,申请4/8,存放变量a的地址//二级指针int** ppa = &pa;//ppa是指针变量,用来存放地址,也得向内存申请,申请4/8,存放一级指针地址int** * pppa = &ppa;//pppa是指针变量,用来存放地址,也得向内存申请,申请4/8,存放二级指针地址printf("%d\n", **ppa);return 0;
}
如图所示:
对于二级指针的运算有:
- *ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa .
- **ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .
7、指针数组🙌
指针数组,顾名思义就是数组。指针数组,是用来存放指针的数组。数组我们已经知道整形数组,字符数组。那指针数组又是长什么样的呢?
int* arr3[5];
上述就是一个指针数组,arr3是数组名,一共有5个元素,每个元素的类型时int*。
接下来举几个栗子辅助大家理解:
可以利用指针数组来模拟二维数组的打印,但是这里有个区别是,二维数组的每一行元素在内存中是连续存放的,这里就不一定。
#include <stdio.h>
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };int* ptr[] = {arr1, arr2, arr3};int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){printf("%d ", ptr[i][j]);}printf("\n");}return 0;
}
程序运行结果图:
上述知识的一个综合运用栗子:
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int i = 0;for (i = 0; i < 10; i++){printf("%d ", i[arr]);//i[arr] -- *(i+arr)//arr[i] -- *(arr+i)}//int* p = arr;//test(arr, 10);*(arr+i) -- *(p+i) -- arr[i]arr[i] --> *(arr+i) --> *(i+arr) -- i[arr]//for (i = 0; i < 10; i++)//{// printf("%p = %p\n", &arr[i], p+i);//}return 0;
}int main()
{int arr[3][5];//arr[i][j]//(*(arr+i))[j]//*(*(arr+i)+j)return 0;
}
总结撒花💞
本篇文章旨在分享C语言详解指针的相关知识点。希望大家通过阅读此文有所收获!😘如果我写的有什么不好之处,请在文章下方给出你宝贵的意见😊。如果觉得我写的好的话请点个赞赞和关注哦~😘😘😘
相关文章:

你是真的“C”——详解指针知识
你是真的“C”——详解指针知识😎前言🙌1、 指针是什么?🙌2、指针和指针类型🙌2 、1指针-整数2 、 2指针的解引用3、 野指针🙌3、 1野指针成因3、 2如何规避野指针4、指针运算🙌4、1 指针-整数4…...
React/ReactNative面试攻略(偏RN)
useMemo Vs useCallBackuseMemo第一个参数返回的是值,useCallBack返回的是函数useMemo和useCallBack第二个参数都是依赖项useMemo避免组件非依赖项更新时参数的计算useCallback避免父组件非依赖项更新时造成子组件的重复渲染React.memo 使用场景纯prue组件ÿ…...

Leetcode-每日一题1234. 替换子串得到平衡字符串(滑动窗口 + 哈希表)
题目链接:https://leetcode.cn/problems/replace-the-substring-for-balanced-string/description/ 思路 题目意思 这题意思是一个只含有[Q, W, E, R] 四个字符的字符串s且长度一定是 4的倍数, 需要你通过替换子串,使他变成一个「平衡字符…...
linux命令小结-查看日志命令
一、查看日志命令cat查看文件 vi编辑后可以用cat进行查看保存是否成功1)cat -n alert_monitor.log2)cat -n alert_monitor.log | tail -n 100 | head -n 20 //查询100行之后的日志,且在100行之后里再查前20条日志more 可以通过回撤键翻页mor…...

Java知识点细节简易汇总——(8)枚举和注解+Java面向对象高级作业
一、枚举 自定义枚举 当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类, 而且是一个 final 类[如何证明],老师使用 javap 工具来演示传统的 public static final Season2 SPRING new Season2(“春天”, “温暖”); 简化成 SPRING(“春天”, “温暖”)…...
快速上手JVM- Java Virtual Machine面试不用慌
一、JVM的定义 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 引入Java语言虚拟机后,J…...

安警官的IP地址是怎样定位到莽村附近的?
要说最近大火的电视剧非《狂飙》莫属。电视剧《狂飙》自开播以来,一举超过《三体》《去有风的地方》等先播电视剧,收视率一路“狂飙”,牢牢占据近期的收视冠军。 在剧中,张译扮演一名坚持公平、正义与理想的人民警察“安欣”&…...

STL中重要容器vector总结
你要尽全力保护你的梦想。那些嘲笑你的人,他们必定会失败,他们想把你变成和他们一样的人。如果你有梦想的话,就要努力去实现。 ——《当幸福来敲门》引言:C中STL里面的容器用法很巧妙,可以解决很多复杂的模型ÿ…...

11_会话原理与实现流程
1、会话的基本知识 # 会话## 1.会话是什么?客户端与服务器之间的对话交流## 2.为什么需要会话?-http 协议是无状态的(六亲不认)-同一用户多次访问同一网站,对网站来说,每次都是全新的-网站不能识别用户身份…...

Java测试——junit的使用(2)
排序 我们同一个类下的多个用例的执行顺序是不确定的,如果需要指定固定的顺序,则需要在类上加这个注解 TestMethodOrder(MethodOrderer.OrderAnnotation.class)然后在想要第一个执行的用例上加上 Order(1)第二个执行的用例上注解: Order(…...

数据库(六): MySQL的主从复制和读写分离
文章目录一、为什么要使用主从复制和读写分离二、主从复制的原理三、如何实现主从复制3.1 master配置3.2 slave配置3.3 测试主从复制四、读写分离五、缺点一、为什么要使用主从复制和读写分离 注意到主从复制和读写分离一般是一起使用的。目的很简单,就是提高数据库…...

编程思想-0x00架构
产生架构的原因? 1、代码均摊 将不同的代码进行分块,然后简历联系,低耦合、高内聚; 原则上:合理的App架构应该是合理分配每个类、结构体、方法、变量的存在都应该遵循单一职责的原则 2、便于测试 测试确保代码质量&…...

QCon演讲实录(上):多云环境下应用管理与交付实践
作者:阿里云大数据基础工程技术团队——郭耀星 大家上午好!我是来自阿里云大数据基础工程技术团队的郭耀星,花名雪尧。今天我很高兴能够来到QCon,与大家分享我的经验和心得。在当前的多云环境中,作为运维支撑团队&…...

async thunk 解决 API 调用的依赖问题
async thunk 解决 API 调用的依赖问题 一句话节省看下面一堆内容的时间就是: async thunk 中可以使用 async/await 锁住其他的 action 操作 一般 API 之间存在三种情况: A 和 B 之间没有依赖关系 这样的情况下,A 和 B 可以各调用各的&#x…...

java 黑马头条 day3 实名认证分布式事务问题 seata
1 完善实名认证功能 1.1 实名认证分布式事务问题 1.1.1 问题分析 在昨天的实名认证代码中,审核完毕后添加 id5的演示异常,重新使用postman进行测试, 会发现 出现异常后 本地方法因为有 Transactional注解 对ap_user ap_user_realname的操作会回滚 而…...

测试开发之Django实战示例 第七章 创建电商网站
第七章 创建电商网站在上一章里,创建了用户关注系统和行为流应用,还学习了使用Django的信号功能与使用Redis数据库存储图片浏览次数和排名。这一章将学习如何创建一个基础的电商网站。本章将学习创建商品品类目录,通过session实现购物车功能。…...

【C++之容器篇】造轮子:list的模拟实现与使用
目录前言一、关于list1. 简介2. 成员类型二、默认成员函数1. 构造函数1. list()2. list(size_t n,const T& val T())和list(InputIterator first,InputIterator last)2. 拷贝构造函数3. 析构函数4. 赋值运算符重载函数三、迭代器1. 普通对象的正向迭代器2. const对象的正向…...
自动驾驶:决策规划算法岗位面经分享
本专栏分享 计算机小伙伴秋招春招找工作的面试经验和面试的详情知识点 专栏首页: 主要分享计算机算法类在面试互联网公司时候一些真实的经验 人情况是985本硕,硕士研究方向是强化学习在移动机器人路径规划中的应用,一段自动驾驶中小厂实习经历,秋招找的大都是机器人和自动驾…...

2.7、进程调度的时机、切换与过程、方式
1、进程调度的时机 进程调度\color{red}进程调度进程调度(低级调度),就是按照某种算法从就绪队列中选择一个进程为其分配处理机 进程在操作系统内核程序临界区\color{red}操作系统内核程序临界区操作系统内核程序临界区中不能\color{red}不能…...
工程管理系统源码+项目说明+功能描述+前后端分离 + 二次开发
工程项目各模块及其功能点清单 一、系统管理 1、数据字典:实现对数据字典标签的增删改查操作 2、编码管理:实现对系统编码的增删改查操作 3、用户管理:管理和查看用户角色 4、菜单管理:实现对系统菜单的增删改查操…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...

Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...