数组(1)

news/2024/10/19 23:47:42/

文章目录

  • 目录
    • 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[];//errchar 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]);//10for (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]);//10for (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]);//10for (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]);//10for (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 * 4printf("%d\n", sizeof(arr));//40 - 计算的是数组的总大小,单位是字节printf("%d\n", sizeof(arr[0]));//4int 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=1int 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=1int 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.ppmy.cn/news/96648.html

相关文章

RabbitMQ的一些问题

什么是RabbitMQ&#xff1f; RabbitMQ是一款开源的&#xff0c;Erlang编写的&#xff0c;基于AMQP协议的消息中间件 rabbitmq 的使用场景 &#xff08;1&#xff09;服务间异步通信 &#xff08;2&#xff09;顺序消费 &#xff08;3&#xff09;定时任务 &#xff08;4&#x…

linux网络初探

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

玄子Share - IDEA 2023.1 自定义 代码模板(Servlet)

玄子Share - IDEA 2023.1 自定义 代码模板&#xff08;Servlet&#xff09; 23版 IDEA 内取消了自动生成 Servlet 模板类&#xff0c;不过我们可以自己定义一个 Servlet 模板 步骤 第一步打开 IDEA 设置界面&#xff0c;编辑器 -> 文件和代码模板 -> 点击加号新建模板…

unity中的SendMessage详解

介绍 SendMessage是Unity中用于在游戏对象之间发送消息的函数。通过SendMessage函数&#xff0c;可以在游戏对象之间调用方法&#xff0c;从而实现脚本之间的通信。SendMessage方法可以用于调用任何公共方法&#xff0c;不仅限于MonoBehaviour脚本中的方法。 方法 SendMessa…

设计模式之备忘录模式

备忘录模式的定义是&#xff1a;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 该模式允许生成对象状态的快照和将其还原&#xff0c;主要用于撤销与重做功能的实现。 该模…

目标检测YOLO实战应用案例100讲-基于深度学习的无人机航拍图像目标检测算法研究与应用

基于深度学习的无人机航拍图像目标检测算法研究与应用 无人机是无线遥控装置和内置的程序控制装置操纵,亦或由车载计算机完全地 或间歇地规律操控的不载人飞机。无人机的地面航拍成像在军事探察、地质勘探、 公安侦查等领域[1-2]得到广泛应用。在军事领域,能够通过无人机进行…

启动U盘制作工具Rufus 4.0.2035

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

第五十五天学习记录:C语言进阶:动态内存管理Ⅲ

柔性数组 C99中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员。 柔性数组的特点&#xff1a; 。结构体中的柔性数组成员前面必须至少有一个其他成员。 。sizeof返回的这种结构大小不包括柔性数组的内存。 。包含柔性数组成员的结构…