【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…

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

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

工厂管理软件中的PLM管理

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

【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;并在服务器之前使用负载均衡器来分配…

华为云云耀云服务器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. 数据类型介绍 前面我们已经学习了基本的内置类型以…

Ubuntu20配置Mysql常用操作

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

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

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

lv7 嵌入式开发-网络编程开发 11 TCP管理与UDP协议

目录 1 TCP管理 1.1 三次握手 1.2 四次挥手 1.3 保活计时器 2 wireshark安装及实验 3.1 icmp协议抓包演示 3.2 tcp协议抓包演示 3 UDP协议 3.1 UDP 的主要特点&#xff1a; 4 练习 1 TCP管理 1.1 三次握手 TCP 建立连接的过程叫做握手。 采用三报文握手&#xff1…

Fiddler抓取手机https包的步骤

做接口测试时&#xff0c;有时我们需要使用fiddler进行抓包分析&#xff0c;那么如何抓取https包。主要分为以下七步&#xff1a; 1.设置fiddler选项&#xff1a;Tools->Options,按如下图勾选 2.下载并安装Fiddler证书生成器 下载地址&#xff1a;http://www.telerik.com/…

C/C++——内存管理

1.为什么存在动态内存分配 灵活性 静态内存分配是在编译时确定的&#xff0c;程序执行过程中无法改变所分配的内存大小&#xff1b;动态内存分配可以根本程序的运行环境来动态分配和释放空间&#xff0c;提供了更大的灵活性 动态数据结构 有些数据结构的大小和结构在编译时…

[计算机入门] Windows附件程序介绍(工具类)

3.14 Windows附件程序介绍(工具类) 3.14.1 计算器 Windows系统中的计算器是一个内置的应用程序&#xff0c;提供了基本的数学计算功能。它被设计为一个方便、易于使用的工具&#xff0c;可以满足用户日常生活和工作中的基本计算需求。 以下是计算器程序的主要功能&#xff1a…

【算法基础】基础算法(二)--(高精度、前缀和与差分)

一、高精度 当一个数很大&#xff0c;大到 int 无法存下时&#xff0c;我们可以考虑用数组来进行存储&#xff0c;即数组中一个位置存放一位数。 但是对于数组而言&#xff0c;一个数顺序存入数组后&#xff0c;对其相加减是很简单的。但是当需要进位时&#xff0c;还是很麻烦的…

华为云云耀云服务器L实例评测|部署个人音乐流媒体服务器 navidrome

华为云云耀云服务器L实例评测&#xff5c;部署个人音乐流媒体服务器 navidrome 一、云耀云服务器L实例介绍1.1 云服务器介绍1.2 产品规格1.3 产品优势1.4 支持镜像 二、云耀云服务器L实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 navidrome3.1 navidrome 介绍3.…