首页 > 其他分享 >数组与地址,数组名到底是什么?

数组与地址,数组名到底是什么?

时间:2023-09-07 13:33:05浏览次数:30  
标签:arr int 地址 len 数组名 数组 sizeof

(数组与地址,数组名到底是什么?


1.问题引出

案例:设计一个函数,可以将整形数组的次序调换 例如:arr[5] = {1,2,3,4,5},输出形式为:arr[5] = {5,4,3,2,1}.

案例代码:

//能否可以正常排序?
#include <stdio.h>
void reverse(int* arr)
{
	int len = sizeof(arr) / sizeof(arr[0]);
	int top = 0;
	int tail = len - 1;
	while (top < tail)
	{
		int tmp = 0;
		tmp = arr[top];
		arr[top] = arr[tail];
		arr[tail] = tmp;
		top++;
		tail--;
	}
}
int main()
{
	int arr[] = { 1,2,3,4,5 };
	int len = sizeof(arr) / sizeof(arr[0]);
	reverse(arr);
	for (int i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

我们来运行一下: 在这里插入图片描述 我们发现结果并不是和我们想象的一样输出 5 4 3 2 1 ,而是对于原数组来说没有变化,这是为什么呢?


2.分析错误代码

首先,按F10,点击调试——>窗口——>监视 在这里插入图片描述 在监视窗口中输入arr,这时是运行在主函数中,所以监控的是主函数中的arr 在这里插入图片描述 这里能够看到,arr中储存着5值

然后按F11进入函数内部,这时的监视窗口是这样:在这里插入图片描述 这里有个技巧:需要在监视中输入arr,5才能正常监视到: 在这里插入图片描述 代码再往下走,我们发现len的值为1 在这里插入图片描述 但是int len = sizeof(arr) / sizeof(arr[0])len的值应该为arr数组的长度啊,应该是5,为什么是1呢,这就需要了解数组名到底是什么


3.数组名是什么?

先探究数组名与数组元素首元素地址:

int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);    //数组名
	printf("%p\n", &arr[0]);//数组首元素地址
	return 0;
}

结果: 在这里插入图片描述

所以得出结论:数组名是数组首元素的地址 <font color="#dd0000">但是有两个例外:</font> 1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节 2.&数组名,这里的数组名表示整个数组,&数组名取出的是数组的地址

验证一下sizeof(数组名):

int main()
{
	int arr[10] = { 0 };
	printf("%d", sizeof(arr));
	return 0;
}

结果: 在这里插入图片描述 数组长度为10,int类型一个元素4个字节,所以输出40,这就说明: sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小

验证 &数组名:

int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);    //数组名
	printf("%p\n", &arr[0]);//数组首元素地址
	printf("%p\n", &arr);   //数组名取地址
	return 0;
}

结果: 在这里插入图片描述 发现这三个输出的地址都相同,它们有什么区别呢?我们再来探究一下

在这里插入图片描述

arr与·&arr[0]一样,都是指向数组首元素地址,他们的类型都是int*&arr是整个数组的地址,&arr的类型为:int(*)[10] 由于这个数组的地址由数组首元素地址开头,所以这三个地址值从表面上看起来一样,但可以从他们的指针类型去区别他们

再对比一下:

int main()
{
	int arr[10] = { 0 };
	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);
	printf("&arr:      %p\n", &arr);  
	printf("&arr+1 :   %p\n", &arr+1);
	return 0;
}

结果: 在这里插入图片描述 分析: 在这里插入图片描述 arr&arr[0]都跳四个字节,也就是数组下一个元素地址 而&arr跳过了40个字节,它跳过了整个数组 从这里的计算,也可以体会出arr&arr[0]的类型是int*,而&arr的类型是int(*)[10]


4.错误分析与修改

错误分析:

前面的内容我们知道了数组名是数组首元素地址,本质上是个指针 所以在函数中,就需要用int*去接收这个指针变量

void reverse(int* arr)
{
	int len = sizeof(arr) / sizeof(arr[0]);
	int top = 0;
	int tail = len - 1;
	while (top < tail)
	{
		int tmp = 0;
		tmp = arr[top];
		arr[top] = arr[tail];
		arr[tail] = tmp;
		top++;
		tail--;
	}
}

而在reverse内部,sizeof(arr)中的arr被判定成了指针,而不是一个数组,所以sizeof(arr)的值为4,sizeof(arr[0])也为4,所以len的值为1,而top=0tail = len-1 = 0top = tail,根本进不去下面的循环,所以数组才不会改变

修改:

因为数组作为参数,它的长度不可以在函数内部被计算出来,所以就要在主函数中把数组的长度计算出来,将数组长度作为参数传到函数中

#include <stdio.h>
void reverse(int* arr,int len)
{
	
	int top = 0;
	int tail = len - 1;
	while (top < tail)
	{
		int tmp = 0;
		tmp = arr[top];
		arr[top] = arr[tail];
		arr[tail] = tmp;
		top++;
		tail--;
	}
}
int main()
{
	int arr[] = { 1,2,3,4,5 };
	int len = sizeof(arr) / sizeof(arr[0]);
	reverse(arr,len);    //两个参数,一个是数组首地址,一个是数组长度
	for (int i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

结果正确: 在这里插入图片描述

因为我们知道数组名其实就是一个指针,所以在函数的参数列表中,可以使用int arr[]去接受,也可以用int* arr去接受收

//这两种形式都可以
void reverse(int* arr,int len);
void reverse(int arr[],int len);

5.总结

  • 1.一般情况下,数组名就是<font color="#dd0000">数组首元素的地址</font>
  • 2.有两个特殊情况:
    • sizeof(数组名),这里的数组名表示<font color="#dd0000">整个数组,计算的是整个数组的大小。</font>
    • &数组名,这里的数组名<font color="#dd0000">表示整个数组,&数组名取出的是数组的地址。</font>
  • 3.有数组作为参数传入的函数中,想要计算这个数组的长度,在函数内部做不到,需要在主函数中将数组长度计算出来,将数组长度作为参数传入函数中,这才可以在函数中使用

标签:arr,int,地址,len,数组名,数组,sizeof
From: https://blog.51cto.com/u_16237630/7396112

相关文章

  • .NET Core 在其上下文中,该请求的地址无效。
    .NETCore在其上下文中,该请求的地址无效。看了端口,发现没被占用,后来发现是IP地址变了改成正确的IP就可以了。......
  • 独享IP地址的意义和作用
    在当今数字化时代,独享IP地址正在成为越来越多企业和个人关注的话题。它是一种网络技术解决方案,为用户提供独立、专属的IP地址,与其他用户隔离开来。本文将探讨独享IP地址的意义和作用,以及它为用户带来的重要价值。首先,我们来理解独享IP的概念。传统上,许多用户在互联网上使用共享IP地......
  • day1 - 数组part01
    力扣704.二分查找思路:假如有n个数,数组下标就是0到n-1,那么第一次从n/2开始找如果这个数比目标数大,说明目标数在左边,于是从0到中间边界找。如果这个数比目标数小,说明目标数在右边,于是从中间边界+1到n-1找。为了明确中间边界是多少,举个例子: 假如数组是:0,1,3,5,6,7,8;target......
  • Modbus协议详解2:通信方式、地址规则、主从机通信状态
    首先我们要清楚:Modbus是一种串行链路上的主从协议,在通信线路上只能有一个主机存在,不会有多主机存在的情况。虽然主机只有一个,但是从机是可以有多个的。Modbus的通信过程都是由主机发起的,从机在接收到主机的请求后再进行响应,从机不会主动进行数据的发送。并且从机之间也不会互相发送......
  • npm,nrm管理源仓库地址
    npm修改源地址,使用nrm管理源仓库地址npm源地址查看与修改#查看当前源地址npmgetregistry#设为淘宝镜像npmsetregistryhttps://registry.npm.taobao.org/使用nrm便捷管理源#全局安装npminrm-g#查看版本,注意是大写Vnrm-V#查看nrm预设配置源地址nrmls......
  • 使用JavaScript计算两点经纬度之间的弧线点经纬度数组
    前言地球是一个近似于椭球体的三维物体,因此在计算两个经纬度点之间的距离时,不能简单地将其视为平面上的直线距离。相反,我们需要考虑地球的曲率,并使用球面三角法来计算两点之间的弧线距离及其中的插值点。通过本篇博客,我们将使用JavaScript来实现根据两个经纬度点返回两点之间的弧......
  • 【Leetcode刷题记录】1、统计参与通信的服务器;2、统计二叉树中好节点的数目;3、从两个
    1、统计参与通信的服务器题目:这里有一幅服务器分布图,服务器的位置标识在 m*n 的整数矩阵网格 grid 中,1表示单元格上有服务器,0表示没有。如果两台服务器位于同一行或者同一列,我们就认为它们之间可以进行通信。请你统计并返回能够与至少一台其他服务器进行通信的服务器的......
  • VMware vSphere 8.0 Update 2 下载地址(ESXi 8.0 U2 & vCenter Server 8.0 U2)
    ESXi8.0U2&vCenterServer8.0U2请访问原文链接:https://sysin.org/blog/vmware-vsphere-8-u2/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org企业级工作负载平台vSphere将云计算的优势引入本地部署工作负载。vSphere可提高性能和运维效率并加速创新。vSpher......
  • 数组转树
    constlist=[{id:1,name:'部门1',pid:0},{id:2,name:'部门1-1',pid:1},{id:3,name:'部门1-2',pid:1},{id:4,name:'部门1-1-1',pid:2},{id:5,name:'部门1-2-1',pid:3},{id:6,name:&#......
  • 【C语言进阶】指针数组 —— 数组指针
    (文章目录)......