C语言数组—二维数组

news2024/11/15 21:47:46


二维数组的创建

//数组创建
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个字节

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

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

希望大家多多注意

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

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

相关文章

超实用!免费软件站大盘点,总有一款适合你

相信用Mac电脑的同学都知道一个网站MacWK&#xff0c;可以白嫖几乎所有常用软件&#xff0c;不用付费&#xff0c;但不好的消息是在2022年10月宣布关站&#xff0c;小编从此走上了开源免费的道路&#xff0c;尽管不太好用&#xff0c;奈何口袋木有钱&#xff0c;经过小编的不断…

一个页面请求从在浏览器中输入网址到页面最终呈现

前言-与正文无关 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&#xff0c;我们往往容易陷入工作的漩涡&#xff0c;忘记了停下脚步&#xff0c;感受周围的世界。让我们一起提醒自己&#xff0c;要适时放慢脚步…

通过调整报文偏移解决CAN应用报文丢帧或周期过长问题

偏移原理 报文很多都是周期性发送的&#xff0c;但是如果每条报文都以一开始作为开始计时的时间点&#xff0c;也就是一开始就发送第一条报文&#xff0c;可能会导致CAN堵塞&#xff0c;导致丢帧或者某些报文某一时刻周期过长&#xff0c;就像下图这样&#xff0c;同一时刻CAN…

机器视觉引导的多材料3D打印

3D打印机使用机器视觉来解决困扰3D喷墨打印机的问题&#xff0c;增加了可以使用的材料范围&#xff0c;并实现了机器人手等复杂物体的快速生产。 增材制造&#xff08;也称为 3D 打印&#xff09;的进步已经产生了越来越强大的能力&#xff0c;可以生产使用传统制造工艺无法制…

CMake编译 c++源码入门教程

CMake 随着工程的越来越大&#xff0c;且需要跨平台的应用&#xff0c;Make工具也会相对麻烦。因此&#xff0c;2000年&#xff0c;由Kitware公司开发。CMake是一种跨平台的构建系统&#xff0c;它使用一种声明式的构建语言&#xff0c;允许用户通过简单的配置文件来定义项目的…

基于Andriod的连锁药店管理系统(源码|论文)

一、系统架构 前端&#xff1a;vue | uni-app 后端&#xff1a;spring | springmvc | mybatis 环境&#xff1a;jdk1.8 | mysql | maven | node 二、代码及数据库 三、功能介绍 01. 登录页 02. 管理后台-首页 03. 管理后台-个人中心-修改密码 04. 管理后台-个人中心-个…

嵌入式Linux 内核的内存管理方法

内存管理的主要工作就是对物理内存进行组织,然后对物理内存的分配和回收。但是Linux引入了虚拟地址的概念。 虚拟地址的作用 如果用户进程直接操作物理地址会有以下的坏处: 1、 用户进程可以直接操作内核对应的内存,破坏内核运行。 2、 用户进程也会破坏其他进程的运行 …

【Unity】CatlikeCoding SRP

Unity 自定义渲染管线 提示&#xff1a;基于CatlikeCoding SRP系列教程学习 学习链接&#xff1a;SRP 个人测试: Demo 相关记录以后有时间再更&#xff1a;

计算机考研|北航北理北邮怎么选?

北航985&#xff0c;北理985&#xff0c;北邮211 虽然北邮事211&#xff0c;但是北邮的计算机实力一点也不弱&#xff0c;学科评级&#xff0c;计算机是A 北航计算机评级也是A&#xff0c;北理的计算机评级是A- 所以&#xff0c;这三所学校在实力上来说&#xff0c;真的大差…

大模型知识积累——幻觉

什么是大模型幻觉 在大语言模型的文本生成场景下&#xff0c;幻觉是指一本正经的胡说八道。逻辑连贯的自然表述中&#xff0c;有理论或者事实错误&#xff0c;捏造事实等问题。 幻觉问题的危害 LLM幻觉可能产生传播错误知识的后果。对于医疗应用中结果安全和可信AI尤为重要&a…

研究揭示OpenAI GPT-3.5-Turbo模型参数量可能只有7B

加利福尼亚州&#xff0c;洛杉矶 - 一项由南加州大学计算机科学系的研究人员进行的新研究&#xff0c;通过创新的数学方法&#xff0c;对OpenAI公司的最新语言模型GPT-3.5-Turbo的内部结构进行了深入分析。研究团队通过一系列精心设计的“暴力提问”实验&#xff0c;成功地估计…

【全网最详细】ComfyUI下,Insightface安装指南-聚梦小课堂

&#x1f96e;背景 ComfyUI下使用IP-adapter下的faceID模型的时候&#xff0c;大家可能会遇到如下错误&#xff1a; Error occurred when executing InsightFaceLoader: No module named insightface File "F:\ComfyUI-aki\execution.py", line 151, in recursive_…

【四】常用数据层技术高可用方案1

常用数据层技术高可用方案 简介 做架构设计我们都要面临系统的三高问题&#xff0c;系统的三高是指高并发、高性能、高可用&#xff0c;这些是系统架构设计中的重要指标。 高并发是指系统能够同时处理大量请求的能力。每次设计架构我们都需要根据业务体量来估算系统需要具备的并…

可视化场景(5):生产监控,比摄像头好用多了。

hello&#xff0c;我是贝格前端工场&#xff0c;本期分享可视化大屏在生产监控场景的应用&#xff0c;如需要定制&#xff0c;可以与我们联络&#xff0c;开始了。 实时监控 可视化大屏可以实时展示生产线上的各种关键指标和数据&#xff0c;如生产速度、设备状态、产量、质量…

PHP反序列化--引用

一、引用的理解&#xff1a; 引用就是给予一个变量一个恒定的别名。 int a 10; int b &a; a 20; cout<<a<<b<<endl; 输出结果 : a20、b20 二、靶场复现&#xff1a; <?php highlight_file(__FILE__); error_reporting(0); include("flag.p…

test测试类-变量学习

test测试类 作用&#xff1a;标记到类上成为测试类&#xff0c;标记到方法上成为测试方法 变量&#xff1a;测试类的变量&#xff0c;在测试类括号中应用 1、invocationCount变量 意思是这个方法应该被调用的次数。 在测试框架中&#xff0c;特别是当使用参数化测试或数据驱动…

最新WordPress网址导航设计师主题风格网站源码

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 最新WordPress精品网址导航主题整站源码WAP端修复tab标签ajax加载模式会显示未审核的网址的bug小屏幕热搜采用水平滚动优化子主题支持添加文章分页 二、效果展示 1.部分代码 代码如…

SpringBoot(拦截器+文件上传)

文章目录 1.拦截器1.基本介绍2.应用实例1.去掉Thymeleaf案例中使用session进行权限验证的部分2.编写自定义拦截器 LoginInterceptor.java 实现HandlerInterceptor接口的三个方法3.注册拦截器1.第一种方式 配置类直接实现WebMvcConfigurer接口&#xff0c;重写addInterceptors方…

本地知识库的底层逻辑是什么?为什么企业需要它?

如果我们将企业比作一座繁华的城市&#xff0c;那么信息就像是城市的建筑&#xff0c;知识库则是城市的地图。知识库不仅可以帮我们存储整理和搜寻信息&#xff0c;而且还可以为我们提供信息的结构以便我们能够更好地理解和利用这些信息。今天&#xff0c;我们要探讨的就是这个…

一维坐标的移动(bfs)

在一个长度为n的坐标轴上&#xff0c;小S想从A点移动B点。 他的移动规则如下&#xff1a; 向前一步&#xff0c;坐标增加1。 向后一步&#xff0c;坐标减少1。 跳跃一步&#xff0c;使得坐标乘2。 小S不能移动到坐标小于0或大于n的位置。 小S想知道从A点移动到B点的最少步数是多…