C语言易错知识点九(指针(part three))

news2025/1/16 5:40:27

❀❀❀ 文章由@不准备秃的大伟原创 ❀❀❀

♪♪♪ 若有转载,请联系博主哦~ ♪♪♪

❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤

   许久不见,甚是想念,本大忙人已经很久没有更新博客了,我想大概我的粉丝们早已按耐不住了吧(假)!好的啊,今天的话继续我们仍未结束的指针。

        在上一篇有关指针的文章中我们谈论了有关野指针assert断言以及与指针有关的计算。还没看过的小伙伴们可以戳戳这里传送哦~  ----->  指针 (Part two) 

        那么今天的话给大伙们介绍一下几种指针类型:字符指针,指针数组,数组指针和函数指针(当然最基础的指针变量大家都会的吧~)     什么,不会?那不赶紧戳一戳这里------>   指针 (Part one)

        嗯哼,好的,接下来开始今天的正题:

                  一.字符指针

        我们既然有了整形指针,那么没有字符指针是不是说不过去?整形指针是int*,那么字符指针不就是char*吗?

        好的,字符指针结束了。

         ...........................................................

        大家都知道我的尿性吧?我说结束了不是结束,而屏幕前的你说结束才是结束,所以,实不相瞒,想要个赞(✿◡‿◡)

        这时候问题就出来了,我们用字符指针存个 'a' 'C' 都是没有什么问题的吧,但 ? 字符串呢?存放的是整个字符串吗?还是只存首元素?还是存放的是首元素的地址?

        如下面一段代码:

int main()
{
 const char* pstr = "hello world!";//pstr里面到底存的是什么
 printf("%s\n", pstr);
 return 0;
}

        在我们运行过后发现,打印的是整个hello world! ,那么我们的pstr存放的就是整个字符串。

—————— 对吗?

        仔细考虑的同学就会发现疑点,“ 既然我用char str[]就可以存放一个字符串,那么char* 还有必要存在吗? ” 是的,我们这么仔细一想就发现,char*存放的才不是元素呢?是地址!是这个字符串的首元素的地址!但这时又有同学有疑惑了“既然存的是地址,那为什么还能打印出整个字符串呢?” 诶,好问题,这就要联系到我们的内存问题了,这部分博主以后会在博客里谈到,这里就简单给大家解释一下:

      我们计算机中任何数据的存储都会占用一定的空间,而每一部分的空间都有自己的独自的地址,我们可以通过地址来寻找到这个空间存放的值。这和数组传参本质是一个道理,我们同样可以通过一个数组的首元素地址来找到数组后面的内容。

        有意思吧?接下来看一个更有意思的代码:

#include <stdio.h>
int main()
{
 char str1[] = "hello bit.";
 char str2[] = "hello bit.";
 const char *str3 = "hello bit.";
 const char *str4 = "hello bit.";
 if(str1 ==str2)
 printf("str1 and str2 are same\n");
 else
 printf("str1 and str2 are not same\n");

 if(str3 ==str4)
 printf("str3 and str4 are same\n");
 else
 printf("str3 and str4 are not same\n");

 return 0;
}

         怎么样,汗流浃背了?这其实没什么,记住我们数组传参的本质是地址,所以我们两个if比较的就是地址。所以答案是....?

c315d0e3dfad47dda397f39dd7efa2ae.png

        对,答案是 not same和same。博主上面也讲到了吧?模拟实现二维数那里。我们创建的数组空间是不连续的,所以str1[] 和 str2[] 指向的是两块不同的空间,虽然他们的内容一样,但是我们if比较的是地址啊?所以是not same;而我们给字符指针str3和字符指针str4定义的是同一个内容(常量字符串), 而在C/C++中会把常量放到一块独立的空间里(常量区),这也就说明,我们的str3和str4指向的是同一块空间,所以是same。

                  二.指针数组 

        诶,在开始前我先问大家一个问题,指针数组是指针还是数组?<(* ̄▽ ̄*)/  我们其实可以类比一下:整形指针是存放整形的指针,字符指针是存放字符的指针,那么指针数组是存放指针的数组。即:指针数组的每个元素都是⽤来存放地址(指针)的。 

        那我们一般定义一个数组是怎么定义的?如存放整形的数组:int arr[10] = {0},每个元素存放的是整形,对吧? 那么同样的,存放指针的数组我们一般就这么定义:int *arr[10] = {0}; 每一个元素存放的是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*的,就可以存放在parr数组中
	int* parr[3] = { arr1, arr2, arr3 };
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d ", parr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

答案如下: 

a7f6d01b2e6e4f718b90c34fef73fcb9.png

        是不是很容易理解?我们这样就通过指针数组模拟实现了一个二位数组,但是!但是!但是!上述的代码模拟出⼆维数组的效果,实际上并⾮完全是⼆维数组,因为每⼀⾏并⾮是连续的(每一个一维数组向内存申请的空间是不连续的)。 

        指针数组的知识大概就到这里了,怎么样,是不是没有觉得很难?

                   二.数组指针

         那博主把铁汁们当一次傻子,数组指针内存放的是什么? 啊对对对,是指针,看来铁汁们有好好看上面的内容,博主很是欣慰。o(^▽^)o

        那        int *p1[10];         int (*p2)[10];         这两个哪个是数组指针?“不就是第二个吗?第一个不是指针数组?” 嗯嗯嗯,好好好,看到铁汁们这么快反应过来真好,哈哈。是的,我们将指针数组的变量名与*括起来就是表达的数组指针。

        原理呢?不懂得可以听博主解释一下哦~:

解释:p和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。所以 p是⼀个指针,指向⼀个数组,叫 数组指针。

        指针数组可以存放多个指针,那么数组指针有什么用呢?既然存在了,怎么会没有用呢?就如同现在的你我可能还没有发觉自己的价值,但是如果你我是无价值的,上帝怎么可能会将我们放到人间呢?对吧,所以大家要对自己有信心!加油!

        呃哼,扯远了,我们继续:如果要存放个数组的地址,就得存放在数组指针变量中,如下: 

int(*p)[10] = &arr;

我们调试也能看到 &arr 和 p 的类型是完全⼀致的: 

7fb891e56a3741b8b39ef3f08d429b1d.png

         既然把数组指针学了,接下来二维数组的传参本质:

先给结论:arr[i] = *(arr+i)     arr[i][j] = *(*(arr+i)+j)

        那我们以前是怎么给函数传二维数组的呢?

void test(int a[3][5], int i, int j);//函数申明
test(arr, 3, 5);//main函数内部的传址和传值

        ⾸先我们再次理解⼀下⼆维数组,⼆维数组起始可以看做是每个元素是⼀维数组的数组,也就是⼆维 数组的每个元素是⼀个⼀维数组。那么⼆维数组的⾸元素就是第⼀⾏,是个⼀维数组。 

        而现在我们学了数组指针,我们就有新的玩法了: 

     根据数组名是数组⾸元素的地址这个规则,⼆维数组的数组名表⽰的就是第⼀⾏的地址,是⼀ 维数组的地址。根据上⾯的例⼦,第⼀⾏的⼀维数组的类型就是 int [5] ,所以第⼀⾏的地址的类 型就是数组指针类型 int(*)[5] 。那就意味着⼆维数组传参本质上也是传递了地址,传递的是第⼀ ⾏这个⼀维数组的地址,那么形参也是可以写成指针形式的。

        所以我们可以这么写:

void test(int (*p)[5], int r, int c);//函数申明
test(arr, 3, 5);//main函数内部的传址和传值

         总结:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。

                  三.函数指针

        之前博主说过,任何数据都是有地址的,那,函数也包括在这个 ‘数据’ 里面吗?我们可以做个测试:

#include <stdio.h>
void test()
{
 printf("hehe\n");
}
int main()
{
 printf("test: %p\n", test);
 printf("&test: %p\n", &test);
 return 0;
}

 cee8283f33d448e5ab1e43345a31c7f7.png

        我们可以看到确实打印出来了地址,所以函数是有地址的,函数名就是函数的地址,当然也可以通过 &函数名 的⽅式获得函数的地址。 

         如果我们要将函数的地址存放起来,就得创建函数指针变量咯,函数指针变量的写法其实和数组指针 ⾮常类似。如下:

void test()
{
 printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)()= test;
int Add(int x, int y)
{
 return x+y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;

        给大家提供两段很有意思的代码,大家私下可以仔细思考思考:

(*(void (*)())0)();
 void (*signal(int , void(*)(int)))(int);

        OK,那么今天的任务也就到此为止了,下一篇part four是指针的最后一篇了,希望大家继续多多支持大伟,加油! 

        Life if full of a lot of pain,the truly great personality is not standing on high,standing in the flowers and applause.The truly great personality is at the bottom of life,in this training,you can still cheer up,still have courage,still have hope,and still will not be casually crushed by disaster.   ————黄色安全帽(抖音)

   本篇博客也就到此为止了,送大家一碗鸡汤,勉励自己以及这世界上所有追逐梦想的赤子趁年华尚好努力提升自己,莫欺少年穷! e2f7b450148f4bf5b53f823b95fd5406.jpeg

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

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

相关文章

使用ArcMap对工厂选址

文章目录 题目流程1&#xff0c;添加河流数据和高程数据2&#xff0c;对河流数据进行选取3&#xff0c;对高程数据进行选取并划定工厂选址范围3&#xff0c;根据工厂选址要求&#xff0c;获得整体的数据 结果 题目 实验名称&#xff1a;工厂选址 实验目的及要求&#xff1a; 根…

BATDK | 社招一年收割大厂算法offer

面试锦囊之面经分享系列&#xff0c;持续更新中 欢迎后台回复『面试』加入讨论组交流噢 没凑齐battmd是因为头条没面&#xff0c;美团面挂了。4/5的胜率&#xff1b;标题党了&#xff0c;T其实面的是搜狗&#xff0c;但是被腾讯收购&#xff0c;入职流程也走了腾讯的&#xf…

【低照度图像增强系列(1)】传统方法(直方图、图像变换)算法详解与代码实现

前言 ☀️ 在低照度场景下进行目标检测任务&#xff0c;常存在图像RGB特征信息少、提取特征困难、目标识别和定位精度低等问题&#xff0c;给检测带来一定的难度。 &#x1f33b;使用图像增强模块对原始图像进行画质提升&#xff0c;恢复各类图像信息&#xff0c;再使用目标检…

Kafka日志

位置 server.properties配置文件中通过log.dir指定日志存储目录 log.dir/{topic}-{partition} 核心文件 .log 存储消息的日志文件&#xff0c;固定大小为1G&#xff0c;写满后会新增一个文件&#xff0c;文件名表示当前日志文件记录的第一条消息的偏移量。 .index 以偏移…

Vue+ElementUI+nodejs学生宿舍报修管理系统68ozj

本站是一个B/S模式系统&#xff0c;采用vue框架&#xff0c;MYSQL数据库设计开发&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得学生宿舍信息管理系统管理工作系统化、规范化。本系统的使用使管理人员从繁重的工作中…

2023的AI工具集合,google和claude被禁用解决和edge的copilot

一、前言 AI工具集合 首先&#xff0c;OpenAI的ChatGPT以其深度学习模型和强大的语言处理能力引领了AI聊天机器人的潮流。自2022年11月30日上线以来&#xff0c;它创下了100万用户的注册记录&#xff0c;并被广泛应用于全球财富500强公司。为了实现盈利&#xff0c;OpenAI发布…

git入门指南:新手快速上手git(Linux环境如何使用git)

目录 前言 1. 什么是git&#xff1f; 2. git版本控制器 3. git在Linux中的使用 安装git 4. git三板斧 第一招&#xff1a;add 第二招&#xff1a;commit 第三招&#xff1a;push 5. 执行状态 6. 删除 总结 前言 Linux的基本开发工具介绍完毕&#xff0c;接下来介绍一…

Go 泛型发展史与基本介绍

Go 泛型发展史与基本介绍 Go 1.18版本增加了对泛型的支持&#xff0c;泛型也是自 Go 语言开源以来所做的最大改变。 文章目录 Go 泛型发展史与基本介绍一、为什么要加入泛型&#xff1f;二、什么是泛型三、泛型的来源四、为什么需要泛型五、Go 泛型设计的简史六、泛型语法6.1 …

采用SpringBoot框架+原生HTML、JS前后端分离模式开发和部署的电子病历编辑器源码(电子病历评级4级)

概述&#xff1a; 电子病历是指医务人员在医疗活动过程中,使用医疗机构信息系统生成的文字、符号、图表、图形、数据、影像等数字化信息,并能实现存储、管理、传输和重现的医疗记录,是病历的一种记录形式。 医院通过电子病历以电子化方式记录患者就诊的信息&#xff0c;包括&…

神经网络:机器学习基础

【一】什么是模型的偏差和方差&#xff1f; 误差&#xff08;Error&#xff09; 偏差&#xff08;Bias&#xff09; 方差&#xff08;Variance&#xff09; 噪声&#xff08;Noise&#xff09;&#xff0c;一般地&#xff0c;我们把机器学习模型的预测输出与样本的真实label…

智能优化算法应用:基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.材料生成算法4.实验参数设定5.算法结果6.…

Netty RPC 实现(二)

Netty RPC 实现 概念 RPC&#xff0c;即 Remote Procedure Call&#xff08;远程过程调用&#xff09;&#xff0c;调用远程计算机上的服务&#xff0c;就像调用本地服务一样。RPC 可以很好的解耦系统&#xff0c;如 WebService 就是一种基于 Http 协议的 RPC。这个 RPC 整体…

生物系统学中的进化树构建和分析R工具包V.PhyloMaker2的介绍和详细使用

V.PhyloMaker2是一个R语言的工具包&#xff0c;专门用于构建和分析生物系统学中的进化树&#xff08;也称为系统发育树或phylogenetic tree&#xff09;。以下是对V.PhyloMaker2的一些基本介绍和使用说明&#xff1a; 论文介绍&#xff1a;V.PhyloMaker2: An updated and enla…

nodejs+vue+ElementUi洗衣店订单管理系统4691l

衣服但是找订单的时间太长&#xff0c;体验非常的差。而且对于店家这也很头疼&#xff0c;麻烦的查找订单的方式&#xff0c;让他总是重复着繁琐的步骤&#xff0c;记录的时候也很容易出问题&#xff0c;容易把衣服弄错&#xff0c;再然后就是对于收来的衣服也很麻烦&#xff0…

互联网+建筑工地源码,基于微服务+Java+Spring Cloud +Vue+UniApp开发

一、智慧工地概念 智慧工地就是互联网建筑工地&#xff0c;是将互联网的理念和技术引入建筑工地&#xff0c;然后以物联网、移动互联网技术为基础&#xff0c;充分应用BIM、大数据、人工智能、移动通讯、云计算、物联网等信息技术&#xff0c;通过人机交互、感知、决策、执行和…

指南:在App Store Connect上编辑多个用户的访问权限

作为一名编程新手&#xff0c;在App Store Connect中管理用户权限可能初听起来有些复杂&#xff0c;但实际上它是一个相对直接的过程。这里是一个步骤清晰的指南来帮助您在App Store Connect上编辑多个用户的访问权限。 App Store Connect 简介 在开始之前&#xff0c;让我们…

CycleGAN-两个领域非匹配图像的相互转换

1. CycleGAN的简介 pix2pix可以很好地处理匹配数据集图像转换&#xff0c;但是在很多情况下匹配数据集是没有的或者是很难收集到的&#xff0c;但是我们可以很容易的得到两个领域大量的非匹配数据。2017年有两篇非常相似的论文CycleGAN和DiscoGAN&#xff0c;提出了一种解决非匹…

Dockerfile ENTRYPOINT 执行shell脚本后自动退出

在Dockerfile文件中&#xff0c;最后一步是在入口处启动服务或执行一些部署脚本&#xff0c;例如&#xff1a; # 运行启动脚本 ENTRYPOINT ["/bin/bash","/home/deploy/run_admin_server.sh"]脚本是这样写的&#xff1a; rm -f /home/workspace/*.jar cd…

物理层——“计算机网络”

各位CSDN的uu们你们好呀&#xff0c;仍然是计算机网络的一些细小的知识点啦&#xff0c;下面&#xff0c;让我们进入计算机网络物理层的世界吧&#xff01;&#xff01;&#xff01; 数据通信基础知识 编码与调制 传输媒体 信道复用技术 数字传输系统 接入技术 数据通信基…

CSS期末知识复习, 重要知识点摘录

CSS期末知识复习&#xff0c;重要知识点摘录 CSS的创建 外部样式表 内部样式表 内联样式 优先级关系 背景设置 1.颜色 2.背景图像 3.背景是否平铺 4.简写 具体属性参考&#xff0c;不多赘述了&#xff0c;毕竟每个人薄弱点不一样 background菜鸟教程 CSS文本 1.颜色 2.对齐方…