【C语言】善于利用指针(一)

💗个人主页💗

⭐个人专栏——C语言初步学习⭐

💫点击关注🤩一起学习C语言💯💫


目录

导读:

1. 什么是指针

1.1 概念

1.2 图解

 1.3 示例

2. 指针和指针类型

2.1 指针的定义

2.2 指针的解引用

3. 野指针

3.1 野指针成因

3.2 如何规避野指针

4. 指针运算

4.1 指针+-整数

 ​编辑

 4.2 指针-指针

5. 指针和数组

5.1 数组指针

5.2 数组元素的访问

6. 二级指针

博主有话说:


导读:

经过前面的学习,我们已经了解了分支结构、循环结构、数组和函数的使用

还包括动态内存分配和柔性数组

 今天我们来学习指针的第一部分,主要学习指针的类型和基本用法

1. 什么是指针

指针是C语言中的一个重要概念,也是C语言的一个重要特色。正确而灵活地运用它,可以使程序简洁、紧凑、高效。每一个学习和使用C语言的人,都应该深入的学习和掌握指针。可以说,不掌握指针就是没有掌握C语言的精华。

1.1 概念

指针理解的2个要点:

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

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

1.2 图解

可以理解为: 

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

 1.3 示例

int main()
{int a = 10;//在内存中开辟一块空间int* p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。//a变量占用4个字节的空间,//这里是将a的4个字节的第一个字节的地址存放在p变量中,//p就是一个之指针变量。return 0;
}

我们来进入调试看一看

我们发现,p存的就是a的地址,对p解引用得到的就是该地址所指向的内存空间的内容

总结:

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

2. 指针和指针类型

2.1 指针的定义

我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?

准确的说:有的。

int num = 10;p = #

要将&num(num的地址)保存到p中,我们知道p就是一个指针变量,那它的类型是怎样的呢? 我们给指针变量相应的类型。

char  *pc = NULL;

int   *pi = NULL;

short *ps = NULL;

long  *pl = NULL;

float *pf = NULL;

double *pd = NULL; ‘

指针的定义方式是:

type + *

  • int 表示指向整型变量的指针
  • double* 表示指向双精度浮点型变量的指针
  • char* 表示指向字符型变量的指针

 需要注意的是,指针类型并不决定指针变量所指向内存地址的类型,而是决定了指针变量对指向的内存地址所存储的值的解释方式。

例如:

一个int类型的指针变量可以指向一个double类型的变量,但这样会导致解释的错误。

因此,指针类型的指定应该与指针变量所指向的变量类型相同,以确保正确的解释和使用。

2.2 指针的解引用

指针的解引用是指通过指针变量访问其所指向的变量的值。

在C++中,可以使用星号(*)来解引用指针变量,例如:

int main()
{int x = 10;int* ptr = &x;   // ptr指向x的地址printf("%d\n", *ptr); //输出10*ptr = 20;       // 将ptr指向的值改为20printf("%d\n", *ptr); // 输出20return 0;
}

 

在上述代码中,ptr指向变量x的地址,可以使用星号()来解引用ptr,访问x的值。

在第一次输出时,输出了x的初始值10,然后使用星号()将ptr解引用,输出了x的值。

在第二次输出时,输出的是x被修改后的值20。

3. 野指针

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

3.1 野指针成因

1. 指针未初始化

对未初始化的指针进行解引用是一种未定义的行为,会导致程序崩溃或产生随机结果,因此在使用指针前一定要确保其被正确初始化。

int main()
{int* p;//局部变量指针未初始化,默认为随机值*p = 20;printf("%d\n", *p);return 0;
}

 

并不能成功运行。

2. 指针越界访问 

指针越界访问是指程序试图访问超出指针所指向的内存空间范围的地址,这也是一种常见的编程错误。

指针越界访问可能会导致程序崩溃、数据被破坏、安全漏洞等问题。这种错误很难检测和调试,因为错误不一定会立即引起程序崩溃,而且错误的结果也不一定与越界访问的代码行直接相关。

 

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

虽然运行成功,但是依旧是错误的

3. 指针指向的空间释放

int main() 
{int* p = (int*)malloc(sizeof(int)); // 分配一个 int 类型的内存块,返回指向该内存块的指针if (p == NULL) {printf("分配内存失败!\n");return -1;}*p = 10; // 给指针所指向的内存块赋值printf("p 指向的值为:%d\n", *p);free(p); // 释放指针所指向的内存块printf("p 指向的值为:%d\n", *p); // 这里会出现错误,因为指针所指向的内存块已被释放return 0;
}

3.2 如何规避野指针

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

例如:

int main()
{int* p = NULL;//....int a = 10;p = &a;if (p != NULL){*p = 20;}return 0;
}

4. 指针运算

指针+- 整数

指针-指针

指针的关系运算

4.1 指针+-整数

int main()
{int n = 10;char* pc = (char*)&n;//强转char*int* pi = &n;printf("%p\n", &n);printf("%p\n", pc);printf("%p\n", pc + 1);printf("%p\n", pi);printf("%p\n", pi + 1);return  0;
}

 

 我们可以看到,都是加1,但是结果却不一样,而这就是与指针的类型有关了

一个int类型占4个字节,int + 1自然就是加四个字节

 一个char类型占一个字节,char + 1也是加一个字节

总结:

指针的类型决定了指针向前或者向后走一步有多大(距离)。

 4.2 指针-指针

int main()
{int arr[5] = { 1, 2, 3, 4, 5 };int* p1 = &arr[1]; // 指向 arr[1] 的指针int* p2 = &arr[4]; // 指向 arr[4] 的指针printf("p2 - p1 = %ld\n", p2 - p1); // 输出 p1 和 p2 之间的距离return 0;
}

5. 指针和数组

5.1 数组指针

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

 

我们发现打印出的地址是一样的,数组名表示的是数组首元素的地址

当然也有例外,感兴趣的小伙伴可以看sizeof与数组

所以我们可以这样定义一个数组指针

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址

5.2 数组元素的访问

引用数组元素可以用下标法,也可以用指针法

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("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p + i);}return 0;
}

所以我们就可以如下进行访问:

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. 二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?

这就是二级指针

int main() 
{int num = 10;int* p = &num;int** pp = &p;return 0;
}

对于二级指针的运算有:

  • *pp 通过对pp中的地址进行解引用,这样找到的是p,*pp其实访问的就是 p

博主有话说:

今天有关指针的初步学习就到这里,更多关于指针的学习关注博主,掌握最新消息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/95605.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【图像处理GIU】图像分割(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

c++【3】 常量、指针、指针变量、变量指针

常量是固定值&#xff0c;在程序执行期间不会改变。这些固定的值&#xff0c;又叫做字面量。 常量可以是任何的基本数据类型&#xff0c;可分为整型数字、浮点数字、字符、字符串和布尔值。 常量就像是常规的变量&#xff0c;只不过常量的值在定义后不能进行修改。 1.指针应用…

想要精通算法和SQL的成长之路 - 并查集的运用和案例(省份数量)

想要精通算法和SQL的成长之路 - 并查集的运用 前言一. 并查集的使用和模板1.1 初始化1.2 find 查找函数1.3 union 合并集合1.4 connected 判断相连性1.5 完整代码 二. 运用案例 - 省份数量 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 并查集的使用和模板 先说一下并查集…

源码分享-M3U8数据流ts的AES-128解密并合并---GoLang实现

之前使用C语言实现了一次&#xff0c;见M3U8数据流ts的AES-128解密并合并。 学习了Go语言后&#xff0c;又用Go重新实现了一遍。源码如下&#xff0c;无第三方库依赖。 package mainimport ("crypto/aes""crypto/cipher""encoding/binary"&quo…

工厂管理软件中的PLM管理

第一部分&#xff1a;介绍PLM管理的定义和背景 1.1 定义&#xff1a;PLM管理是指通过工厂管理软件实现对产品生命周期各个阶段的全面管理和协同合作&#xff0c;包括产品设计、工艺规划、生产制造、质量控制、供应链管理等环节。 1.2 背景&#xff1a;随着市场竞争的加剧和消…

Vue组件通信应用实践总结

【1】 组件通信的5种方式 props vue的自定义事件 pubsub第三方库 slot vuex① props 父子组件间通信的基本方式 属性值的2大类型: 一般: 父组件-->子组件函数: 子组件-->父组件 隔层组件间传递: 必须逐层传递(麻烦) 兄弟组件间: 必须借助父组件(麻烦)② vue自定义事件 …

【ORM】浅聊C#和Java的ORM底层框架

给自己一个目标&#xff0c;然后坚持一段时间&#xff0c;总会有收获和感悟&#xff01; 国庆假期马上结束&#xff0c;闲暇时间&#xff0c;突然对Ado.Net这个词的由来感兴趣&#xff0c;然后就一顿复习了一遍&#xff0c;顺便也了解了下java关于ORM框架的底层是什么&#xff…

Gmail 将停止支持基本 HTML 视图

根据 Google 支持文档的更新内容&#xff0c;Gmail 将从明年 1 月起停止支持基本 HTML 视图。 ▲ Gmai 基本 HTML 视图界面 目前网页版 Gmail 提供两个界面&#xff1a;基本 HTML 视图和标准视图。停止支持基本 HTML 视图后&#xff0c;当前打开经典模式的基本 HTML 视图模式 …

一文解释mapState的来龙去脉

mapState Vuex 提供的辅助函数之一&#xff0c;将 store 中的状态映射到组件的计算属性中&#xff0c;使得在组件中可以轻松地访问 Vuex store 中的状态值 MapState(映射状态) 在我们的 Count.vue 组件中&#xff0c;可以使用 mapState 来更简洁地获取 count 的状态值 首先&…

python读取vivo手机截图,将满屏图片文件移动别的路径

问题之初 python读取vivo手机截图&#xff0c; 将满屏图片文件移动别的路径好多这样的图片&#xff0c;占用手机大量的内存&#xff0c;食之无味弃之可惜&#xff01;那么会复制粘贴&#x1f440;代码的我们我们今天就把这些图片筛选清理掉。 这段代码 原有逻辑的基础上&…

基于知识蒸馏的两阶段去雨去雪去雾模型学习记录(二)之知识收集阶段

前面学习了模型的构建与训练过程&#xff0c;然而在实验过程中&#xff0c;博主依旧对数据集与模型之间的关系有些疑惑&#xff0c;首先是论文说这是一个混合数据集&#xff0c;但事实上博主在实验时是将三个数据集分开的&#xff0c;那么在数据读取时是如何混合的呢&#xff0…

林沛满-Wireshark的提示

本文整理自&#xff1a;《Wireshark网络分析的艺术 第1版》 作者&#xff1a;林沛满 著 出版时间&#xff1a;2016-02 最近有不少同事开始学习 Wireshark&#xff0c;他们遇到的第一个困难就是理解不了主界面上的提示信息&#xff0c;于是跑来问我。问的人多了&#xff0c;我也…

如何一步步优化负载均衡策略

发展到一定阶段后&#xff0c;Web 应用程序就会增长到单服务器部署无法承受的地步。这时候企业要么提升可用性&#xff0c;要么提升可扩展性&#xff0c;甚至两者兼而有之。为此&#xff0c;他们会将应用程序部署在多台服务器上&#xff0c;并在服务器之前使用负载均衡器来分配…

第10章 MySQL(二)

10.11 请你说下你对ACID的理解 难度:★ 重点:★★ 白话解析 前面的题目搞明白了MySQL的原理、架构和索引,那接下来,我们捋一捋SQL在执行过程中的最核心的问题了——事务问题。 先搞明白事务的4个特性。 参考答案 1、A(Atomicity):原子性,就是一堆的SQL操作要么全部…

华为云云耀云服务器L实例评测|SpringCloud相关组件——nacos和sentinel的安装和配置 运行内存情况 服务器被非法登陆尝试的解决

前言 最近华为云云耀云服务器L实例上新&#xff0c;也搞了一台来玩&#xff0c;期间遇到各种问题&#xff0c;在解决问题的过程中学到不少和运维相关的知识。 本篇博客介绍SpringCloud相关组件——nacos和sentinel的安装和配置&#xff0c;并分析了运行内存情况&#xff0c;此…

数据在内存中的存储(1)

文章目录 目录1. 数据类型介绍1.1 类型的基本归类 2. 整形在内存中的存储2.1 原码、反码、补码2.2 大小端介绍2.3 练习 附&#xff1a; 目录 数据类型介绍整形在内存中的存储大小端字节序介绍及判断浮点型在内存中的存储 1. 数据类型介绍 前面我们已经学习了基本的内置类型以…

【数据结构】数据结构基础概念

系列文章目录 第一章&#xff1a;【数据结构】数据结构基础概念 文章目录 系列文章目录前言简介名词解释数据数据元素数据项数据对象数据结构数据类型抽象抽象数据类型算法算法设计要求 总结 前言 数据结构是软件编程的基础&#xff0c;是程序员的基本功。 简介 数据结构是一…

Ubuntu20配置Mysql常用操作

文章目录 版权声明ubuntu更换软件源Ubuntu设置静态ipUbuntu防火墙ubuntu安装ssh服务Ubuntu安装vmtoolsUbuntu安装mysql5.7Ubuntu安装mysql8.0Ubuntu卸载mysql 版权声明 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明&#xff0c;所有版权属于黑马程…

12、建立健全人员培训体系

9、大小屏分离与精细化审核 10、质量审核的设立与合并 11、视频分类建议 内容仓为公司其他部门输送了许多人才&#xff0c;既包括有潜力的主管&#xff0c;也有表现突出或者具备某些特殊能力的员工&#xff0c;从内容仓走出的同事&#xff0c;有些已经成为公司重要业务某个方…

回归预测 | MATLAB实现PSO-SVR粒子群优化支持向量机回归多输入单输出预测

回归预测 | MATLAB实现PSO-SVR粒子群优化支持向量机回归多输入单输出预测 目录 回归预测 | MATLAB实现PSO-SVR粒子群优化支持向量机回归多输入单输出预测预测效果基本介绍模型描述程序设计预测效果 <