数组(1)

news2024/11/27 0:31:27

文章目录

  • 目录
    • 1. 一维数组的创建和初始化
      • 1.1 一维数组的创建
      • 1.2 一维数组的初始化
    • 2. 一维数组的使用
    • 3. 一维数组在内存中的存储
    • 4. 二维数组的创建和初始化
      • 4.1 二维数组的创建
      • 4.2 二维数组的初始化
    • 5. 二维数组的使用
    • 6. 二维数组在内存中的存储
    • 7. 数组越界
    • 8. 数组作为函数参数
  • 附:

目录

  • 一维数组的创建和初始化
  • 一维数组的使用
  • 一维数组在内存中的存储
  • 二维数组的创建和初始化
  • 二维数组的使用
  • 二维数组在内存中的存储
  • 数组越界
  • 数组作为函数参数
  • 三子棋
  • 扫雷游戏

1. 一维数组的创建和初始化

1.1 一维数组的创建

数组是一组相同类型元素的集合。
数组的创建方式:

type_t arr_name [const_n];

type_t 是指数组的元素类型
const_n 是一个常量表达式,用来指定数组的大小

数组创建的实例:

int main()
{
	int arr1[10];
	int count = 10;
	int arr2[count];//常量表达式才可以
	//VS2019 VS2022 这样的IDE 不支持C99 中的变长数组
	
	//C99 标准之前 数组的大小只能是常量表达式
	//C99 标准中引入了:变长数组的概念,使得数组在创建的时候可以使用变量,但是这样的数组不能初始化

	return 0;
}
//gcc中就支持变长数组
#include <stdio.h>

int main()
{
	int n = 0;
	scanf("%d", &n);
	int arr[n];//局部的变量,这些局部的变量或者数组是存放在栈区,存放在栈区上的数组,如果不初始化的话,默认是随机值
	int i = 0;

	for (i = 0; i < n; i++)
	{
		arr[i] = i;
	}

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

	return 0;
}

1.2 一维数组的初始化

数组的初始化是指在创建数组的同时给数组的内容一些合理初始值(初始化)。

int main()
{
	//int arr1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//完全初始化
	//int arr2[10] = { 1, 2, 3 };//不完全初始化,剩余的元素默认都是0
	//int arr3[10] = { 0 };//不完全初始化,剩余的元素默认都是0
	//int arr4[] = { 0 };//省略数组的大小,数组必须初始化,数组的大小是根据初始化的内容来确定
	//int arr5[] = { 1, 2, 3 };
	//int arr6[];//err

	char arr1[] = "abc";
	char arr2[] = { 'a', 'b', 'c' };
	char arr3[] = { 'a', 98, 'c' };

	return 0;
}

2. 一维数组的使用

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

#include <stdio.h>

int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	//              0  1  2  3  4  5  6  7  8  9
	//printf("%d\n", arr[5]);//[] 下标引用操作符
	//printf("%d\n", arr[0]);//[] 下标引用操作符
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);//10

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

	return 0;
}
#include <stdio.h>

int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	//              0  1  2  3  4  5  6  7  8  9
	//printf("%d\n", arr[5]);//[] 下标引用操作符
	//printf("%d\n", arr[0]);//[] 下标引用操作符
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);//10

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

	return 0;
}
#include <stdio.h>

int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	//              0  1  2  3  4  5  6  7  8  9
	//printf("%d\n", arr[5]);//[] 下标引用操作符
	//printf("%d\n", arr[0]);//[] 下标引用操作符
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);//10

	for (i = sz - 1; i >= 0; i--)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}
#include <stdio.h>

int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	//              0  1  2  3  4  5  6  7  8  9
	//printf("%d\n", arr[5]);//[] 下标引用操作符
	//printf("%d\n", arr[0]);//[] 下标引用操作符
	int i = 0;;
	int sz = sizeof(arr) / sizeof(arr[0]);//10

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

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

	return 0;
}

总结:

  1. 数组是使用下标来访问的,下标是从0开始。
  2. 数组的大小可以通过计算得到。
#include <stdio.h>

int main()

{
	int arr[10] = { 0 };//10 * 4
	printf("%d\n", sizeof(arr));//40 - 计算的是数组的总大小,单位是字节
	printf("%d\n", sizeof(arr[0]));//4
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数的方法
	printf("%d\n", sz);

	return 0;
}

3. 一维数组在内存中的存储

//%p  --  是用来打印地址的
#include <stdio.h>

int main()
{
	int arr[10] = { 1, 2, 3, 4, 5 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;

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

	return 0;
}

一维数组在内存中的存储
仔细观察输出的结果,我们知道,随着数组下标的增长,元素的地址也在有规律的递增。由此可以得出结论:一维数组在内存中是连续存放的
一维数组在内存中连续存放

4. 二维数组的创建和初始化

4.1 二维数组的创建

int main()
{
	//数组的创建
	int arr[4][5];
	char ch[3][8];

	return 0;
}

4.2 二维数组的初始化

int main()
{
	//数组的初始化
	int arr[4][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7},{5,6,7,8,9} };
	int arr2[4][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7,5,6,7,8,9 };
	//二维数组即使初始化了的
	//行是可以省略的,但是列是不能省略的
	int arr3[][5] = { {1,2,3}, {2,3,4}, {3,4,5,6,7}, {5,6,7,8,9} };

	return 0;
}

5. 二维数组的使用

二维数组的使用也是通过下标的方式。

#include <stdio.h>

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

		printf("\n");
	}

	return 0;
}

6. 二维数组在内存中的存储

#include <stdio.h>

int main()
{
	int arr[4][5] = { 0 };
	int i = 0;
	//行号
	for (i = 0; i < 4; i++)
	{
		int j = 0;
		
		for (j = 0; j < 5; j++)
		{
			printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
		}

	}

	return 0;
}

二维数组在内存中的存储
通过结果我们可以分析到,其实二维数组在内存中也是连续存储的
二维数组在内存中连续存放
注:

//假想是:1 2 3 4 5
//       2 3 4 5 6
//       3 4 5 6 7
//       5 6 7 8 9
//实际上:连续存放的

//1. 二维数组是【一维数组】的数组
//                元素
//
//2. 可以这样理解: 类比一维数组 int arr[10]  arr[j];//0~9   -->  arr[0][j]中arr[0]是数组名 j是下标

7. 数组越界

  • 数组的下标是有范围限制的:数组的下标规定是从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;
	//0~10
	//越界访问
	//
	for (i = 0; i <= 10; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

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

8. 数组作为函数参数

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


首先,来看一下不用函数的写法:

//输入10个整数,对这组数进行排序
//排序有很多的方法
//1. 冒泡排序
//2. 选择排序
//3. 插入排序
//4. 快速排序
// ....

#include <stdio.h>

int main()
{
	int arr[10] = { 0 };
	//输入
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

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

	//冒泡排序 - 升序
	//冒泡排序 - 两两相邻的元素进行比较
	//一趟冒泡排序让一个值来到最终应该出现的位置上
	//1. 确定冒泡排序的趟数
	//2. 一趟冒泡排序的实现

	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		//一趟内部比较的对数
		for (j = 0; j < (sz-1-i); j++)
		{

			if (arr[j] > arr[j + 1])
			{
				//交换
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}

		}

	}

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

	return 0;
}

接着,我们运用函数来实现:

#include <stdio.h>

void bubble_sort(int arr[10], int sz)//这里的arr的本质是指针
{
	//           4       /        4      = 1
	//int sz = sizeof(arr) / sizeof(arr[0]);//sz=1
	int i = 0;

	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		//一趟内部比较的对数
		for (j = 0; j < (sz-1-i); j++)
		{

			if (arr[j] > arr[j + 1])
			{
				//交换
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}

		}

	}

}

//void bubble_sort(int *arr, int sz)//这里的arr的本质是指针
//{
//	//           4       /        4      = 1
//	//int sz = sizeof(arr) / sizeof(arr[0]);//sz=1
//	int i = 0;
//
//	for (i = 0; i < sz - 1; i++)
//	{
//		int j = 0;
//		//一趟内部比较的对数
//		for (j = 0; j < (sz - 1 - i); j++)
//		{
//
//			if (arr[j] > arr[j + 1])
//			{
//				//交换
//				int tmp = arr[j];
//				arr[j] = arr[j + 1];
//				arr[j + 1] = tmp;
//			}
//
//		}
//
//	}
//
//}
//以上两种写法都可以

int main()
{
	int arr[10] = { 0 };
	//输入
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

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

	//排序 - 升序
	//arr作为数组进行了传参
	//数组传参,传递的是地址,传递的是首元素的地址
	bubble_sort(arr, sz);//让这个函数来完成数组arr中数据的排序
					 //arr是数组首元素的地址
	
	//输出
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

此外,我们还可以对它进行一些优化:

//冒泡排序的优化

#include <stdio.h>

void bubble_sort(int* arr, int sz)//这里的arr的本质是指针
{
	//           4       /        4      = 1
	//int sz = sizeof(arr) / sizeof(arr[0]);//sz=1
	int i = 0;

	for (i = 0; i < sz - 1; i++)
	{
		//每一趟开始前就假设已经有序了
		int flag = 1;

		int j = 0;
		//一趟内部比较的对数
		for (j = 0; j < (sz - 1 - i); j++)
		{

			if (arr[j] > arr[j + 1])
			{
				//交换
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;
			}

		}

		if (1 == flag)
		{
			break;
		}

	}

}

int main()
{
	int arr[10] = { 0 };
	//输入
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

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

	//排序 - 升序
	//arr作为数组进行了传参
	//数组传参,传递的是地址,传递的是首元素的地址
	bubble_sort(arr, sz);//让这个函数来完成数组arr中数据的排序
					 //arr是数组首元素的地址

	//输出
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

看完以上代码,肯定会有疑惑:为什么sizeof(arr)中的arr表示整个数组,而传参时arr表示数组首元素的地址呢?

//数组名该怎么理解?
//数组名通常情况下就是数组首元素的地址
//但是有2个例外:
//1. sizeof(数组名),数组名单独放在sizeof()内部,这里的数组名表示整个数组,计算的是整个数组的大小
//2. &数组名,这里的数组名也表示整个数组,这里取出的是整个数组的地址
//除此之外,所有遇到的数组名都表示数组首元素的地址

#include <stdio.h>

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

	printf("%p\n", &arr[0]);
	printf("%p\n", &arr[0] + 1);
	
	printf("%p\n", &arr);//数组的地址
	printf("%p\n", &arr + 1);//+1,跳过整个数组

	//printf("%d\n", sizeof(arr));//40?

	return 0;
}

数组名的理解

附:

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

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

相关文章

chatgpt赋能python:Python自动填表单:提高工作效率的好帮手

Python 自动填表单&#xff1a;提高工作效率的好帮手 在现代社会中&#xff0c;表单已成为我们日常工作中不可或缺的一部分。填表单虽然看似简单&#xff0c;但是时间一长&#xff0c;不仅会影响工作效率&#xff0c;还会带来心理负担。幸运的是&#xff0c;Python 自动填表单…

Linux-0.11 boot目录bootsect.s详解

Linux-0.11 boot目录bootsect.s详解 模块简介 bootsect.s是磁盘启动的引导程序&#xff0c;其概括起来就是代码的搬运工&#xff0c;将代码搬到合适的位置。下图是对搬运过程的概括&#xff0c;可以有个印象&#xff0c;后面将详细讲解。 bootsect.s主要做了如下的三件事: 搬…

doris---Rollup

Rollup 3.5.1基本概念 通过建表语句创建出来的表称为 Base 表&#xff08;Base Table,基表&#xff09; 在 Base 表之上&#xff0c;我们可以创建任意多个 ROLLUP 表。这些 ROLLUP 的数据是基于 Base 表产生的&#xff0c;并且在物理上是独立存储的。 Rollup表的好处&#xff…

C#调用FreeSpire.PDF获取PDF文档中使用的字体

除了图片之外&#xff0c;电子文件中使用的字体都必须要在本机中安装才能正常查看文字&#xff08;word缺少字体的话会自动使用相似或默认字体&#xff09;&#xff0c;要想知道电子文件中使用的字体&#xff0c;可以将电子文件转换为PDF文件&#xff08;如果是打印成PDF的话&a…

chatgpt赋能python:Python收集数据在SEO中的重要性

Python 收集数据在 SEO 中的重要性 随着互联网的发展&#xff0c;搜索引擎对于用户获取信息的重要性日益增加。SEO&#xff08;搜索引擎优化&#xff09;一直是每个网站必须考虑的问题。Python 收集数据在 SEO 中可以发挥重要的作用&#xff0c;帮助网站提高排名。下面我们来详…

Solidity拓展:数学运算过程中数据长度溢出的问题

在数学运算过程中假如超过了长度则值会变成该类型的最小值&#xff0c;如果小于了该长度则变成最大值 数据上溢 uint8 numA 255; numA;uint8的定义域为[0,255]&#xff0c;现在numA已经到顶了&#xff0c;numA会使num变成0(由于256已经超过定义域&#xff0c;它会越过256&…

结构体 --- C语言

目录 1.结构体的声明 2.结构体变量的定义和初始化 3.结构体成员访问 4.结构体传参 1.结构体的声明 结构是一些值的集合&#xff0c;这些称为成员变量&#xff0c;结构的每个成员可以是不同类型的变量。 而数组是一组类型相同的元素的集合。 生活中的描述 人&#xff1a;名…

测试C#分词工具jieba.NET(续1:提取关键词及并行分词)

jieba.NET支持通过两种算法提取文本关键词&#xff1a;TF-IDF算法和TextRank算法&#xff0c;关于这两种算法的介绍详见参考文献10-11&#xff0c;在jieba.NET中对应的类为TfidfExtractor和TextRankExtractor&#xff0c;这两个分词都都支持调用ExtractTags和ExtractTagsWithWe…

文件上传至公有云Nos及对接CDN

项目开发中&#xff0c;需要将图片文件上传至网易公有云的Nos,并且结合CDN做加速服务&#xff0c;记录一下开发过程。流程图&#xff1a; 1. 文件上传到公有云Nos 网易对象存储服务&#xff08;Netease Object Storage&#xff0c;简称NOS&#xff09;是网易数帆提供的高可用…

pycharm环境下打开Django内置的数据库Sqlite出错问题解决

问题描述 在数据库库文件中写入一条记录后&#xff0c;在pycharm的terminal终端下执行查看表的命令出错 执行语句为&#xff1a; 连接数据库报错 python manage.py dbshell CommandError: You appear not to have the sqlite3 program installed or on your path. Error:…

JavaScript之DOM基础

1. 初识DOM DOM: 文档对象模型 是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口。 w3c已经定义了一系列的DOM接口&#xff0c;通过这些DOM接口可以改变网页的内容&#xff0c;结构和样式。 DOM树&#xff1a;文档&#xff1a;一个页面就是一个文档, DOM中使用d…

Android逆向猿人学2022年app比赛第四题grpc与Protobuf使用(步步验证)

教程 前言一、起步二、抓包三、分析四、验证五、HOOK借鉴 前言 前面2-3题和第一题解题思路基本上一样的&#xff0c;这里就不出教程了&#xff0c;这篇文章比较繁琐&#xff0c;基本上描述了我做这题的思路&#xff0c;有很多走不通的地方也有对应的方法&#xff0c;所以会比较…

linux网络初探

linux网络 1.1查看本机ip IP地址 IP地址网络地址主机地址&#xff0c;网络地址&#xff08;网络号&#xff09;相同的主机为本地网络中的主机&#xff0c;可以直接相互通信&#xff0c;而网络地址不同的主机为远程网络中的主机&#xff0c;相互通信必须通过本地网关&#xf…

Flutter Windows开发环境搭建教程与学习资料推荐

Windows应用软件开发有很多框架可以选择&#xff0c;例如比较流行的Electron、Qt、CEF、WPF、WinForm、MFC、DuiLib、SOUI等等。Flutter是近几年流行的全平台应用开发框架&#xff0c;可以进行Android、IOS、Web、MacOS、Windows、Linux等平台的应用软件开发。 一、Flutter介绍…

启动U盘制作工具Rufus 4.0.2035

Rufus是是一款小巧实用免费开源的帮助格式化和创建可启动USB闪存驱动器的工具&#xff0c;如USB钥匙/软盘、记忆棒等&#xff0c;可快速制作linux系统或者win启动u盘&#xff0c;可快速的将ISO镜像文件制作成可引导启动的USB启动盘&#xff0c;支持ISO镜像、GPT和UEFI&#xff…

设置参考文献编号与文中插入引用的具体步骤

目录 一、前言 二、操作步骤 &#xff08;一&#xff09;参考文献设置编号 &#xff08;二&#xff09;文章中引用参考文献方式 一、前言 本教程使用的软件是WPS 二、操作步骤 &#xff08;一&#xff09;参考文献设置编号 1.把引用文献的这个编号全部删掉 2.右键点击段…

学习笔记——vue中使用el-dropdown组件报错

今天在工作中&#xff0c;发现使用el-select做的下拉框&#xff0c;下拉菜单展开后&#xff0c;鼠标点击下拉框之外的区域时&#xff0c;下拉菜单没有收起。然后&#xff0c;我打开控制台&#xff0c;发现了这个错误。 Uncaught TypeError: Cannot read properties of null (re…

《Linux0.11源码解读》理解(四) head之重新设置IDT/GDT

上节提到&#xff0c;现在cs:ip指向0地址&#xff0c;此处存储着作为操作系统核心代码的system模块&#xff0c;是由head.s和 main.c以及后面所有源代码文件编译链接而成。head.s(以下简称head)紧挨着main.c&#xff0c;我们先执行head。 重新设置内核栈 _pg_dir: _startup_3…

堆(堆排序 模拟堆)

目录 一、堆的数据结构二、堆的操作方法往下调整的示意图往上调整的示意图相关功能的实现思路1.插入一个数2.求最小值3.删除最小值4.删除任意一个元素5.修改任意一个元素 三、堆的实战运用堆排序模拟堆 一、堆的数据结构 堆是一个完全二叉树&#xff1a;除了最后一层结点以外&…

C语言三子棋,五子棋,n子棋的代码实现

C语言三子棋&#xff0c;五子棋&#xff0c;n子棋的代码实现 这里以五子棋为例&#xff0c;来说明开发过程开发思路菜单打印棋盘的打印棋子的打印电脑下棋&#xff08;随机数&#xff09;判断输赢代码整合注意事项 这里以五子棋为例&#xff0c;来说明开发过程 其中该项目包含…