【C数组】详解数组

news2024/11/23 13:15:41

数组

  • 前言
  • 一、一维数组的创建和初始化
    • (一)数组的创建
      • 1.数组的概念和创建方式
      • 2.变长数组
    • (二)数组的初始化
    • (三)一维数组的使用
    • (四)一维数组在内存中的存储
  • 二、二维数组的创建和初始化
    • (一)二维数组的创建
    • (二)二维数组的初始化
    • (三)二维数组的使用
    • (四)二维数组在内存中的存储
      • 1.存储方式
      • 2.小知识
  • 三、数组越界
    • (一)概念
    • (二)拓展知识
      • 1.题目描述:
      • 2.解释
        • (1)代码
        • (2)简单解析
        • (3)完整解析
  • 四、数组作为函数参数
    • (一)传参
    • (二)数组名
  • 五、数组实例
    • (一)三子棋
    • (二)扫雷
  • 总结


前言

数组在C语言中是很重要的,大家需要有前面函数知识的基础才能学好数组,数组分为一维数组、二维数组,在C语言中存储是十分重要的,所以大家需要仔细看看下面的内容,牢牢掌握数组。


一、一维数组的创建和初始化

(一)数组的创建

1.数组的概念和创建方式

概念:数组是一组相同类型元素的集合。
在这里插入图片描述

2.变长数组

在这里插入图片描述
在这里插入图片描述

解释:数组创建,在C99标准之前,[]中要给一个常量才可以运行,不能使用变量。在C99标准支持了变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化(在Linux编译器底下是不能被初始化的,而可以使用变长数组)。而VS IDE不支持C99变长数组,所以报错。

(二)数组的初始化

#include<stdio.h>

int main() {

	//创建的同时给数组一些值,这叫做初始化
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };//完全初始化
	int arr2[10] = { 1,2,3 }; //不完全初始化,剩余的元素默认初始化为0
	int arr3[] = { 1,2,3,4,5 }; //没有指定数组元素个数,编译器会根据初始化的内容来确定数组的元素个数

	int arr4[] = { 1,2,3 };  //3个元素
	int arr5[10] = { 1,2,3 }; //10个元素

	char arr6[3] = { 'a','b','c' };
	char arr7[] = { 'a','b','c' };

	char arr8[10] = "abc"; //'a' 'b' 'c' '\0' 10个元素
	char arr9[] = "abc";   //'a' 'b' 'c' '\0' 4个元素
	
	char arr10[] = "abcd";  //5个元素 'a' 'b' 'c' 'd' '\0'
	char arr11[] = { 'a','b','c','d' }; //4个元素 'a' 'b' 'c' 'd'
	printf("%s\n", arr10);
	printf("%s\n", arr11);
	
	int arr12[10]; //不初始化默认放的都是0
	
	return 0;
}

如下图,完全初始化和不完全初始化数组的对比:
在这里插入图片描述

如下图,不给元素个数而初始化自动填充元素个数,arr3:
在这里插入图片描述

如下图,arr4和arr5初始化的值相同而元素个数的不同:
在这里插入图片描述
如下图,arr6和arr7是一样的:
在这里插入图片描述

如下图,arr88和arr9初始化的值相同而元素个数的不同:
在这里插入图片描述

如下图,arr10与arr11的区别至关重要,这是由于指针从a这个元素往后找一直找到\0才肯罢休,arr10数组后面默认有个\0,这是编译器默认的规矩,所以那个指针找到\0了,统计有五个元素就完了,可是arr11这个数组后面没有\0,编译器找不到啊,那咋办,输出一堆随机值,那这些随机值是什么呢?在函数栈帧的创建于销毁中我们已经看到过了,就是cc cc cc cc这个乱码。
函数栈帧的创建与销毁
在这里插入图片描述

(三)一维数组的使用

对于数组的使用我们之前介绍了一个操作符:[],下标引用操作符。它其实就是数组访问的操作符,如下代码:

//1.数组是有下标的,下标是从0开始的
//2.[]下标访问操作符
//3.数组的大小可以通过计算得到

int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//按照顺序打印数组
	int sz = sizeof(arr) / sizeof(arr[0]); //算总字节长度除以第一个字节的长度就是数组的元素个数
	int i = 0;
	//正序打印
	for (i = 0; i < sz; i++) {
		printf("%d ", arr[i]);  
	}
	printf("\n");

	//倒序打印
	for (i = sz - 1; i >= 0; i--) {
		printf("%d ", arr[i]);
	}
	printf("\n");

	//奇数打印
	for (i = 0; i < sz - 1; i += 2) {
		printf("%d ", arr[i]);
	}
	printf("\n");

	return 0;
}

(四)一维数组在内存中的存储

在这里插入图片描述
在这里插入图片描述

大家看到这个地址是每一个都差4的,不由想到int占4个字节,由此推出两个结论:
结论1:一维数组在内存中是连续存放的
结论2:随着数组下标的增长,地址是由低到高变化的

所以是不是只需要你知道第一个元素的地址,就可以找到之后的所有地址并找到它的值了,这是不是和指针有一定的联系,可以用指针指向第一块的空间并往后查找并打印,上代码试一试:

#include<stdio.h>

int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//按照顺序打印数组
	int sz = sizeof(arr) / sizeof(arr[0]); //算总字节长度除以第一个字节的长度就是数组的元素个数
	int i = 0;
	/*for (i = 0; i < sz; i++) {
		printf("%d ", arr[i]);
	}*/
	正序打印
	//for (i = 0; i < sz; i++) {
	//	printf("&arr[%d]=%p\n", i, &arr[i]);
	//}
	//printf("\n");

	int* p = &arr[0];
	for (i = 0; i < sz; i++) {
		printf("%d ", *(p + i));
	}

	return 0;
}


二、二维数组的创建和初始化

(一)二维数组的创建

与一维数组大致相同,如下图:
在这里插入图片描述

(二)二维数组的初始化

先上代码再分析:

#include<stdio.h>

int main() {
	int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 }; //表示三行四列
	int arr1[3][4] = { 1,2,3,4,5 }; //不完全初始化,后面未初始化默认赋0
	int arr2[3][4] = { {1,2},{3,4},{5,6} }; //按照自己心意给不同地方赋值
	//二维数组的行可以省略,但是列不可以省略
	int arr3[][4] = { 1,2,3,4,5,6,7,8,9 };

	return 0;
}

在这里插入图片描述
这里有个小知识点:
二维数组的行是可以省略的,但是列是千万不能省略的,为什么呢?因为当二维数组是先是横着一个个往后放,到末尾了,列告诉你,到头了,不要再放了,然后就换了个行,继续放,所以列是关键,列告诉你可以放或者放到底了不能再放了,所以行可以省略而列不能省略。

(三)二维数组的使用

只需锁定它的行和列找到并打印出即可:
在这里插入图片描述
在这里插入图片描述

(四)二维数组在内存中的存储

1.存储方式

二维数组在内存中是连续存放的,我们只需要将一个二维数组转换成n个一维数组即可。

在这里插入图片描述

为了更好的理解二维数组是连续存放的,接下来上个指针的代码,指针是加1跳过4个字节(在int 类型当中),供大家思考一下:

#include<stdio.h>

int main() {
	int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	int i = 0;
	for (i = 0; i < 3; i++) {
		int j = 0;
		for (j = 0; j < 4; j++) {
			printf("%d ", arr[i][j]);
		}
	}
	printf("\n");

	int* p = &arr[0][0];
	int k = 0;
	for (k = 0; k < 12; k++) {
		printf("%d ", *(p + k));
	}

	return 0;
}

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

2.小知识

其实二维数组是一维数组的数组,是存放n个一维数组的数组。
在这里插入图片描述
利用sizeof关键字就能推断出来二维数组的大小(总共有多少个元素):

	int row = sizeof(arr) / sizeof(arr[0]); //算行有多少
	int col = sizeof(arr[0]) / sizeof(arr[0][0]); //算列有多少
	int sum = row * col; //算总共多少个元素

在这里插入图片描述

三、数组越界

(一)概念

数组的下标是有范围限制的。
数组的下标是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。所以数组的下标如果小于1,或者大于n-1,就是数组的越界访问了,超出了合法空间的访问。而C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以我们在进行编译的时候,要检查一下有没有越界。
在这里插入图片描述

(二)拓展知识

在大厂面试的时候,有道题目看起来很简单,但是解释起来很复杂,其实不需要那么难的解释,接下来,让我细细来讲一下:

1.题目描述:

在这里插入图片描述

2.解释

(1)代码

代码如下:

#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 <= 12; i++) {
		printf("Hello World\n");
		arr[i] = 0;
	}
	return 0;
}

(2)简单解析

在新版2022的VS IDE下运行结果是没问题,调试的过程中也不会像老版2013VS IDE一样会死循环i在运行到12的时候i的值会变成0重新进入循环,此时取地址i与取地址arr[12]是一样的,而新版VS IDE只会出现异常提醒,i的值不会从12变成0。
在这里插入图片描述

局部变量是放在内存中的栈区的,栈区的使用习惯是先使用高地址处的空间,再使用低地址处的空间。
在这里插入图片描述
在这里插入图片描述

(3)完整解析

在老版2013的VS IDE中如果越界超过2个元素,那么&i与&arr[12]两者地址是一样的,所以当循环到12时,i自动变为0,从头开始循环了,而最新版的VS IDE中解决了这个问题,只是报出警告。
同样,这个小问题在其他编译器上也会出现,但是看溢出的元素的个数而定的,就比如Linux编译器上是不能溢出的,是只要你有一个元素溢出都会产生死循环。
在这里插入图片描述

四、数组作为函数参数

(一)传参

先来一个冒泡排序,进行理解一下:
在这里插入图片描述

//选择排序,冒泡排序,插入排序
//冒泡排序思想
//两两相邻元素进行比较

#include<stdio.h>

//Void Sort(int* arr, int sz) //本质
void Sort(int arr[], int sz) {
	//int n = sizeof(arr)/sizeof(arr[0]);  //n的值为1
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++) {
		//一趟冒泡排序,决定了进行多少对比较
		int j = 0;
		for (j = 0; j < sz - i - 1; j++) {
			if (arr[j] > arr[j + 1]) {
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}


int main() {
	int arr[] = { 3,1,4,2,9,8,6,7,0,5 };
	int sz = sizeof(arr) / sizeof(arr[0]);//sz的值为10
	//写一个函数对数组进行排序
	Sort(arr, sz);  
	//打印
	int i = 0;
	for (i = 0; i < sz; i++) {
		printf("%d ", arr[i]);
	}

	return 0;
}

(二)数组名

大家需要先知道的是数组名是一个地址,但到底是谁的地址呢?数组名是首元素的地址。
但是有两个例外:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
2.&数组名,这里的数组名表示整个数组,&数组名取出的是数组的地址。但是取地址和首元素取地址是一样的。而往后+1就差别巨大,&arr+1是跳过整个数组,&arr+1是跳过一个int型的字节。
&arr地址输出的是首元素地址,arr地址输出的是首元素地址,&arr[0]地址输出的是首元素地址,而进行加1,往后找元素的时候大不相同,&arr是取的一整个数组,加1是代表整个数组跳过了,而&arr[0]与arr取的是数组的首元素,往后加一是跳过一个元素,也就是int类型的四个字节。

在这里插入图片描述

所以大家可以想到为什么前面所讲的冒泡排序中的n为1,而不是我们想要的数组元素,因为在X86(32位)机器下,int* 是占4个字节的,而底下Sort把arr传参传的是指针,是arr数组的首元素的地址,所以在Sort函数内部的n是1。
指针的字节长度是取决于编译器是几位的,具体可以看一下下面的博客:【C函数】初识函数

在这里插入图片描述
当进行传参的时候,只把数组首元素地址传参上去,上面的数组知道了这个首元素地址以后可以往后找原数组中的其他元素,这对于节省空间和时间层面都是十分重要的。

五、数组实例

(一)三子棋

三子棋的创建,让大家能够很轻松就了解数组之间的关系,如下博客:
三子棋

(二)扫雷

了解了扫雷,对于数组的理解会有质的飞跃,大家可以看下面博客:
初阶扫雷


总结

这篇分享,我们学习到了关于数组的知识,知道了数组的底层逻辑,学习到了很多不一样的小知识,这在以后的学习当中是受益匪浅的,在学习数组的过程中我们详细知道了一维数组和二维数组的知识,也同样经过一个大厂面试题使大家了解到了数组越界的危险,最重要的是大家了解到了数组作为函数进行传参,这个是十分关键的,对于后续指针的学习是很有利的,以及对于理解内存是很关键的。


客官,码字不易,来个三连支持一下吧~~~

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

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

相关文章

rabbitmq基础7——队列和消息过期时间设置、死信队列、延迟队列、优先级队列、回调队列、惰性队列

文章目录一、过期时间1.1 针对队列设置1.2 针对消息设置二、死信队列2.1 死信交换器2.2 死信队列原理2.3 延迟队列&#xff08;特殊用法&#xff09;三、优先级队列3.1 监控页面创建优先级队列3.2 监控页面创建优先级消息四、回调队列4.1 RPC的定义4.2 PRC工作机制4.3 监控页面…

java本地socket服务端暴露至公网访问【内网穿透】

Java 服务端demo环境 jdk1.8 框架:springbootmaven 开发工具:IDEA 在pom文件引入第三包封装的netty框架maven坐标 <dependency><groupId>io.github.fzdwx</groupId><artifactId>sky-http-springboot-starter</artifactId><version>0.…

叮叮当~~叮叮当~~|您有一份白玉兰酒店圣诞节豪礼等待抱走!

不知不觉2022年已经临近尾声 全国各地都已经放开了 相信有很多小伙伴在这一年 都没有好好的出来浪一浪 在即将到来的圣诞节 各地的圣诞玩乐都已经齐齐亮相 同时 白玉兰酒店客房 也已迎来了圣诞系列主题 是时候计划一场完美的圣诞之旅了 兰小姐为您准备了丰富多彩的圣…

【苹果家庭群发推送】软件安装Apple推送是一种基于IMESSAGE平台的新信息推送功效的营销软件

推荐内容IMESSGAE相关 作者推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者推荐内容3.日历推 *** 点击即可查看作者要求内容信息作者推荐…

DevOps-7:Jenkins API介绍

前言&#xff1a; 为什么要使用Jenkins的API&#xff1f; 我在使用Jenkins的过程中&#xff0c;觉得Jenkins的UI还是有不少问题的&#xff1a; UI性能差&#xff0c;尤其是有一些任务在构建中时&#xff0c;UI非常卡顿&#xff0c;等个十来秒都正常&#xff0c;极端时甚至会崩…

LeetCode 221. 最大正方形

LeetCode 221. 最大正方形 在一个由 0 和 1 组成的二维矩阵内&#xff0c;找到只包含 1 的最大正方形&#xff0c;并返回其面积。 示例 1&#xff1a; 输入&#xff1a;matrix [["1","0","1","0","0"],["1",&quo…

【OpenCV-Python】教程:8-1 图像去噪 Image Denoising

OpenCV Python 图像去噪 Image Denoising 【目标】 非局部均值去噪算法去除图像中的噪声。 cv2.fastNlMeansDenoising() , cv2.fastNlMeansDenoisingColored() etc. 【理论】 在前面的章节中&#xff0c;我们已经看到了许多图像平滑技术&#xff0c;如高斯模糊&#xff0c…

1、MYSQL基础(DDL DML DCL)

&#xff08;1&#xff09;关于字段修改 change和modify的异同&#xff1a; 同&#xff1a;可以修改表的定义 异&#xff1a;change需要写两次列名&#xff0c;不方便&#xff0c;但是change可以修改表名&#xff0c;modify不可 &#xff08;2&#xff09;多表更新&#xff…

店铺如何快速实现数字化管理?不妨参考一下管理系统

百数店铺管理系统主要是以门店管理为核心&#xff0c;该应用管理涵盖商品、订单、库存、客户、采购、财务、营销等功能体系&#xff0c;维度数据分析&#xff0c;智能指导门店经营&#xff0c;账目清晰一目了然&#xff0c;店铺经营更高效。 1、销售看板 该分析报表里通过销售…

手把手教你玩转 Excel 数据透视表

1. 什么是数据透视表 数据透视表是一种可以快速汇总、分析大量数据表格的交互式分析工具。使用数据透视表可以按照数据表格的不同字段从多个角度进行透视&#xff0c;并建立交叉表格&#xff0c;用以查看数据表格不同层面的汇总信息、分析结果以及摘要数据。 使用数据透视表…

【Vue + Koa 前后端分离项目实战6】使用开源框架==>快速搭建后台管理系统 -- part6 前端实现期刊列表管理【增删查改】

要把努力当成一种习惯&#xff0c;而不是一时热血。 对应后端部分章节回顾&#xff1a; 【Vue Koa 前后端分离项目实战4】使用开源框架&#xff1e;快速搭建后台管理系统 -- part4 后端实现【增删改查】功能_小白Rachel的博客-CSDN博客 目录 一、前端项目准备 1.运行项目 …

支持百问网T113 D1-H D1s V853 V851s 等开发板 使用 Tina Linux NOR Flash文件系统 开发指南

此文章内容适用于 百问网T113 D1-H D1s V853 V851s 等开发板&#xff0c;开发板详情请访问 www.100ask.net 。 1 简介 编写目的 此文档描述Sunxi NOR 模块的使用方法&#xff0c;为相关人员调试提供指导 适用范围 boot0: 适用于brandy-2.0u-boot: 适用于u-boot-2018kernel: …

记录内值排序

记录内值排序 【问题】 could anyone please suggest a way to accomplish this. i have a table which consists of six columns : Table name : orders num1 number, num2 number , num3 number , num4 number , num5 number , num6 number there is a routine which fi…

修改后的代码只进行了git add操作不小心给他恢复了怎么找回来

一份干净的代码在main.js里加了一行console.log(666)&#xff0c;并且只进行了git add 然后不小心给他reset了&#xff01; git reset --hard哦豁&#xff0c;没了&#xff1f; 别急一样可以恢复&#xff0c;我们先执行 git fsck --lost-found然后我们去项目的.git下找到这个…

初级软件测试面试会问什么 除了常见问题,技术题也是重点

众所周知&#xff0c;面试是我们进入一个公司的门槛&#xff0c;面试者只有通过了面试才能进入公司&#xff0c;因此&#xff0c;很多新手测试人就想要知道&#xff0c;自己去面试初级软件测试的岗位&#xff0c;HR们都会问些什么样的问题&#xff1f;自己可以从哪些方面做准备…

多线程顺序运行的 4 种方法

1、在子线程中通过join()方法指定顺序 通过join()方法使当前线程“阻塞”&#xff0c;等待指定线程执行完毕后继续执行。 举例&#xff1a;在线程thread2中&#xff0c;加上一句thread1.join()&#xff0c;其意义在于&#xff0c;当前线程2运行到此行代码时会进入阻塞状态&…

FineReport填报报表常用属性方法

1、去除填报页面选中单元格时的黑色边框 // 加载结束事件 _g().curLGP.hideSelectFrame(); 2、 获取单元格焦点 预览填报报表时&#xff0c;希望页面加载完成后&#xff0c;自动将光标定位在某个控件中&#xff0c;可以直接编辑。 // 获取A2单元格 var cell _g().curLGP.getT…

风控模型算法

目录1 蚂蚁金服2 陆金所3 京东金融4 苏宁金融5 百度金融6 腾讯理财通7 宜信8 钱大掌柜9 万达金融10 网易理财11 美团金融主要是整理目前市面上的风控模型以及风控算法。1 蚂蚁金服 &#xff08;1&#xff09;对接第三方征信公司芝麻信用分&#xff0c;通过用户信用历史、行为偏…

echarts的xAxis和yAxis——x轴y轴以及网格线的详细配置

先看一下xAxis和yAxis配置的图表效果 下图详细的标注了图表中x轴y轴可见的内容 说明一下&#xff1a; x轴y轴在echarts配置项里&#xff0c;从内容上来说大体上没有太大区别&#xff0c;x轴能用的配置项y轴基本也可以用。 通过配置xAxis和yAxis可实现内容 坐标轴箭头的样式&…

Python量化交易01——构建基础策略

参考书目:深入浅出Python量化交易实战 量化交易是很早就想开的栏目了&#xff0c;之前没时间。现在正好放寒假&#xff0c;然后也找到了一本合适的书可以进行学习。 本次第一章就介绍一下简单的量化流程和一个简单的策略。 量化交易顾名思义就是用代码去验证交易策略是否赚钱…