C语言数组—二维数组


二维数组的创建

//数组创建
int arr[3][4];
//三行四列,存放整型变量
double arr[2][4];

二维数组的初始化

我们如果这样初始化,效果是什么样的呢

int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };

image-20240318212310793

那如果我们不写满十二个呢

int arr[3][4] = { 1,2,3,4,5,6,7};

image-20240318212428608

不完全初始化,后面默认补0

那我们如何按行初始化呢?
int arr[3][4] = {{1,2},{3,4},{4,5}};

image-20240318212615781

二维数组可以省略行吗
int arr[][4] = {{1,2},{3,4},{4,5}};

image-20240318212742929

所以有几行可以根据初始化的元素来判断,但是有几列无法判断

不可以省略列数,但是可以省略行数

二维数组的使用

这里有一点需要我们注意一下,二维数组的行和列(下标)和一维数组(下标)一样,都是从0开始

所以我们只要有了行列的坐标,就可以精确找到这个数字

我们通过行和列的双重循环是不是就可以打印出二维数组中所有的元素呢

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

我们来看运行效果

image-20240318213739143

二维数组在内存中的存储

是怎么样存储的呢?

我们还是和一维数组一样,把二维数组的地址都打印下来

#include <stdio.h>
int main()
{
	int arr[3][4];
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
		}
	}
	return 0;
}

看结果

image-20240318214053529

我们注意一下就能发现,每两个数组元素之间的地址都差了4

正好是我们所储存的一个整型变量的空间

所以就说明:

二维数组在内存中也是连续存放的,换行也是连续的

那么我们在回到刚刚的问题,为什么行数可以省略,而列数不能省略呢?

因为地址存放是连续的,有几行直接往后加就行,但是我们如果不知道有几列,就不知道下一行开始时候的地址,所以就无法进行存储

那如果二维数组在内存中是连续的,我们是不是可以通过地址来打印呢?
#include <stdio.h>
int main()
{
	int arr[][4] = {{1,2},{3,4},{4,5}};
	int i = 0;
	int* p = &arr[0][0];
	for (i = 0; i < 12; i++)
	{
		printf("%d", *p);
		p++;
	}
	return 0;
}

看结果

image-20240318214928418


其实我们可以这么理解

我现在有一个二维数组

arr[3][4]

那么每一个数组名就是

arr[0] [0]arr[0] [1]arr[0] [2]arr[0] [3]
arr[1] [0]arr[1] [1]arr[1] [2]arr[1] [3]
arr[2] [0]arr[2] [1]arr[2] [2]arr[2] [3]

我们其实也可以把第一行的元素看成数组名为arr[0]的一维数组,下标为[0],[1],[2],[3]

下面几行也是

所以二维数组也可以这么理解

数组越界

数组的下标是有范围限制的。

数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。

所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。

C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就 是正确的,

所以程序员写代码时,最好自己做越界的检查。

#include <stdio.h>
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int i = 0;
    for(i=0; i<=10; i++)
   {
        printf("%d\n", arr[i]);//当i等于10的时候,越界访问了
   }
 return 0;
}

二维数组的行和列也可能存在越界。

数组作为函数参数

往往我们在写代码的时候,会将数组作为参数传个函数,比如:我要实现一个冒泡排序(这里要讲算法 思想)函数将一个整形数组排序。

int main()
{
    int arr[] = {9,8,7,6,5,4,3,2,1,0};
    //排序为升序
    return 0;
}

好的,那么我们开始写一下冒泡排序

bubble_sort(int arr[])
{
    
}
int main()
{
    int arr[] = {9,8,7,6,5,4,3,2,1,0};
    bubble_sort(arr);
    return 0;
}

什么是冒泡排序呢?

思想:

两两相邻的元素进行比较,并且可能的话需要交换

9 8 7 6 5 4 3 2 1 0

8 9 7 6 5 4 3 2 1 0

8 7 9 6 5 4 3 2 1 0

8 7 6 5 4 3 2 1 0 9

一趟冒泡排序后,有一个数字一定来到他最终应该在的位置上

一趟解决一个数组

8 7 6 5 4 3 2 1 0 9

7 8 6 5 4 3 2 1 0 9

7 6 8 5 4 3 2 1 0 9

7 6 5 4 3 2 1 0 8 9

十个数字就需要就趟排序,n个数字就需要n-1趟排序


所以我们来写函数

bubble_sort(int arr[])
{
    //计算数组元素个数
    int sz = sizeof(arr)/sizeof(arr[0]);
    //确定趟数
    int i = 0;
    for(i = 0, i< sz - 1, i++)
        //这里的sz - 1就是循环的趟数
    {
        //一趟冒泡排序的过程
        int j = 0;
        for(j=0; j<sz-i-1; j++)
            //这里的sz-i-1就是每一次比较的个数,每次循环都会把一个数字放在正确的位置,那么我们只需要比较前面的数字就行
       {
            if(arr[j] > arr[j+1])
           {
                int tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
    }
}//这就是冒泡排序

我们来看运行

image-20240318223112452

好的我们看到,在这里已经出现问题了,我们在传参的时候并没有传递完整数组

问题出在哪呢?
bubble_sort(int arr[])//arr的本质是指针

int sz = sizeof(arr)/sizeof(arr[0]);//那sizeof(arr)应该是4个字节

bubble_sort(arr);//数组在传参的时候,传递的其实是数组首元素的地址

所以,我们应该在函数外面计算数组的长度,作为参数传递进函数

#include <stdio.h>
bubble_sort(int arr[],int sz)
{
    //确定趟数
    int i = 0;
    for (i = 0; i < sz - 1; i++)//这里的sz - 1就是循环的趟数
    {
        //一趟冒泡排序的过程
        int j = 0;
        for (j = 0; j < sz - i - 1; j++)
            //这里的sz-i-1就是每一次比较的个数,每次循环都会把一个数字放在正确的位置,那么我们只需要比较前面的数字就行
        {
            if (arr[j] > arr[j + 1])
            {
                int tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
            }
        }//这就是冒泡排序
    }
}

int main()
{
    int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
    //计算数组元素个数
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr,sz);
    return 0;
}

image-20240318223639076

image-20240318223656100

成功!

还有几个问题值得探讨一下

数组名是什么?

数组名是数组首元素的地址

但是有两个例外

  1. sizeof(数组名) 数组名表示数组 计算的是整个数组的大小
  2. &数组名 数组名表示的是整个数组 取出的是整个数组的地址
int main()
{
    int arr[10] = { 0 };
    int sz = sizeof(arr);
    printf("%p\n", &arr);
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    printf("%d\n", sz);
    return 0;
}

image-20240318224217865

最后一个很好理解,为什么前三个地址都相同呢?

首先,数组名就是首元素地址,所以第二行和第三行相同是没错的

但是第一行,&arr取出的实际上是数组的地址

只是数组的地址和数组首元素的地址是相同的

怎么去理解呢?
int main()
{
    int arr[10] = { 0 };
    int sz = sizeof(arr);
    printf("%p\n", &arr);
    printf("%p\n", &arr + 1);
    printf("%p\n", arr);
    printf("%p\n", arr + 1);

    return 0;
}

image-20240318224630022

我们很明显能看出来,数组地址的下一个地址和上一个差了A8-D0,转换成10进制就是40个字节

而数组首元素的下一个地址和本身只是差了4个字节

所以说虽然他们看起来一样,但是实际上表达的含义是不一样的

所以当数组以形参传到函数内部时,是无法计算元素个数的

希望大家多多注意

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

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

相关文章

数据可信流通:从运维信任到技术信任

1.数据可信流通概念 "数据可信流通"通常指的是确保数据在不同系统、应用程序或者组织之间的传输和交换过程中的可信性、完整性和安全性。在数据流通的过程中&#xff0c;确保数据的真实性、完整性和保密性是非常重要的&#xff0c;尤其是涉及到敏感信息或者重要数据…

Day21:实现退出功能、开发账号设置、检查登录状态

实现退出功能 将登录凭证修改为失效状态。跳转至网站首页。 数据访问层 不用写了&#xff0c;已经有了updateStatus方法&#xff1b; 业务层 UserService public void logout(String ticket) {loginTicketMapper.updateStatus(ticket, 1);}Controller层 RequestMapping(p…

glib交叉编译

Glib交叉编译 逸一时&#xff0c;误一世。 —— 田所浩二「夏夜银梦」 交叉编译 GLib 涉及到在一个平台上生成能够在另一个平台上运行的目标文件。在这种情况下&#xff0c;我们将会在一台主机&#xff08;通常是开发机器&#xff09;上使用交叉编译工具链来构建 GLib 库&#…

Linux:git的基础操作

git的下载 版本控制系统一般分为两种&#xff0c;集中式版本控制系统&#xff0c;分布式版本控制系统 什么是集中式版本控制系统&#xff1a;版本库集中存放在中央服务器&#xff0c;工作时候使用自己的电脑&#xff0c;当工作时候在中央服务器上拉取最新版本的代码&#xff0c…

微服务:高并发带来的问题的容错方案

1.相关脚本&#xff08;陈天狼&#xff09; 启动nacos客户端&#xff1a; startup.cmd -m standalone 启动sentinel控制台&#xff1a; # 直接使⽤jar命令启动项⽬(控制台本身是⼀个SpringBoot项⽬) java -Dserver.port8080 -Dcsp.sentinel.dashboard.serverlocalhost:808…

【渗透测试实战】用渗透实例sqllibs第46关来讲解SQL报错注入的操作顺序

1、查出库名&#xff08;database()&#xff09; http://127.0.0.1/sqli7/Less-46/?sortupdatexml(1,if(12,1,concat(0x7e,database(),0x7e)),1) 2、通过库名&#xff0c;查表名&#xff08;table_name&#xff09; http://127.0.0.1/sqli7/Less-46/?sortupdatexml(1,if(12…

VMware虚拟机和主机之间无法复制粘贴,移动文件,重新安装vmware-tools变灰,VMware Tools继续运行脚本未能在虚拟机中成功运行。

起初&#xff0c;虚拟机只是无法和主机之间进行复制粘贴&#xff0c;移动文件。查询了很多资料,反反复复地安装卸载vmware-tools&#xff0c;但是都没有成功。通过这篇文章&#xff1a;虚拟机安装VMware Tools的两种方法_vmware tools有3种安装方式-CSDN博客 安装了vmware_too…

中国巨型地下中微子实验室准备探究宇宙奥秘

JUNO设施将于今年上线&#xff0c;将有助于确定哪种类型的中微子质量最高 - 这是物理学中最大的谜团之一。 中国江门地下中微子天文台&#xff08;JUNO&#xff09;的建设工作。朱诺号希望在2024年底之前探测到中微子。图片来源&#xff1a;Qiu Xinsheng/VCG via Getty 开平区…

JAVA八股day1

遇到的问题 相比于包装类型&#xff08;对象类型&#xff09;&#xff0c; 基本数据类型占用的空间往往非常小为什么说是几乎所有对象实例都存在于堆中呢&#xff1f;静态变量和成员变量、成员变量和局部变量的区别为什么浮点数运算的时候会有精度丢失的风险&#xff1f;如何解…

PHP姓名快速匿名化工具(重组脱敏)

PHP姓名重组工具(脱敏/匿名化工具) 将excel数据姓名列粘贴提交&#xff0c;得到随机姓随机中间字随机尾字的重组姓名 那些年自用瞎搞的代码&#xff0c;今日整理成网页交提交得到结果的交互功能分享。 <?php //PHP姓名重组工具(脱敏/匿名化工具) //将excel数据姓名列粘贴…

Linux TCP参数——tcp_adv_win_scale

文章目录 tcp_adv_win_scaleip-sysctl.txt解释buffering overhead内核缓存和应用缓存示例计算深入理解从2到1(tcp_adv_win_scale的值)总结 tcp_adv_win_scale adv-advise&#xff1b;win-window; 用于指示TCP中接收缓存比例的值。 static inline int tcp_win_from_space(int …

蓝桥杯-Python组(一)

1. 冒泡排序 算法步骤&#xff1a; 比较相邻元素&#xff0c;如果第一个大于第二个则交换从左往右遍历一遍&#xff0c;重复第一步&#xff0c;可以保证最大的元素在最后面重复上述操作&#xff0c;可以得到第二大、第三大、… n int(input()) a list(map(int, input()…

java实现kml文件下载接口

根据业务需求&#xff0c;需提供一个下载kml格式航线文件的HTTP GET接口 示例代码 RequestMapping(value "/getFlyingPathFile/{uavTypeId}/{flyingPathId}.kml", method RequestMethod.GET, produces "application/vnd.google-earth.kmlxml") Respons…

轻松打造完美原型:9款在线工具推荐

早年&#xff0c;UI设计师选择的工具有限&#xff0c;功能相对单一&#xff0c;大多数在线原型设计工具都是国外的&#xff0c;语言和网络都增加了设计工作的负担。如今&#xff0c;国内外有许多在线原型设计工具&#xff0c;不仅可以在浏览器上使用&#xff0c;而且还具有团队…

wsl or 虚拟机 安装

1.wsl2安装 WSL全称Windows Subsystem for Linux&#xff0c;是微软开发的适用于Linux的Windows子系统 如今已经有两代了&#xff1a; 所以用的多的还是wsl2。 安装前需要先去设置启用或关闭Windows功能&#xff1a; 打开适用于linux的子系统和虚拟机平台。 Microsoft Store里…

论文阅读——MoCo

Momentum Contrast for Unsupervised Visual Representation Learning 动量在数学上理解为加权移动平均&#xff1a; yt-1是上一时刻输出&#xff0c;xt是当前时刻输入&#xff0c;m是动量&#xff0c;不想让当前时刻输出只依赖于当前时刻的输入&#xff0c;m很大时&#xff0…

小程序搜索排名优化二三事

小程序的优化主要是排名优化和性能优化两个版块。性能优化这方面主要靠开发者自己完善&#xff0c;我们团队提供的服务就是把产品的排名打上去&#xff0c;获得更多的自然流量&#xff0c;实现盈利。 如何提升小程序的搜索排名主要从如下几个方面出发&#xff1a; 首先要知道…

二蛋赠书十八期:《一本书讲透Elasticsearch:原理、进阶与工程实践》

Elasticsearch 是一种强大的搜索和分析引擎&#xff0c;被广泛用于各种应用中&#xff0c;以其强大的全文搜索能力而著称。 不过&#xff0c;在日常管理 Elasticsearch 时&#xff0c;我们经常需要对索引进行保护&#xff0c;以防止数据被意外修改或删除&#xff0c;特别是在进…

【数据结构与算法】:非递归实现快速排序、归并排序

&#x1f525;个人主页&#xff1a; Quitecoder &#x1f525;专栏&#xff1a;数据结构与算法 上篇文章我们详细讲解了递归版本的快速排序&#xff0c;本篇我们来探究非递归实现快速排序和归并排序 目录 1.非递归实现快速排序1.1 提取单趟排序1.2 用栈实现的具体思路1.3 代码…

PHP反序列化---字符串逃逸(增加/减少)

一、PHP反序列化逃逸--增加&#xff1a; 首先分析源码&#xff1a; <?php highlight_file(__FILE__); error_reporting(0); class A{public $v1 ls;public $v2 123;public function __construct($arga,$argc){$this->v1 $arga;$this->v2 $argc;} } $a $_GET[v…