【C语言进阶】深入C语言指针:基础到进阶的跨越

news2024/11/15 9:02:55

📝个人主页🌹:Eternity._
⏩收录专栏⏪:C语言 “ 登神长阶 ”
🤡往期回顾🤡:C语言数据在内存中的存储
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

❀C语言指针进阶

  • 📒1. 字符指针
  • 📚2. 指针数组
  • 📜3. 数组指针
    • 🌄数组指针的定义
    • 🏞️&数组名VS数组名
    • ⛰️数组指针的使用
  • 📝4. 数组参数、指针参数
    • 🌞一维数组传参
    • 🌙二维数组传参
    • ⭐一级指针传参
    • 🍁二级指针传参
  • 📖5. 总结


前言:在编程的浩瀚星空中,指针犹如一颗璀璨的星辰,它不仅照亮了C语言乃至许多其他编程语言的深邃之路,更是衡量一个程序员技能深度与广度的重要标尺。对于每一位渴望在编程领域深耕细作的开发者而言,掌握指针的进阶应用,无疑是通往高手殿堂的必经之路

指针,作为直接操作内存的强大工具,其魅力在于那份对底层机制的深刻洞察与精准控制。然而,正如攀登高峰需历经艰难险阻,指针的进阶学习同样充满了挑战与未知。从基础的指针声明、解引用,到复杂的指针运算、动态内存管理,再到高级的数据结构如链表、树等的实现与优化,每一步都需要我们付出辛勤的努力与不懈的探索

但正是这些挑战,塑造了指针进阶学习的独特价值。它要求我们不仅要掌握扎实的理论基础,更要具备灵活的思维方式和丰富的实践经验。通过不断地学习与实践,我们将逐渐领悟指针的精髓,学会如何运用指针解决复杂问题,优化程序性能,提升代码质量

让我们一同踏上这场充满挑战与收获的指针进阶之旅吧!


📒1. 字符指针

在C语言中,字符指针是一种特殊的指针类型,它用来存储字符(通常是一个字符串的首地址)的地址。字符指针非常有用,因为它们允许你以数组的形式处理字符串,但实际上是通过指针来操作

int main()
{
	char ch = 'w';
	char* pc = &ch;
	*pc = 'w';
	return 0;
}

除了放字符还可以放置字符串

int main()
{
	const char* pstr = "hello";
	printf("%s\n", pstr);
	return 0;
}

但是在这段代码中,并没有将hello放到字符指针 pstr 里,本质是把字符串 hello首字符的地址放到了pstr中,也就是把一个常量字符串的首字符 h 的地址存放到指针变量 pstr 中

在这里插入图片描述


我们再来看一道经典的题目来了解以下字符指针

int main()
{
	char str1[] = "hello world.";
	char str2[] = "hello world.";
	const char* str3 = "hello world.";
	const char* str4 = "hello world.";
	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;
}

在这里插入图片描述

这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4不同


📚2. 指针数组

C语言中的指针数组是一种特殊的数组,其元素是指针类型,即每个数组元素都存储了一个地址。这些地址可以指向整数、浮点数、结构体、字符串(字符数组的首地址)或其他任何类型的数据。指针数组特别适用于处理多个字符串、动态分配的数据结构集合,或者当你需要存储一系列指向不同对象的指针时

我们在学习指针初阶时,已经简单了解过了,指针数组是一个存放指针的数组

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

📜3. 数组指针

在C语言中,数组指针(有时也被称为指向数组的指针)是一个特殊的指针,它指向一个数组的首元素地址,但其类型表明它指向的是一个数组,而不仅仅是一个单独的元素。然而,需要注意的是,C语言标准中并没有直接称为“数组指针”的类型;我们通常所说的“数组指针”实际上是指向数组首元素的指针,但我们可以根据上下文理解其指向整个数组的含义


🌄数组指针的定义

定义:

int (*p)[10];
//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。
//所以p是一个指针,指向一个数组,叫数组指针。

这里要注意:[]的优先级要高于 * 号的,所以必须加上()来保证p先和 * 结合


🏞️&数组名VS数组名

我们在之前学习指针的时候知道arr是数组名,数组名表示数组首元素的地址,那&数组名是什么含义呢?

示例1:

int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr);
	return 0;
}

在这里插入图片描述
数组名和&数组名打印的地址竟然是一样的?难道它们没有一点区别嘛?我们继续往下看


示例2:

int main()
{
	int arr[10] = { 0 };
	printf("arr = %p\n", arr);
	printf("&arr= %p\n", &arr);
	printf("arr+1 = %p\n", arr + 1);
	printf("&arr+1= %p\n", &arr + 1);
	return 0;
}

在这里插入图片描述
&arr和arr,虽然值是一样的,但是意义应该不一样的

实际上: &arr 表示的是数组的地址,而不是数组首元素的地址。 &arr 的类型是: int(*)[10] ,是一种数组指针类型,数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40


⛰️数组指针的使用

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int(*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
	return 0;
}

但是我们一般很少这样写代码,数组指针一般用于函数的使用


void print_arr(int(*arr)[5], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
	//数组名arr,表示首元素的地址
	//但是二维数组的首元素是二维数组的第一行
	//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
	//可以数组指针来接收
	print_arr(arr, 3, 5);
	return 0;
}

📝4. 数组参数、指针参数

🌞一维数组传参

void test(int arr[])//ok?
{}
void test(int arr[10])//ok?
{}
void test(int* arr)//ok?
{}
void test2(int* arr[20])//ok?
{}
void test2(int** arr)//ok?
{}
int main()
{
	int arr[10] = { 0 };
	int* arr2[20] = { 0 };
	test(arr);
	test2(arr2);
}

在一维数组传参中,以上传参都是可行的


🌙二维数组传参

void test1(int* arr)//ok?
{}
void test2(int* arr[5])//ok?
{}
void test3(int(*arr)[5])//ok?
{}
void test4(int** arr)//ok?
{}
void test5(int arr[3][5])//ok?
{}
void test6(int arr[][])//ok?
{}
void test7(int arr[][5])//ok?
{}
int main()
{
	int arr[3][5] = { 0 };
	test7(arr);
}

在这一堆传参中,只有6会传参失败,二维数组传参,函数形参的设计只能省略第一个[]的数字。
因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算


⭐一级指针传参

void print(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d\n", *(p + i));
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	//一级指针p,传给函数
	print(p, sz);
	return 0;
}

🍁二级指针传参

void test(int** ptr)
{
	printf("num = %d\n", **ptr);
}
int main()
{
	int n = 10;
	int* p = &n;
	int** pp = &p;
	test(pp);
	test(&p);
	return 0;
}

📖5. 总结

在探索C语言指针进阶的旅途中,我们一同跨越了从基础概念到高级应用的广阔天地。指针,作为C语言乃至许多其他编程语言中不可或缺的利器,其强大与灵活让我们能够深入操作系统的底层,高效管理内存,实现复杂的数据结构和算法。通过这一系列的探讨,我们不仅加深了对指针基本原理的理解,如指针的声明、初始化、运算以及如何通过指针访问变量,还深入学习了指针与数组、字符串等高级特性的结合应用,这些技能无疑为我们在编程道路上铺就了坚实的基石

然而,指针的进阶学习并非一蹴而就,它需要我们不断地实践、反思与总结。在这个过程中,我们可能会遇到各种挑战和困惑,但请记住,正是这些经历塑造了我们对编程更深层次的理解与感悟。保持好奇心,勇于探索未知,是每一位编程爱好者应当秉持的态度

在此,我们暂告一段落,但学习的脚步永不停歇。下节内容中,我们将继续深化对指针的理解,探索指针在函数参数传递、以及一些题目的思考。 让我们带着这份对技术的热爱与追求,继续前行,在C语言的海洋中乘风破浪,发现更多未知的精彩

在这里插入图片描述

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

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

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

相关文章

Linux中安装java和tomcat(保姆级教程)

java 篇 JDK是用于开发Java应用程序的软件开发工具包。它包含了编译器、调试器、运行时环境和其他一些开发工具&#xff0c;可以帮助开发人员创建、编译、调试和部署Java应用程序。JDK提供了Java编程语言的开发工具和运行时库&#xff0c;使开发人员能够编写和执行Java代码。 …

TypeScript教程(一)之我们为什么要学TypeScript

根据软件开发设计公司 The Software House 针对 2022 年前端市场状态的调查显示&#xff0c;84% 的受访者都在使用 TypeScript&#xff0c;43% 的受访者甚至认为 TypeScript 将超越 JavaScript 成为前端开发的主要语言。TypeScript 这些年越来越火&#xff0c;可以说是前端工程…

影视会员官方渠道api对接

API对接是指两个不同的软件系统或应用程序之间通过API&#xff08;应用程序编程接口&#xff09;进行交互的过程。这种交互允许数据和功能的共享&#xff0c;而不必暴露系统的内部工作原理。在影视会员充值场景中&#xff0c;API对接具有以下几个关键特点和优势&#xff1a; 数…

【Linux系列】AWK命令使用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Java面试题--JVM大厂篇之JVM大厂面试题及答案解析(4)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而我的博…

使用VBA快速创建非规则数据图表

实例需求&#xff1a;工作表中共有4组数据&#xff0c;第一组数据涵盖所有日期&#xff0c;其他3组均为断续数据。 现在需要创建如下图所示的线图&#xff0c;由于数据区域是非连续的&#xff0c;因此无法直接创建图表。 需要先将数据表按照日期对齐&#xff0c;如下图所示&…

《深度学习》 OpenCV 计算机视觉入门 (中篇)

目录 一、OpenCV函数使用 1、改变像素值 2、图像切片合并 1&#xff09;直接截取相加 2&#xff09;使用cv2.add合并 3&#xff09;此时亮度太高了&#xff0c;需要降低亮度 3、边界填充 1&#xff09;常数填充 2&#xff09;镜面反射填充&#xff08;复制交界处&…

论文仍在苦恼?分享最实用6款AI论文工具网站的汇总!

论文写作是学术研究中的重要环节&#xff0c;然而&#xff0c;面对繁重的写作任务&#xff0c;许多学者和学生常常感到力不从心。幸运的是&#xff0c;随着人工智能技术的飞速发展&#xff0c;一系列AI论文写作工具应运而生&#xff0c;极大地简化了论文写作流程&#xff0c;提…

【Mybatis】介绍+搭建+参数传递+增删改查操作+事务与连接池

目录 一. Mybatis介绍 二. Mybatis搭建 1. 导入Mybatis依赖的jar包 2. 创建Mybatis全局配置文件 3. 定义一个接口 4. 创建sql映射文件 5. 测试 * MyBatisX插件安装 三. 数据库连接池 四. 参数传递 1. 将数据封装到对象中 2. 使用Param注解 五. 数据库事务 六.…

11、Redis高级:Key设置、BigKey解决、批处理优化、集群下批处理、慢查询

Redis高级篇之最佳实践 今日内容 Redis键值设计批处理优化服务端优化集群最佳实践 1、Redis键值设计 1.1、优雅的key结构 Redis的Key虽然可以自定义&#xff0c;但最好遵循下面的几个最佳实践约定&#xff1a; 遵循基本格式&#xff1a;[业务名称]:[数据名]:[id]长度不超过…

【golang学习之旅】复杂数据类型——切片(slice)

系列文章 【golang学习之旅】使用VScode安装配置Go开发环境 【golang学习之旅】报错&#xff1a;a declared but not used 【golang学习之旅】Go 的基本数据类型 【golang学习之旅】深入理解字符串string数据类型 【golang学习之旅】go mod tidy 【golang学习之旅】记录一次 p…

OpenHarmony实战开发: unittest单元测试的编写

背景 程序开发与单元测试二者密不可分&#xff0c;是每个开发人员的基本业务。当功能性代码开发完成后&#xff0c;要自行测试其是否满足设计预期&#xff0c;如果不满足就要回去完善代码&#xff0c;满足则可以提交功能代码及测试用例。 测试用例的另一个重要作用就是阅读者…

【USRP】 Link 16 战术数据链 实训系统

Link 16 战术数据链 实训系统 一、基于USRP的Link16平台简介1、整体架构2、JTIDS终端架构3、平台特点3.1、提高技术理解与应用能力3.2、培养创新思维与问题解决能力3.3、加强跨学科融合与团队合作 4、平台建设4.1、基础理论教学模块4.2、LabVIEW 算法模块4.3、USRP仿真模块4.4、…

如何用ChatGPT快速提升论文质量:实用技巧大公开

近年来&#xff0c;人工智能技术急速发展&#xff0c;尤其在自然语言处理领域取得了显著进展。作为OpenAI推的一款先进的语言模型&#xff0c;ChatGPT不仅在日常交互中表现卓越&#xff0c;也在专业写作领域显示了巨大的潜力。本文旨在详尽介绍如何高效运用ChatGPT来撰写和修改…

JWT双令牌认证实现无感Token自动续约

概念 JSON Web Token (JWT)是一个开放标准(RFC 7519) &#xff0c;它定义了一种紧凑和自包含的方式&#xff0c;用于作为 JSON 对象在各方之间安全地传输信息。此信息可以进行验证和信任&#xff0c;因为它是经过数字签名的。JWT 可以使用机密(使用 HMAC 算法)或使用 RSA 或 E…

LeetCode --- 411周赛

题目列表 3258. 统计满足 K 约束的子字符串数量 I 3259. 超级饮料的最大强化能量 3260. 找出最大的 N 位 K 回文数 3261. 统计满足 K 约束的子字符串数量 II 一、统计满足K约束的子字符串数量I 这种要求满足区间内某种性质的题&#xff0c;一般都可以用滑动窗口来做。这题…

STM32MP157_uboot_初次编译

STM32MP157_uboot_初次编译 前言&#xff1a; 为了快速入门&#xff0c;这边选择直接使用正点原子提供的uboot源码&#xff0c;先体验一下uboot的编译流程&#xff0c;为后面的移植原厂uboot做环境准备。 1、获取正点原子的uboot源码&#xff08;复制到虚拟机里面&#xff09; …

均值漂移算法原理及Python实践

均值漂移算法&#xff08;Mean Shift Algorithm&#xff09;是一种基于密度的非参数聚类算法&#xff0c;其原理主要基于核密度估计和梯度上升方法。以下是均值漂移算法原理的详细解析&#xff1a; 1. 基本思想 均值漂移算法的基本思想是通过迭代地更新数据点的位置&#xff…

Android APK优化系列瘦身篇:实战一个APK从11MB压缩到4MB,APK无用资源去除与代码压缩、混淆,瘦身维度的选型分析

目录&#xff1a; 为什么要进行APK瘦身呢&#xff1f;APK瘦身主要是瘦身哪些呢&#xff1f; a. 优化resources.arsc&#xff1a; b. res优化 c. lib优化 d. 资源优化&#xff0c;代码混淆和压缩总结 一、为什么要进行APK瘦身呢&#xff1f; 减少下载时间和流量消耗&#xff1…

el-table 表格自定义添加表格数据后自动滚动到最底部

动态表格&#xff0c;可以新增行列数&#xff0c;为了用户体验&#xff0c;新增后超出表格流体高度后&#xff0c;自动滚动到最下方 需要element-plus如下api 代码如下&#xff1a; const addCapacity () > {inputList.value.push({name: "",desc: "&quo…