C语言之深入指针(二)(详细教程)

C语言之深入指针

文章目录

  • C语言之深入指针
    • 1. 传值调用和传址调用
    • 2. 数组名的理解
    • 3. 使用指针访问数组
    • 3. ⼀维数组传参的本质

1. 传值调用和传址调用

写一个函数用来交换a b的值

传值调用:

#include <stdio.h>
void Swap1(int x, int y)
{
	int tmp = 0;
	tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:%d %d\n", a, b);
	Swap1(a, b);
	printf("交换后:%d %d\n", a, b);
	return 0;
}

代码运行结果如下:
在这里插入图片描述
从运行结果可以看到,a和b的值并没有进行交换,因为传给Swap1函数的只是a和b的值,在Swap1函数内部创建了a和b的临时备份,也就是将实参传给了形参,形参有自己的内存空间,对形参的修改并不会影响实参
这种函数调用方式是:传值调用

结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实

传址调用:

#include <stdio.h>
void Swap2(int* x, int* y)
{
	int tmp = 0;
	tmp = *x;
	*x = *y;
	*y = tmp;
}

int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:%d %d\n", a, b);
	Swap2(&a, &b);
	printf("交换后:%d %d\n", a, b);
	return 0;
}

在这里插入图片描述
从运行结果可以看出,a和b的值有进行交换,这是因为传给Swap2函数的是a和b的地址,然后Swap2函数用两个指针变量来储存a和b的地址,所以在函数中改变x和y的值,由于是相同地址,所以a和b的值也会改变,着这种函数调用方式是:传址调用

2. 数组名的理解

先来看段代码:

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf(" arr    = %p\n", arr);
	printf("&arr[0] = %p\n", &arr[0]);
	return 0;
}

代码运行结果:
在这里插入图片描述

从运行结果来看,arr和&arr[0]的打印出来的地址都是相同的,可以得知道,数组名就是数组⾸元素(第⼀个元素)的地址

但是有两个情况是例外

  1. • sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,
    单位是字节
  2. • &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素
    的地址是有区别的)
//情况1
#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d", sz);
	return 0;
}

在以上情况下,sizeof中的数组名是表示整个数组,计算的是整个数组的大小

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	/*int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d", sz);*/
	printf(" arr    = %p\n", arr);
	printf("&arr    = %p\n", &arr);
	printf("&arr[0] = %p\n", &arr[0]);
	return 0;
}

在这里插入图片描述

从运行结果看出,arr,&arr和&arr[0]打印的地址是一样的,都是首元素地址,arr和&arr[0]都是表示首元素的地址,那么arr和&arr有什么区别嘛
再来看一段代码:

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	/*int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d", sz);*/
	printf(" arr      = %p\n", arr);
	printf(" arr + 1  = %p\n", arr+1);
	printf("&arr      = %p\n", &arr);
	printf("&arr + 1  = %p\n", &arr+1);
	printf("&arr[0]   = %p\n", &arr[0]);
	printf("&arr[0]+1 = %p\n", &arr[0]+1);
	return 0;
}

运行结果如下:
在这里插入图片描述
从结果可以看出
arr + 1 从~B78 变成了 ~B7C 加上了4个字节的空间
&arr + 1从~B78 变成了 ~BA0 由于是16进制,转换为二进制就是从120变成了160 加上了40个字节的空间
&arr[0] + 1和arr + 1的结果一样,都是加上了4个字节

• 结论 arr + 1 表示跳过4个字节也就是一个元素,而&arr + 1 表示跳过40个字节,也就是一整个数组

3. 使用指针访问数组

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);  //求数组中元素的个数
	int* p = arr;
	int i = 0;
	for(i=0;i<sz;i++)
	{
		//输入10个数 以下方法都可以
		scanf("%d", p + i);
	    /*scanf("%d", arr+i);*/
	}
	for (i = 0; i < sz; i++)
	{
		//输出10个数 以下方法都可以
		printf("%d ", *(p + i)); 
		/*printf("%d ", p[i]);*/
		/*printf("%d ", *(arr + i));*/
		/*printf("%d ", arr[i]); */
		/*printf("%d ", i[arr]);*/
	}
	return 0;
}

p + i 等价于 arr + i
p [ i ] 等价于 *( p + i )
arr[ i ] 等价于 *( arr + i )
都是通过首元素的地址 + 偏移量,然后解引用来访问数组的元素
arr[ i ] 编译器会转换成 *( arr + i )来处理的,例如加法的交换律a+b可以写成b+a,那么也可以写成 *(i + arr),所以也就可以写成 i [arr],但是不建议这样写,代码的可读性极低,只是做个了解

3. ⼀维数组传参的本质

给定一共整形数组,求数组的的元素个数

#include <stdio.h>
void test1(int arr[])//参数写成数组形式,本质上是指针
{
	int sz2 = sizeof(arr) / sizeof(arr[0]);
	printf("sz2 = %d\n", sz2);
}
void test2(int* arr) //参数写成指针形式
{
	int sz3 = sizeof(arr) / sizeof(arr[0]);
	printf("sz3 = %d\n", sz3);
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz1 = sizeof(arr) / sizeof(arr[0]);
	printf("sz1 = %d\n", sz1);
	test1(arr);
	test2(arr);
	return 0;
}

代码运行结果如下:
在这里插入图片描述

1.数组名是数组⾸元素的地址;那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参本质上传递的是数组⾸元素的地址
所以在函数中是无法计算数组的元素个数的
2. 其次,一维数组的传参,函数的参数可以写成数组的形式,也可以写成指针形式

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第十八章 Swing程序设计

Swing用于开发桌面窗体程序&#xff0c;是JDK的第二代GUI框架&#xff0c;其功能比JDK第一代GUI框架AWT更为强大、性能更加优良。但因为Swing技术推出时间太早&#xff0c;其性能、开发效率等不及一些其他流行技术&#xff0c;所以目前市场上大多数桌面窗体程序都不是由Java开发…

rabbitmq 集群搭建

RabbitMQ集群介绍 RabbitMQ集群是一组RabbitMQ节点&#xff08;broker&#xff09;的集合&#xff0c;它们一起工作以提供高可用性和可伸缩性服务。 RabbitMQ集群中的节点可以在同一物理服务器或不同的物理服务器上运行。 RabbitMQ集群的工作原理是&#xff0c;每个节点在一个…

12-使用vue2实现todolist待办事项

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

Python杂谈--关于iter迭代器的一些讨论

首先我们来看下面一段代码&#xff1a; for i in range(5):print(i) 这是一段非常简单的代码&#xff0c;它会打印出“0-5”这五个数字。 此时在range()迭代器中&#xff0c;它的start为空(默认为无穷小)&#xff0c;stop为5&#xff0c;step为空(默认为1)。 此时我们在看下…

hidl hwbinder和binder混合使用相关的joinThreadPool问题解答

背景&#xff1a; 今天一个学员在群里有个提问如下图&#xff0c;怎么有两个joinThread&#xff0c;会执行么&#xff1f;joinThread不是死循环等待数据吗&#xff1f; /frameworks/av/media/mediaserver/main_mediaserver.cpp 当开始看到这个时候确实也觉得最后的hw的join根本…

电脑篇——将串口映射到远程电脑上

通过Windows自带的远程桌面连接功能&#xff0c;可以通过修改本地资源选项&#xff0c;将本机的串口/端口映射到远程电脑上。 即可将端口映射到远程电脑上。 &#xff08;在远程的电脑的设备管理器中可能不会显示&#xff0c;但是用串口调试相关的工具&#xff0c;是可以找到相…

JVM——类加载器(JDK8及之前,双亲委派机制)

目录 1.类加载器的分类1.实现方式分类1.虚拟机底层实现2.JDK中默认提供或者自定义 2.类加载器的分类-启动类加载器3.类加载器的分类-Java中的默认类加载器4.类加载器的分类-扩展类加载器5.类加载器的分类-类加载器的继承 2.类加载器的双亲委派机制 类加载器&#xff08;ClassLo…

文件上传_白名单、内容校验、竞争上传

服务端校验—后缀名白名单校验 服务端校验—文件内容头校验 竞争上传

ROS 学习应用篇(五)服务Server学习之自定义服务与调用

在之前我学着如何建立一个话题Topic的消息类型&#xff0c;那时候建立了一个msg文件&#xff0c;包括&#xff0c;消息名称和消息数据类型&#xff08;int还是什么之类的。&#xff09;&#xff0c;将其链接到CMakeList&#xff0c;.xml文件补录需要的依赖&#xff0c;CMakeLis…

十九章总结

一.Java绘图类 1.Graphics类 Graphics类是所有图形上下文的抽象基类&#xff0c;它允许应用程序在组件以及闭屏图像上进行绘制。Graphics类封装了Java支持的基本绘图操作所需的状态信息&#xff0c;主要包括颜色、字体、画笔、文本、图像等。 2.Graphics2D类 Graphics2…

Vue3问题:如何实现拼图验证+邮箱登录功能?前后端!

前端功能问题系列文章&#xff0c;点击上方合集↑ 序言 大家好&#xff0c;我是大澈&#xff01; 本文约3500字&#xff0c;整篇阅读大约需要5分钟。 本文主要内容分三部分&#xff0c;第一部分是需求分析&#xff0c;第二部分是实现步骤&#xff0c;第三部分是问题详解。 …

「软件设计」权威领域驱动设计(DDD)简介

「软件设计」权威领域驱动设计(DDD)简介 今天的企业应用程序无疑是复杂的&#xff0c;并依赖一些专门技术&#xff08;持久性&#xff0c;AJAX&#xff0c;Web服务等&#xff09;来完成它们的工作。作为开发人员&#xff0c;我们倾向于关注这些技术细节是可以理解的。但事实是…

一键将CSDN博客文章如何转为Markdown

文章目录 1.在CSDN博文页面点击右键&#xff0c;选择“检查”&#xff08;Google浏览器为例&#xff09;。2.在查看器中搜索article_content&#xff0c;找到对应内容&#xff0c;点击…复制为outerHTML。3.打开网址https://tool.lu/markdown/&#xff0c;点击HTML2MD&#xff…

准备搞OpenStack了,先装一台最新的Ubuntu 23.10

正文共&#xff1a;1113 字 25 图&#xff0c;预估阅读时间&#xff1a;2 分钟 依稀记得前面发了一篇Ubuntu的安装文档&#xff08;66%的经验丰富开发者和69%的学生更喜欢的Ubuntu的安装初体验&#xff09;&#xff0c;当时安装的是20.04.3的版本&#xff0c;现在看来已经是非常…

第一百七十三回 如何创建线性渐变背景

文章目录 1. 概念介绍2. 实现方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"SegmentedButton组件"相关的内容&#xff0c;本章回中将介绍" 如何创建线性渐变背景"。闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. …

医学图像 开源数据整理合集1

本文为医学图像 开源数据整理合集&#xff0c;为科研数据提供方便和检索。 目录 1 NIH database of 100000 Chest X-rays 2 The Cancer Imaging Archive (TCIA) 3 National Institute for Mental Healths (NIMHs) OpenNeuro.org 4 RSNAs Quantitative Imaging Data Wareh…

Git目录不对,即当前文件夹不对应git仓库

报错信息是&#xff1a; fatal: not a git repository (or any of the parent directories): .git 如&#xff1a; 是当前文件夹不对应git仓库&#xff0c;一般在git clone之后&#xff0c;需要进入下一级文件夹才对应仓库。 在文件夹看&#xff0c;本层中没有.git文件夹&…

动画短片怎么制作gif?一个方法简单又好用

网络上常常能看到动画短片&#xff0c;虽然时长短但是内容很丰富。当我们想要将这种动画短片做成gif格式图片的时候&#xff0c;应该怎么办呢&#xff1f;很简单&#xff0c;通过使用在线制作动画&#xff08;https://www.gif.cn/&#xff09;网站&#xff0c;无需下载软件上传…

Django模版层

解析: forloop内置对象:运行结果解析 counter0: 从0开始计数 counter : 从1开始计数 first: True,判断循环的开始 last : Tues,判断循环的结束模版变量的书写 我们可以在html中编写python代码。 演示&#xff1a; {{ 填写变量 }}{% 填写类的 %}{{ d.0 }} {{ d.1 }…
最新文章