C语言基础(10)之指针(2)

        在上一篇文章中我们谈到了指针,并给老铁们讲解了什么是指针、指针类型、野指针以及指针运算等知识。在这篇文章中小编将继续带大家了解指针的相关知识点。

1. 指针和数组

        指针和数组之间又能有什么联系呢?在谈这个之前,我们先来讲讲指针和数组之间的关系

                1.指针变量就是指针变量,不是数组,指针变量的大小是4/8个字节,专门用来存放地址的。
                2.数组就是数组,不是指针,数组是一块连续的空间,可以存放1个或者多个类型相同的数据。

        那既然指针变量是指针变量,数组是数组,二者之间能有什么联系呢?来看看下面的例子:

        从程序的运行结果中可以得知,数组名和数组首元素的地址是一样的。那么可以得出的结论是:数组名表示的是数组首元素的地址。(2种情况除外,数组部分讲解了)

        既然可以把数组名当成地址存放到一个指针中,那我们使用指针来访问数组就成为可能。再看看如下例子:

#include<stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;  // 指针用来存放数组首元素的地址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;
}

        我们将数组首元素的地址存放在指针p中。从运行结果来看,p+i 其实计算的是数组 arr 下标为i的地址。那我们就可以直接通过指针来访问数组。

        因此指针与数组的联系便是:在数组中,数组名其实就是数组首元素的地址(2种情况除外)。当我们知道数组首元素的地址的时候,因为数组又是连续存放的,所以通过指针就可以遍历访问数组,数组是可以通过指针来访问的。

        个人理解:数组名 == 地址 == 指针。

2. 二级指针

        在次之前,我们谈到的指针都是一级指针,那二级指针是干什么的呢?

        对于一级指针来说,一级指针变量也是变量,是变量就会在内存中开辟空间,是变量就会有地址。因此二级指针变量就是用来存放一级指针变量的地址。

#include<stdio.h>int main()
{int a = 10;int* p = &a; // p是一级指针int** pp = &p; // pp就是二级指针变量*(*pp) = 100;printf("%d\n", **pp); // 解引用2次printf("%d\n", a);同理//int*** ppp = &pp;return 0;
}

        对于上述代码,p是一级指针变量,pp是二级指针变量,int** 其中的 int* 是在说明pp指向的是int*的类型变量,即p的完整类型,*是说明pp是指针变量。

        由于二级指针变量存储的是一级指针变量的地址,因此我们对二级指针pp解引用(即 *pp ),实则访问的是一级指针变量p;所以如果想通过指针pp来找到变量a,那就需要再次进行解引用(即 **pp )。

        换句话说,*pp 等价于 p,对指针 p 解引用找到a,即 *p。所以 *p 等价于 **pp。故 **pp = 100  等价于  *p = 100  等价于  a = 100。

        那么三级指针该怎么写呢?讲到这相信很多老铁都会举一反三了,那便是 int*** ppp = &pp;

3. 指针数组

        指针数组?那究竟是指针还是数组呢?我们可以联想到整型数组、字符数组指的都是数组,那指针数组自然也是指数组了!

        那指针数组是怎样的呢?下面举例来说明:

整型数组:int arr1[5];


字符数组:char arr2[6];


指针数组:int* arr3[5];

所以:

        整型数组  ——  存放整型的数组。
        字符数组  ——  存放字符的数组。
        指针数组  ——  存放指针(地址)的数组。

#include<stdio.h>int main()
{char arr1[] = "abcdef";char arr2[] = "hello xxx";char arr3[] = "cuihua";char* parr[] = { arr1,arr2,arr3 };printf("%c\n", *parr[1]); printf("%c\n", *(parr[1] + 1)); printf("%c\n", (*parr)[1]); return 0;
}

        在上述代码中,数组parr便是指针数组了。在前面我们提到,数组名是数组首元素的地址,因此指针数组parr中存储的是三个字符数组首元素的地址,而不是存储的三个数组内的元素。

        那可能就有老铁好奇怎么通过指针数组来访问三个字符数组中的元素了,下面我将对上述代码中三个printf语句进行讲解,来帮助大家更进一步了解指针数组的的使用和解引用

                1. 对于 *parr[1],因为 [] 的优先级要比 * 高,所以parr先于 [] 结合,即取出数组parr中下标为1的元素,即是 数组arr2 首元素的地址,再对其进行解引用操作,所以取出的是 数组arr2 的首元素,为 h。

                2. 对于 *(parr[1] + 1),同样的 parr[1] 是 数组arr2 首元素的地址。我们可以假设 char* p = parr[1],则 p = arr2,所以 *(parr[1] + 1) 等价于 *(p + 1) 等价于 arr2[1]。故取出的是 数组arr2 中下标为1的元素,即是 e 。

                3. 对于 (*parr)[1],这里与第一点不同,因为有(),所以 parr 先于 * 结合。而指针数组也是数组,parr是数组名,故对数组名解引用 (*parr) 则是取出数组首元素,即是 数组arr1 首元素的地址。所以 *parr 等价于 arr1,即 (*parr)[1] 等价于 arr1[1],故结果为 b

        那指针数组有什么作用呢?如果我们想要打印数组arr1,arr2,arr3,此时指针数组parr就类似于二位数组,通过双层循环便可将三个数组的内容输出出来。

#include<stdio.h>int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 5,6,7,8,9 };int arr3[] = { 0,2,4,6,8 };// 指针数组int* parr[] = { arr1,arr2,arr3 };// 类似于(模拟)的二维数组int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){//printf("%d ", *(parr[i] + j));printf("%d ", parr[i][j]);}printf("\n");}return 0;
}

4. const 修饰指针的理解

        在之前我们谈到const 修饰的变量 变成了常量,即该变量的值不可修改。那么当const修饰指针时,指针是否可修改呢?下面我将通过两个例子来为各位老铁们讲解。

        如上两图中,我们用const修饰指针p。此时const 放在 * 的左边,再通过指针修改其指向的内容时,编译器无法编译通过会报错;而修改指针变量指向的对象时,代码正常运行。也就是说,当const 放在 * 的左边时,限制的是指针指向的内容,不能通过指针变量来改变指针指向的内容,但指针变量的本身是可以改变的。

        如上两图中,同样用const修饰指针变量p,但此时 const 放在了 * 的右边,我们通过指针修改其指向的内容时,编译器却能正常运行了,而修改指针变量所指向的对象时,编译器却报错。也就是说,当 const 放在 * 右边时,限制的时指针变量本身,指针变量本身是不能改变的,但是指针指向的内容是可以通过指针来改变的。

总结:

        1. 当const 放在 * 的左边时,限制的是指针指向的内容,不能通过指针变量来改变指针指向的内容,但指针变量的本身是可以改变的。(限制的是 *p)

        2. 当 const 放在 * 右边时,限制的时指针变量本身,指针变量本身是不能改变的,但是指针指向的内容是可以通过指针来改变的。(限制的是 p)

        不知道各位老铁们看完这篇文章后,有没有对指针有更进一步的了解呢?那我们下篇文章见吧!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Android15车载音频之Virtualbox中QACT实时调试(八十八)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

微信小程序开发-调试及配置文件介绍

一&#xff0c;隐藏控制台系统日志 在小程序开发中&#xff0c;如果你想要隐藏控制台中的系统日志&#xff0c;可以通过以下步骤进行操作&#xff1a; 打开小程序的开发工具。在开发工具的控制台(Console)中&#xff0c;找到你想要隐藏的系统日志。右键点击该系统日志条目。在…

MySQL连接查询:外连接

先看我的表结构 dept表 emp表 外连接分为 1.左外连接 2.右外连接 1.左外连接 基本语法 select 字段列表 FORM 表1 LEFT [OUTER] JOIN 表2 ON 条件;例子&#xff1a;查询emp表的所有数据&#xff0c;和对应部门的员工信息&#xff08;左外连接&#xff09; select e.*, d.n…

利士策分享,旅游是否要舟车劳顿才能尽兴?

利士策分享&#xff0c;旅游是否要舟车劳顿才能尽兴&#xff1f; 国庆假期&#xff0c;当夜幕降临&#xff0c;城市灯火阑珊&#xff0c;一场关于美食与等待的较量悄然上演。 李女士在北京天坛公园附近餐厅的等位经历——前方1053桌的壮观景象&#xff0c;不仅让人咋舌&#xf…

信息学奥赛复赛复习14-CSP-J2021-03网络连接-字符串处理、数据类型溢出、数据结构Map、find函数、substr函数

PDF文档回复:20241007 1 P7911 [CSP-J 2021] 网络连接 [题目描述] TCP/IP 协议是网络通信领域的一项重要协议。今天你的任务&#xff0c;就是尝试利用这个协议&#xff0c;还原一个简化后的网络连接场景。 在本问题中&#xff0c;计算机分为两大类&#xff1a;服务机&#x…

3. BBP系列运动控制板(飞控板)简介

3.1. 概述 Bread Board Pilot(简称BBP) 是在积累了前期 Single Pilot 及 PH7 飞控板大量设计及使用经验的基础上&#xff0c;全新基于PH47代码框架开发的高灵活性&#xff0c; 高性能&#xff0c; 超低成本的最新一代飞控板设计。 目前&#xff0c;因为其使用便捷灵活&#xf…

Hallo部署指南

一、介绍 Hallo是由复旦大学、百度公司、苏黎世联邦理工学院和南京大学的研究人员共同提出的一个AI对口型肖像图像动画技术&#xff0c;可基于语音音频输入来驱动生成逼真且动态的肖像图像视频。 该框架采用了基于扩散的生成模型和分层音频驱动视觉合成模块&#xff0c;提高了…

【AI知识点】正则化(Regularization)

正则化&#xff08;Regularization&#xff09; 是机器学习和统计学中的一种技术&#xff0c;用于防止模型过拟合。在训练模型时&#xff0c;模型可能会过度拟合训练数据&#xff0c;导致在新数据上的表现较差。正则化通过在优化过程中引入额外的约束或惩罚项&#xff0c;使模型…

【开发心得】筑梦上海:项目风云录(6)

目录 会海跳槽 票务开启 漂泊在外的日子 未完待续 会海跳槽 随着时刻表的出炉&#xff0c;意味着大规模的界面开发逐步进入正规。项目组里陆陆续续引进了8个人&#xff0c;最多的时候&#xff0c;同时有10个人在现场。“松工”为我们准备的办公室坐的满满当当&#xff0c;…

Maven 高级之分模块设计与继承、聚合

在软件开发中&#xff0c;随着项目规模的扩大&#xff0c;代码量和复杂度不断增加&#xff0c;传统的一体化开发模式逐渐暴露出诸多问题。为了解决这些问题&#xff0c;模块化开发应运而生&#xff0c;而 Maven 正是模块化开发的利器&#xff0c;它提供的继承和聚合机制为构建和…

wc命令:统计文本行数、单词数、字节数

一、命令简介 ​wc​&#xff08;word count&#xff09;是一个在类 Unix 系统中常用的命令行工具&#xff0c;用于统计文本文件的 行数​、单词数 ​和 字节数​。 ​​ ‍ 二、命令参数 ​wc​ 命令的基本语法如下&#xff1a; wc [选项] 文件选项&#xff1a; ​-c​…

当管理遇上AI,工作效率翻了3倍!

最近这段时间&#xff0c;很多企业都开始降薪、裁员。 在降本增效的大背景下&#xff0c;企业但凡有什么大动作&#xff0c;压力往往都会转嫁到管理者的身上。 一方面&#xff0c;要调大家的状态&#xff0c;处理团队中的各种琐事&#xff1b;另一方面&#xff0c;要及时响应…

【ESP32】Arduino开发 | Timer定时器+定时器闹钟例程

有关定时器外设的详细介绍在ESP-IDF的对应文章中&#xff0c;跳转栏目目录可以找到。 1. API 1.1 启动定时器 hw_timer_t * timerBegin(uint8_t timer, uint16_t divider, bool countUp); timer&#xff1a;定时器序号&#xff08;ESP32有4个硬件定时器&#xff0c;所以可填序…

SpringBoot赋能旅游管理:系统设计与实现

第三章 系统分析 3.1可行性分析 对所有的系统来说&#xff0c;都有可能会受到时间和空间上的制约。所以&#xff0c;我们在设计每一个项目的时候&#xff0c;必须对该系统实行可行性分析&#xff0c;这样不但能够降低项目的危害&#xff0c;还能改降低人力、物力和财力的损耗。…

【CKA】十六、监控Pod度量指标

16、监控Pod度量指标 1. 考题内容&#xff1a; 2. 答题思路&#xff1a; 题目意思是&#xff1a;找出label有namecpu-user的CPU最高的Pod&#xff0c;然后把它的名字写在已经存在的 /opt/KUTR00401/KUTR00401.txt文件里 3. 官网地址&#xff1a; https://kubernetes.io/zh-…

LeetCode 54 Spiral Matrix 解题思路和python代码

题目&#xff1a; Given an m x n matrix, return all elements of the matrix in spiral order. Example 1: Input: matrix [[1,2,3],[4,5,6],[7,8,9]] Output: [1,2,3,6,9,8,7,4,5] Example 2: Input: matrix [[1,2,3,4],[5,6,7,8],[9,10,11,12]] Output: [1,2,3,4,8,1…

反射在Go语言中的具体应用场景

在Go语言中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的特性&#xff0c;它允许程序在运行时检查、修改和操作变量的类型信息。 尽管反射在性能上通常不如直接操作&#xff0c;但它在某些特定场景下非常有用。 反射在Go语言中的具体应用场景&#xff1a;…

基于JAVA的鲜花商城管理系统(源码+定制+讲解)鲜花商城管理系统、鲜花商城管理平台、鲜花商城信息管理、鲜花商城系统开发与应用、鲜花在线商城管理系统

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

基于Springboot海宝海鲜餐厅系统JAVA|VUE|SSM计算机毕业设计源代码+数据库+LW文档+开题报告+答辩稿+部署教+代码讲解

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿 部署教程代码讲解代码时间修改教程 一、开发工具、运行环境、开发技术 开发工具 1、操作系统&#xff1a;Window操作系统 2、开发工具&#xff1a;IntelliJ IDEA或者Eclipse 3、数据库存储&#xff1a…

旅游管理智能化转型:SpringBoot系统设计与实现

第四章 系统设计 4.1系统结构设计 对于本系统的开发设计&#xff0c;先自上向下&#xff0c;将一个完整的系统分解成许多个小系统来进行实现&#xff1b;再自下向上&#xff0c;将所有的“零件”组装成一个大的、完整的系统。因此这里面的许多个小功能块都要对将要实现的功能进…