当前位置: 首页 > news >正文

C语言 —— 指针

目录

1. 指针是什么?

2. 指针和指针类型的关系

2.1 指针的解引用

2.2 指针+-整数

3. 野指针

3.1 野指针成因

1. 指针未初始化

2. 指针越界访问

3. 指针指向的空间释放

3.2 如何规避野指针

4. 指针运算

4.1 指针+-整数

4.2 指针-指针

指针-指针的使用

4.3 指针的关系运算

5. 指针和数组

6. 二级指针

7. 指针数组


1. 指针是什么?

指针是什么?
指针理解的2个要点:
1. 指针是内存中一个最小单元的编号,也就是地址
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量

总结:指针就是地址,口语中说的指针通常指的是指针变量。


我们在初识C语言中知道, 内存是一块很大的空间, 这么大的内存空间如何管理呢?

其实我们是把内存切割成一个个的内存单元, 一个内存单元大小是1byte.

对于要点的理解:

  • 第一点

  • 第二点

当写下以下代码时:

int a = 10;//a是整型变量,占用4个字节的内存空间

意味着要在内存中找4个空间存放a.


指针=指针变量, 指针变量中存放地址, 通过这个地址可以找到一个内存单元.

总结:

  • 指针变量是用来存放地址的,地址是唯一标示一块地址空间的。
  • 指针的大小在32位平台是4个字节,在64位平台是8个字节。

注意下面所使用的环境是x86的环境, 也就是32位的环境. (如果改成x64就是64位的环境)

我们来看一下指针的大小.

int main()
{char* pc = NULL;short* ps = NULL;int* pi = NULL;double* pd = NULL;//sizeof 返回的值的类型是无符号整型  unsigned intprintf("%zu\n", sizeof(pc));printf("%zu\n", sizeof(ps));printf("%zu\n", sizeof(pi));printf("%zu\n", sizeof(pd));return 0;
}

执行结果:

可以看到, 不同类型指针的大小都是4个字节.

既然这样, 不管是创建什么类型的指针, 在32位平台是4个字节,在64位平台是8个字节, 那么为什么还要区分不同类型的指针出来? 而不是直接使用一个统一的指针类型?

C语言并没有使用统一的指针类型, 说明每一种类型的指针都是有意义的, 并不多余.

接下来我们来探讨指针类型的意义.

2. 指针和指针类型的关系

2.1 指针的解引用

我们来看这段代码的效果:

int a = 0x11223344;    
int* pa = &a;
*pa = 0;

通过调试可以看到:

如果把代码改为:

int a = 0x11223344;    
char* pc = (char*)&a;//a原本应该是int*, 而非要赋给char*, 此时进行强转
*pc = 0;

pc是否有能力存下a的地址? 有, pc也是指针变量, 在x86环境下的大小也为4个字节.

我们来调试查看:

所以可以看到, a的地址是可以存到pc中.

但是, 使用的时候会有差异, 即*pc.

注: 上图为重新调试的截图, 所以会和前面的图有地址差异.

可以看到, *pc所修改的内容只有一个字节, 因为pc的类型是char*指针, 所以解引用时只访问了一个字节.

而前面使用int*pc是访问了4个字节.


综上, 我们有以下结论.

指针类型决定了指针在被解引用的时候访问几个字节
如果是int*的指针,解引用访问4个字节
如果是char*的指针,解引用访问1个字节
(还可以推广到其他类型)
这便是指针类型的第一个意义.再来看第二个意义.

2.2 指针+-整数

int main()
{int a = 0x11223344;int*  pa = &a;char* pc = (char*)&a;printf("pa = %p\n", pa);printf("pa+1 = %p\n", pa+1);printf("pc = %p\n", pc);printf("pc+1 = %p\n", pc+1);return 0;
}

执行结果:

所以我们得出以下结论:

指针的类型决定了指针+-1操作的时候,跳过几个字节, 它决定了指针的步长.

3. 野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

3.1 野指针成因

1. 指针未初始化

int main()
{int* p;//p没有初始化,就意味着没有明确的指向//一个局部变量不初始化的话,放的是随机值:0xcccccccc*p = 10;//非法访问内存了,这里的p就是野指针return 0;
}

2. 指针越界访问

int main()
{int arr[10] = { 0 };int* p = arr;//&arr[0]int i = 0;for (i = 0; i <= 10; i++){//当指针指向的范围超出数组arr的范围时,p就是野指针*p = i;p++;}return 0;
}

3. 指针指向的空间释放

int* test()
{int a = 10;return &a;
}int main()
{int*p = test();printf("haha\n");printf("abcdef\n");if (p != NULL){printf("%d\n", *p);}return 0;
}

3.2 如何规避野指针

1. 明确的给指针初始化

2. 小心指针越界

3. 指针指向空间释放即使置NULL

4. 避免返回局部变量的地址

5. 指针使用之前检查有效性

4. 指针运算

  • 指针+- 整数
  • 指针-指针
  • 指针的关系运算

4.1 指针+-整数

#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{*vp++ = 0;
}

4.2 指针-指针

指针-指针得到的结果的绝对值是指针和指针之间元素的个数.

int arr[10] = { 0 };
printf("%d\n", &arr[0] - &arr[9]);//9

注意: 不是所有的指针都能相减, 指向同一块空间的2个指针才能相减.

下面写法是错误的:

int arr[10] = { 0 };
char ch[5] = {0};
printf("%d\n", &ch[0] - &arr[5]);//err

指针-指针的使用

使用指针-指针的方式求字符串长度.

显然的, 只需要知道第一个字符的地址和\0的地址就可以知道字符串长度, 两个指针相减即可.
#include <stdio.h>
#include <string.h>int my_strlen(char* str)
{char* start = str;while (*str != '\0'){str++;}return (str - start);
}int main()
{int len = my_strlen("abcdef");printf("%d\n", len);return 0;
}

4.3 指针的关系运算

#define N_VALUES 5
float values[N_VALUES];
float *vp;for(vp = &values[N_VALUES]; vp > &values[0];)
{*--vp = 0;
}

代码简化:

for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{*vp = 0;
}

实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。

标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

5. 指针和数组

我们知道:

数组:一组相同类型元素的集合
指针变量:是一个变量,存放的是地址
数组名表示的是数组首元素的地址(两种情况除外)
int main()
{int arr[10] = {0};//arr 是首元素的地址//&arr[0]int* p = arr;//我们可以通过指针来访问数组, 这就是两者的联系int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (i = 0; i < sz; i++){printf("%d ", *(p + i));}for (i = 0; i < sz; i++){printf("%p ----- %p\n", &arr[i], p + i);}return 0;
}

6. 二级指针

#include <stdio.h>int main()
{int a = 10;int* pa = &a;//pa是一个指针变量,一级指针变量//*pa = 20;printf("%d\n", a);//pa是变量, 它在内存中也会有自己的内存空间, 那么就能&pa.int** ppa = &pa;//ppa是一个二级指针变量**ppa = 20;return 0;
}
一级指针变量就是如果通过pa找a的话, 找一次就可以了.

二级指针变量是用来存放级指针变量的地址的.

7. 指针数组

指针数组是数组, 是存放指针的数组。

我们知道, 创建比较多的相同类型的变量可以使用数组, 那么假设对于这些变量都有对应的指针去存放它们的地址, 是否也能用类似的方式, 去创建一个类型都为指针的数组? 显然是可以的, 也就是说C语言是有这种语法存在的.

int a = 10;
int b = 20;
int c = 30;int* pa = &a;
int* pb = &b;
int* pc = &c;
int arr[10];int* parr[10] = {&a, &b, &c};
int i = 0;
for (i = 0; i < 3; i++)//0 1 2
{printf("%d ", *(parr[i]));
}

int arr1[4] = { 1,2,3,4 };
int arr2[4] = { 2,3,4,5 };
int arr3[4] = { 3,4,5,6 };int* parr[3] = {arr1, arr2, arr3};
int i = 0;
for (i = 0; i < 3; i++)
{int j = 0;for (j = 0; j < 4; j++){printf("%d ", parr[i][j]);}printf("\n");
}

相关文章:

C语言 —— 指针

目录 1. 指针是什么&#xff1f; 2. 指针和指针类型的关系 2.1 指针的解引用 2.2 指针-整数 3. 野指针 3.1 野指针成因 1. 指针未初始化 2. 指针越界访问 3. 指针指向的空间释放 3.2 如何规避野指针 4. 指针运算 4.1 指针-整数 4.2 指针-指针 指针-指针的使用 4.3 指针的关系运…...

淘宝店铺所有商品数据接口,淘宝整店所有商品数据接口,淘宝店铺商品接口,淘宝API接口

淘宝店铺所有商品数据接口可以通过淘宝开放平台获取。以下是具体步骤&#xff1a; 在开放平台注册成为开发者并创建一个应用&#xff0c;获取到所需的 App Key 和 App Secret 等信息。使用获取到的 App Key 和 App Secret 进行签名和认证&#xff0c;获取 Access Token。调用开…...

【Redis】Java客户端使用zset命令

zadd/zrange zcard zrem zscore zrank...

记录一个@Transaction注解引发的bug

记录一个Transactional(readOnly true)注解引发的bug 一、问题代码和报错 1-1 问题代码模拟 引发这个问题的三大要素分别是&#xff1a; 事务注解任意数据库操作数据库操作后执行耗时业务&#xff08;耗时超过数据库配置的超时时间&#xff09; //1.这里是问题的核心之一…...

解决docker使用pandarallel报错OSError: [Errno 28] No space left on device

参考&#xff1a;https://github.com/nalepae/pandarallel/issues/127 在使用pandarallel报错OSError: [Errno 28] No space left on device&#xff0c;根据上述issue发现确实默认使用的MEMORY_FS_ROOT为 /dev/shm&#xff0c;而在docker环境下这个目录大小只有64M&#xff0…...

Javascript自定义页面复制事件

Javascript自定义页面复制事件 – WhiteNights Site 2023年10月13日 文章访问量&#xff1a;90 标签&#xff1a;Javascript 监听copy事件以达到自定义页面复制功能的效果。 写者注 需要注意的是&#xff0c;浏览器的部分拓展插件&#xff08;如迅雷&#xff09;会导致本文…...

Nginx:反向代理(示意图+配置)

示意图&#xff1a; 反向代理 反向代理&#xff08;Reverse Proxy&#xff09;是代理服务器的一种&#xff0c;它代表服务器接收客户端的请求&#xff0c;并将这些请求转发到适当的服务器。当请求在后端服务器完成之后&#xff0c;反向代理搜集请求的响应并将其传输给客户端。…...

macbook笔记本电脑内存怎么清理才能干净流畅?

假如你还在为“你的系统内存不足”的提示所困扰&#xff0c;或者你的Mac电脑突然运行缓慢和卡顿&#xff0c;那么你一般需要认真了解一下macbook内存怎么清理了? MacBook是功能强大的电脑&#xff0c;这点毫无疑问&#xff0c;但是它仍旧会随着时间推移变得运行缓慢。值得庆幸…...

spark 与 mapreduce 对比

Spark 为什么比 MapReduce 快总结 首先澄清几个误区&#xff1a; 1&#xff09;两者都是基于内存计算的&#xff0c;任何计算框架都肯定是基于内存的&#xff0c;所以说网上所说的 Spark 是基于内存计算所以快&#xff0c;显然是错误的。 2&#xff09;DAG 计算模型减少的是磁…...

kafka 相关概念

1 kafka 生产者 kafka 用push的方式把消息推送到topic 每个topic下可以有多个分区&#xff0c; 可以用hash 也可以用轮询的方式指定分区 每个分区内部是可以保证顺序的&#xff0c;但是整体无法保证顺序&#xff0c;除非设置成一个topic只有一个分区。 kafka这种多分区的设置 带…...

Ubuntu下vscode配置OpenCV以及Libtorch

opencv安装 sudo apt-get updatesudo apt-get install libopencv-dev 该方式安装的版本可能比较旧。 测试代码 #include <opencv2/opencv.hpp>#include <iostream>int main() {cv::Mat image cv::imread("t.png");cv::imshow("Image", ima…...

关于共识算法Raft的常见误解

关于共识算法Raft的常见误解 Raft 共识算法最终一致性与线性一致性日志的覆盖与删除Remove节点时需要skip 总结参考文档 Raft 共识算法 最近翻了翻Raft相关的资料&#xff0c;同时也总结了日常工作的一些积累&#xff0c;就当做Raft技术笔记吧。 由于工作的关系&#xff0c;Ra…...

Python学习基础笔记七十——模块和库1

模块和库&#xff1a; 一个python代码文件就实现了功能。功能比较单一。 在企业中&#xff0c;项目开发的文件&#xff0c;可能有成百上千个。 不同的代码文件&#xff0c;实现了不同的功能模块&#xff0c;就像一块块积木一样。这些功能文件整合起来&#xff0c;实现一个完…...

SystemVerilog Assertions应用指南 第一章(1.28章节 内建的系统函数)

SVA提供了几个内建的函数来检查一些最常用的设计条件。 $onehot(expression)—检验表达式满足“one-hot”,换句话说,就是在任意给定的时钟沿,表达式只有一位为高。 $onehot0( expression)—检验表达式满足“ zero one-hot”&#xff0c;换句话说,就是在任意给定…...

正则表达式(自用)

正则表达式 符号概述 分类符号用法示例元字符^以 ***开头$以 ***结尾d匹配数字s匹配任意的空白符.匹配除换行符以外的任意字符w匹配字母或数字或下划线或汉字\转义重复限定符*次数&#xff0c;至少一次至少1次?0次 或者 1次{n}{n,}{n,m}重复n次&#xff1b;n活更多次&#x…...

大厂真题:【模拟】OPPO2023秋招提前批-小欧数组求和

题目描述与示例 题目描述 小欧拿到了一个数组&#xff0c;她有q次操作&#xff0c;每次操作修改一个元素。小欧希望每次修改后得到当前数组所有元素之和。你能帮帮她吗&#xff1f; 输入描述 第一行输入两个正整数n和q&#xff0c;代表数组的大小和操作次数。 第二行输入n…...

Python括号匹配问题

给定一个只包含小写字母的字符串&#xff0c;判断该字符串中的括号是否闭合&#xff0c;如果每个左括号都有对应的右括号&#xff0c;并且括号的嵌套顺序正确&#xff0c;那么括号就能正确闭合。 否则&#xff0c;括号不能正确闭合&#xff0c;字符串中括号仅限于 "("…...

微信小程序备案内容常见问题汇总

一、备案时间点 自2023年09月01日起,新的微信小程序,必须备案后才能上架; 在2024年03月31日前,所有小程序都必须完成备案; 于2024年04月01日起,对未备案小程序进行清退处理。 微信小程序备案系统已于9月4日上线。 二、备案流程 [找备案入口]–[填主体信息]–[填小程…...

无人机新手防炸飞行技巧

不要在室内飞行,容易撞墙。起飞前设置好避障和返航模式。使用模拟器熟练掌握操控。选择开阔环境目视起飞。使用低速档平稳飞行。合理使用避障功能,不要盲目依赖。使用九宫格避障法。留意电量,及时返航。极低电量时放弃强行返航。飞行后及时为电池充电保养。...

webrtc opus 音频编码支持SILK和CELT模式

SILK CELT是指将SILK编解码器和CELT编解码器结合在一起的混合音频编码方案。 SILK&#xff08;Super-wideband audio coding&#xff09;是一种低延迟的音频编解码器&#xff0c;用于实时的语音通信。它提供高质量的音频传输&#xff0c;并且适用于各种比特率和带宽条件。SILK…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分&#xff1a; 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

前端中slice和splic的区别

1. slice slice 用于从数组中提取一部分元素&#xff0c;返回一个新的数组。 特点&#xff1a; 不修改原数组&#xff1a;slice 不会改变原数组&#xff0c;而是返回一个新的数组。提取数组的部分&#xff1a;slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...