【C语言指针专题(4)】指针与一维数组

一、数组名的理解

在之前我们我们使用指针访问数组的时候,使用到了这样一段代码:

int arr[10] = { 0 };
int* pa = &arr[0];

这里我们使用 &arr[0] 的方式拿到了数组第一个元素的地址,但是其实数组名本来就是地址,而且 是数组首元素的地址,我们来做个测试。

//演示1.1

#include <stdio.h>

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

\

我们发现数组名和数组首元素的地址打印出的结果一模一样,数组名就是数组首元素(第一个元素)的地址。 这时候我们可能会有疑问,如果数组名是数组首元素的地址,那下面的代码要怎么理解呢?

//演示1.2

#include <stdio.h>

int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    printf("%d\n", sizeof(arr));
    return 0;
}

如果数组名是数组首元素的地址,那么这里的结果应该是4或8,也就是一个地址的大小。但我们已经知道结果是40,是10个整型的大小。这是为什么呢?

其实数组名就是数组首元素(第一个元素)的地址是对的,但是有两个例外:

• sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表示整个数组,计算的是整个数组的大小,单位是字节。

• &数组名,这里的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的,下面我们会详细解释)。

除此之外,任何地方使用数组名,数组名都表示首元素的地址。

接下来让我们看看下面这段代码:

//演示1.3

#include <stdio.h>

int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    printf("&arr[0] = %p\n",&arr[0]);
    printf("    arr = %p\n",arr);
    printf("   &arr = %p\n",&arr);
    return 0;
}

从这段代码看,&arr[0]、arr、&arr的打印结果完全一样,那么它们区别在哪里呢?

我们再看下面这段代码:

//演示1.4

#include <stdio.h>

int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    printf("    &arr[0] = %p\n",&arr[0]);
    printf("&arr[0] + 1 = %p\n",&arr[0] + 1);
    printf("    arr + 1 = %p\n",arr + 1);
    printf("   &arr + 1 = %p\n",&arr + 1);
    return 0;
}

它们的结果已经不一样了,可以看到,相比于arr[0],

&arr[0]+1和arr+1,跳过了4个字节,说明它们代表的是数组首元素的地址,+1后跳过一个元素,也就是跳过一个整型;

&arr+1,跳过了40个字节,说明它代表的是整个数组的地址,+1后跳过一个arr数组的大小。

二、使用指针访问数组

有了前面知识的理解,再结合数组的特点,我们就可以很方便的使用数组来访问数组了。

//演示2.1

#include <stdio.h>

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* parr = arr;
    //输入
	for (i = 0; i < sz; i++)
	{
		scanf("%d", parr + i);
        //也可以写成 scanf("%d", arr + i);
	}
    //输出
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(parr + i));
	}
	return 0;
}

数组名arr是数组首元素的地址,可以赋值给parr,也就是说数组名arr和整型指针parr在这里是等价的。那么我们可以使用arr[i]来访问数组中的元素,是不是也可以使用parr[i]来实现这样的操作呢?

//演示2.2

#include <stdio.h>

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* parr = arr;
	for (i = 0; i < sz; i++)
	{
		scanf("%d", parr + i);
	}
	for (i = 0; i < sz; i++)
	{
		printf("%d ", parr[i]);
	}
	return 0;
}

输入的数据被很好的打印了出来,所以说parr[i]是等价于arr[i]的,实质上,arr[i]和parr[i]都会被计算机理解为*(parr+i)。

三、一维数组传参的本质

我们已经了解两个知识,在主函数中通过sizeof相除来求数组中元素的个数,以及数组可以作为参数传递给函数。

那么我们可不可以把一个数组传递给主函数外的某个函数,然后在这个函数内通过sizeof相除的方法求出数组元素的个数呢?我们来试一下:

//演示3.1

#include <stdio.h>

void test(int pa[])
{
    int sz2 = sizeof(pa)/sizeof(pa[0]);
    printf("sz2 = %d\n", sz2);
}

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

我们发现这种做法行不通。它的原因涉及到一维数组传参的本质,我们接下来来探讨一下这个问题。

我们知道,数组名代表的是数组首元素的地址,那么我们在将数组名作为参数直接传递给函数时,传过去的也就应该是数组首元素的地址。

所以在演示3.1中test函数计算sz2时,sizeof(pa)的值不会是arr数组的大小,而是arr数组首元素地址的大小,也就是4或8个字节,所以sz2结果的结果是1或2(在x64环境下)。

通过上面的例子,我们知道了一维数组在传参时实际传递的是一个地址,所以函数的形参部分理论上应该用一个指针来接受传来的参数。但是实际运用中呢,我们常常就写作数组的形式了,因为这样并不错,而且也更易于理解。

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

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

相关文章

使用opencv实现图像中几何图形检测

1 几何图形检测介绍 1.1 轮廓(contours) 什么是轮廓&#xff0c;简单说轮廓就是一些列点相连组成形状、它们拥有同样的颜色、轮廓发现在图像的对象分析、对象检测等方面是非常有用的工具&#xff0c;在OpenCV 中使用轮廓发现相关函数时候要求输入图像是二值图像&#xff0c;这…

麒麟V10 ARM 离线生成RabbitMQ docker镜像并上传Harbor私有仓库

第一步在外网主机执行&#xff1a; docker pull arm64v8/rabbitmq:3.8.9-management 将下载的镜像打包给离线主机集群使用 在指定目录下执行打包命令&#xff1a; 执行&#xff1a; docker save -o rabbitmq_arm3.8.9.tar arm64v8/rabbitmq:3.8.9-management 如果懒得打包…

力扣:77. 组合(回溯, path[:]的作用)

题目&#xff1a; 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ] 示例 2&#xff1a; 输入&…

机器学习数据的清洗,转化,汇总及建模完整步骤(基于Titanic数据集)

目录 介绍&#xff1a; 一、数据 二、检查数据缺失 三、数据分析 四、数据清洗 五、数据类别转化 六、数据汇总和整理 七、建模 介绍&#xff1a; 线性回归是一种常用的机器学习方法&#xff0c;用于建立一个输入变量与输出变量之间线性关系的预测模型。线性回归的目标…

Inkscape SVG 编辑器 导入 Gazebo

概述 本教程描述了拉伸 SVG 文件的过程&#xff0c;这些文件是 2D 的 图像&#xff0c;用于在 Gazebo 中为您的模型创建 3D 网格。有时是 更容易在 Inkscape 或 Illustrator 等程序中设计模型的一部分。 在开始之前&#xff0c;请确保您熟悉模型编辑器。 本教程将向您展示如…

神经网络:池化层知识点

1.CNN中池化的作用 池化层的作用是对感受野内的特征进行选择&#xff0c;提取区域内最具代表性的特征&#xff0c;能够有效地减少输出特征数量&#xff0c;进而减少模型参数量。按操作类型通常分为最大池化(Max Pooling)、平均池化(Average Pooling)和求和池化(Sum Pooling)&a…

使用STM32微控制器读取和显示DHT11温湿度传感器数据

在本文中&#xff0c;我们将介绍如何使用STM32微控制器读取和显示DHT11温湿度传感器的数据。我们将使用C语言和STM32的库函数来实现这个功能。本文包含硬件连接和软件编程两个方面的内容。 硬件连接 首先&#xff0c;我们需要将DHT11温湿度传感器连接到STM32微控制器上。DHT11…

基于ASF-YOLO融合空间特征和尺度特征的新型注意力尺度序列融合模型开发构建涵洞隧道场景下墙壁建筑缺陷分割检测系统

在ASF-YOLO提出之初&#xff0c;我们就进行了相应的实践开发&#xff0c;感兴趣的话可以自行移步阅读&#xff1a; 《基于ASF-YOLO融合空间特征和尺度特征的新型注意力尺度序列融合模型开发构建医学场景下细胞分割检测识别系统&#xff0c;以【BCC、DSB2018数据集为基准】》 …

性能压力测试--确保企业数字化业务稳健运行

随着企业的数字化转型和依赖云计算的普及&#xff0c;软件系统的性能已经成为企业成功运营的关键因素之一。性能压力测试作为确保系统在各种条件下都能高效运行的关键步骤&#xff0c;对企业的重要性不可忽视。以下是性能压力测试对企业的几个重要方面的影响和作用&#xff1a;…

行为型设计模式(二)责任链模式 策略模式

责任链模式 Chain of Responsibility 1、什么是责任链模式 责任链模式为请求创建一个接收者对象的链&#xff0c;每个接收者都包含对另一个接收者的引用。如果一个对象不能处理请求&#xff0c;它会将请求传递给链中的下一个接收者&#xff0c;如此模式下&#xff0c;请求沿着…

机器视觉工程师,我存多少钱可以躺平

钱钱钱&#xff01;还是钱&#xff01;除了钱还能聊点别的吗&#xff1f;钱可以让你生活的更好&#xff0c;也可以让你​在生活中的选择很无奈。 如果想要知道拥有多少存款才能躺平不上班&#xff0c;那么首先要明确躺平的定义。所谓的躺平&#xff0c;其实并不代表不能工作&a…

ASP.NET Core面试题之Redis高频问题

&#x1f388;&#x1f388;在.NET后端开发岗位中&#xff0c;如今也少不了、微服务、分布式、高并发高可用相关的面试题&#x1f388;&#x1f388; &#x1f44d;&#x1f44d;本文分享一些整理的Redis高频面试题&#x1f389; &#x1f44d;&#x1f44d;机会都是给有准备…

WPF——样式和控件模板、数据绑定与校验转换

样式和控件模板 合并资源字典 Style简单样式的定义和使用 ControlTemplate控件模板的定义和使用 定义 使用 Trigger触发器 数据绑定与校验转换 数据绑定的设置 代码层实现绑定 数据模板DataTemplate xml文件的读取与显示 方法的返回值作为源绑定到控件中ObjectDataProvider L…

Axure之中继器的使用(交互动作reperter属性Item属性)

目录 一.中继器的基本使用 二.中继器的动作&#xff08;增删改查&#xff09; 2.1 新增 2.2 删除 2.3 更新行 2.4 效果展示 2.5 模糊查询 三.reperter属性 在Axure中&#xff0c;中继器&#xff08;Repeater&#xff09;是一种功能强大的组件&#xff0c;用于创建重复…

ES集群G1回收器,堆空间无法被回收问题

ES堆空间不足的问题&#xff0c;困扰了我有两年的时间。dump堆去分析&#xff0c;也未能分析出来&#xff0c;堆到底是被什么占用了。 我把堆空间给了31.9G&#xff0c;这是指针压缩生效的临界值&#xff0c;如果再大就指针压缩失效了。 痛苦的是&#xff0c;随着时间的增长。堆…

【HarmonyOS开发】ArkTs关系型和非关系型数据库的存储封装

前面使用了首选项的存储方式&#xff0c;因此将其他的两种存储方式&#xff08;键值型数据库和关系型数据库&#xff09;也学习一下&#xff0c;简单记录一下&#xff0c;并进行封装&#xff0c;方便后续使用。 1、效果预览 2、使用条件 2.1 键值型数据库 键值型数据库实现数据…

linux 应用开发笔记---【线程】

1.概念&#xff1a; 线程是参与系统调度的最小单位&#xff0c;它被包含在进程中&#xff0c;是进程的实际运行单位 一个进程可以创建多个线程&#xff0c;多个线程并发运行&#xff0c;每个线程执行不同的任务 2.如何创建线程 当一个程序启动的时候&#xff0c;一个进程被…

小鹅通基于 TSE 云原生 API 网关的落地实践

导语 2023腾讯全球数字生态大会已于9月7-8日完美落幕&#xff0c;40专场活动展示了腾讯最新的前沿技术、核心产品、解决方案。 微服务与消息队列专场&#xff0c;我们邀请到了小鹅通的基础架构组负责人黄徐震为我们带来了《小鹅通基于 TSE 云原生网关的落地实践》的精彩演讲。…

TCP 核心工作机制

TCP 的核心知识&#xff1a;如何保证传输可靠 如何提高传输效率 如何保证传输可靠&#xff1a;确认应答机制 超时重传机制 如何提高传输效率&#xff1a;滑动窗口机制、流量控制机制、延时应答机制、捎带确认机制、拥塞控制机制 可靠机制 TCP的可靠性主要是通过 确认应答 …

多门店自助点餐+外卖二合一小程序系统源码:自助点餐+外卖配送 带完整搭建教程

互联网的普及和移动支付的便捷&#xff0c;餐饮行业也在经历着数字化转型。小编来给大家介绍一款多门店自助点餐外卖二合一小程序&#xff0c;带完整的搭建教程。 以下是部分代码示例&#xff1a; 系统特色功能一览&#xff1a; 1.多门店管理&#xff1a;支持一个平台管理多个…