C语言数组介绍 -- 一维数组和二维数组的创建、初始化、下标、遍历、存储,C99 变长数组

目录

[1. 一维数组](#1. 一维数组)

[1.1 数组的概念](#1.1 数组的概念)

[1.2 一维数组的创建](#1.2 一维数组的创建)

[1.3 一维数组的初始化](#1.3 一维数组的初始化)

[1.4 数组的类型](#1.4 数组的类型)

[1.5 数组下标](#1.5 数组下标)

[1.5.1 数组元素的遍历](#1.5.1 数组元素的遍历)

[1.5.2 数组的输入](#1.5.2 数组的输入)

[1.6 一维数组在内存中的存储](#1.6 一维数组在内存中的存储)

[1.7 sizeof 计算数组元素个数](#1.7 sizeof 计算数组元素个数)

[2. 二维数组](#2. 二维数组)

[2.1 二维数组的创建](#2.1 二维数组的创建)

[2.2 二维数组的初始化](#2.2 二维数组的初始化)

[2.2.1 不完全初始化](#2.2.1 不完全初始化)

[2.2.2 完全初始化](#2.2.2 完全初始化)

[2.2.3 按行初始化](#2.2.3 按行初始化)

[2.2.4 初始化时省略行,但是不能省略列](#2.2.4 初始化时省略行,但是不能省略列)

[2.3 二维数组的下标](#2.3 二维数组的下标)

[2.3.1 二维数组的遍历](#2.3.1 二维数组的遍历)

[2.4 二维数组在内存中的存储](#2.4 二维数组在内存中的存储)

[3. C99 中的变长数组](#3. C99 中的变长数组)


1. 一维数组

1.1 数组的概念

数组是一组相同类型元素的集合。(1)数组中存放的是 1 个或者多个元素,数组元素个数不能为 0。(2)数组中存放的数据的类型是相同的。

1.2 一维数组的创建

一维数组创建的基本语法:

cpp 复制代码
type  arr_name[常量值];

type:数组中元素的数据类型(char,int,struct 等)。

arr_name:数组名。

常量值:表示数组的大小。

cpp 复制代码
int math[20];    // 创建 math 数组用于存储 20 人的数学成绩,数据成绩的类型为 int
double score[10];    // 创建 score 数组用于存储 10 个人得分情况,得分的类型为 double

1.3 一维数组的初始化

数组在创建的时候,给定一些初始值,就叫做数组的初始化。 数组的初始化一般使用大括号,将数据放在大括号中。初始化的时候给定元素个数不能超过数组的大小。

cpp 复制代码
#include <stdio.h>

int main()
{
	int arr1[5] = {1, 2, 3, 4, 5};	// 完全初始化
	int arr2[6] = { 1, 5 };	// 不完全初始化:前面元素为给定的值,剩余的元素默认初始化为 0。
    int arr3[7];    // 定义数组的时候可以不初始化,但是默认为随机值。
	return 0;
}

1.4 数组的类型

数组也是有类型的,数组算是一种自定义类型,去掉数组名留下的就是数组的类型

cpp 复制代码
int arr1[10];

int arr2[12];

char ch[5];

arr1 数组的类型是 int [10],arr2 数组的类型是 int [12],ch 数组的类型是 char [5]。

1.5 数组下标

C 语言规定数组是有下标的,下标从 0 开始,假设数组有 n 个元素,最后一个元素的下标是 n - 1 ,下标就相当于数组元素的编号,如下:

cpp 复制代码
int arr[10] = {1,2,3,4,5,6,7,8,9,10};

C 语言数组的访问提供了一个操作符 " [] ",这个操作符叫做下标访问操作符

有下标访问操作符,就可以轻松访问数组的元素了。访问下标为 7 的元素,就使用 arr[7],如下:

cpp 复制代码
#include <stdio.h>

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n", arr[7]);
	printf("%d\n", arr[3]);
	return 0;
}

1.5.1 数组元素的遍历

可以通过 for 循环 + 下标的方式对整个数组的元素进行遍历。

cpp 复制代码
#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 ", arr[i]);
	}
	return 0;
}

1.5.2 数组的输入

想对数组中的元素进行修改,可以使用 scanf 进行输入对数组的元素进行修改

cpp 复制代码
#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++)
	{
		scanf("%d", &arr[i]);
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

注:scanf 访问数组中单独的一个元素的时候需要加上取地址运算符

1.6 一维数组在内存中的存储

我们可以通过打印数组每个元素的地址来观察数组在内存中是如何存储的

cpp 复制代码
#include <stdio.h>

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

	return 0;
}

从输出的结果上可以看出来,数组随着下标的增长,地址是由小变大的,并且每两个响铃的元素之间相差 4,这是因为这个数组中目前存储的数据类型为 int 类型,int 类型每一个元素需要 4 个字节进行存储。

所以可以得出结论:数组在内存中是连续存放的

1.7 sizeof 计算数组元素个数

如果想直到数组的元素个数,可以使用 sizeof 关键字来计算类型或者变量的大小,sizeof 返回的并不是数组的元素个数,返回的是数组占据多少字节,可以通过占据的字节数除以数组中数据类型的方式来计算数组中的元素个数

cpp 复制代码
#include <stdio.h>

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	
	printf("数组占用的字节数: %d\n", sizeof(arr));
	printf("数组中一个元素的大小: %d\n", sizeof(arr[0]));//计算⼀个元素的⼤⼩,单位是字节

	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("数组中元素的个数: %d\n", sz);

	return 0;
}

2. 二维数组

2.1 二维数组的创建

把一维数组作为数组的元素时,这时候该数组就是二维数组。同理将二维数组作为数组的元素时,这时候该数组就是三位数组。二维数组以上的数组统称为多维数组。

创建二维数组的语法如下:

cpp 复制代码
type arr_name[常量值1][常量值2];

type:表示二维数组中数据的类型。

arr_name:表示二维数组的数组名。

常量1:表示二维数组的行数。

常量2:表示二维数组的列数。

cpp 复制代码
int arr[3][5];
double data[2][8];

上述中 arr 表示为一个 3 行 5 列的二维数组,存储的数据类型为 int 类型;data 表示为一个 2 行 8 列的二维数组,存储的数据类型为 double 类型。

2.2 二维数组的初始化

2.2.1 不完全初始化

cpp 复制代码
#include <stdio.h>

int main()
{
	int arr1[3][5] = { 1, 2, 3, 4, 5, 6, 7};
	int arr2[3][5] = { 0 };

	return 0;
}

如上,可以看出,当对二维数组进行初始化的时候,是一行一行进行初始化的,等该行初始化完,在继续初始化下一行,并且剩余没有初始化的元素默认初始化为 0

2.2.2 完全初始化

cpp 复制代码
#include <stdio.h>

int main()
{
	int arr3[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };

	return 0;
}

2.2.3 按行初始化

cpp 复制代码
#include <stdio.h>

int main()
{
	int arr4[3][5] = { {1,2},{3,4},{5,6} };

	return 0;
}

2.2.4 初始化时省略行,但是不能省略列

cpp 复制代码
int arr5[][5] = { 1,2,3 };
int arr6[][5] = { 1,2,3,4,5,6,7 };
int arr7[][5] = { {1,2}, {3,4}, {5,6} };

2.3 二维数组的下标

二维数组是有行有列的,只要锁定行和列就能锁定数组中唯一的一个元素

C语⾔规定,⼆维数组的⾏是从0开始的,列也是从0开始的,如下所示:

cpp 复制代码
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};

如果想要访问 7 这个数组,那么就可以通过 arr[2][4] 进行访问。

cpp 复制代码
#include <stdio.h>

int main()
{
	int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
	printf("%d\n", arr[2][4]);
	return 0;
}

2.3.1 二维数组的遍历

一维数组是使用 for 循环 + 数组下标的方式进行遍历的,那么二维数组也可以通过同样的方式对数组进行遍历,只是遍历二维数组的时候需要两层 for 循环。下列就通过遍历的方式向二维数组中输入数据并通过 printf 打印出来。

cpp 复制代码
#include <stdio.h>

int main()
{
	int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
	int i = 0;//遍历⾏
	//输⼊
	for (i = 0; i < 3; i++) //产⽣⾏号
	{
		int j = 0;
		for (j = 0; j < 5; j++) //产⽣列号
		{
			scanf("%d", &arr[i][j]); //输⼊数据
		}
	}

	printf("\n");
	//输出
	for (i = 0; i < 3; i++) //产⽣⾏号
	{
		int j = 0;
		for (j = 0; j < 5; j++) //产⽣列号
		{
			printf("%d ", arr[i][j]); //输出数据
		}
		printf("\n");
	}

	return 0;
}

2.4 二维数组在内存中的存储

像一维数组一样,通过打印出二维数组每个元素的地址观察二维数组中元素的存储方式

cpp 复制代码
#include <stdio.h>

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

从上述的输出结果可以看出,每一行内部的每个元素都是相邻的,地址之间相差 4 个字节,跨行位置处的两个元素也是相邻的,也只相差 4 个字节,所以二维数组中的每个元素都是连续存放的

3. C99 中的变长数组

在 C99 标准之前,C 语言在创建数组的时候,数组大小的指定只能使用常量、常量表达式。这样的语法限制在创建数组的时候不够灵活,有时候数组创建大了会造成空间浪费,有时候数组创建小了又不够用。

C99 中给出一个变长数组(variable-length array,VLA)的新特性,允许我们可以使用变量指定数组大小

cpp 复制代码
int n = a+b;
int arr[n];

上面示例中,arr 数组就是变长数组,因为它的长度取决于变量 n 的值,编译器在编译的时候无法确定 n 的值为多少,只有运行时才能知道 n 是多少

变长数组的根本特征就是数组长度只有运行时才能确定,所以变长数组不能初始化 。好处是在开发时不用随意为数组指定一个估计的长度,可以在运行时为数组分配精确的长度。变⻓数组的意思是数组的大小是可以使⽤变量来指定的,在程序运⾏的时候,根据变量的⼤⼩来指定数组的元素个数,⽽不是说数组的⼤⼩是可变的。数组的大小⼀旦确定就不能再变化了

在 VS2022 上虽然支持大部分 C99 语法,但是没有支持 C99 变长数组,下面是在 gcc 编译器上测试的结果:

cpp 复制代码
#include <stdio.h>

int main()
{
        int n = 0;
        scanf("%d", &n);
        int arr[n];
        int i = 0;
        for (i = 0; i < n; i++)
        {
                scanf("%d", &arr[i]);
        }
        for (i = 0; i < n; i++)
        {
                printf("%d ", arr[i]);
        }
        printf("\n");
        return 0;
};
相关推荐
小张成长计划..9 分钟前
双向链表的实现
数据结构·链表
s1533516 分钟前
数据结构之顺序表,链表,栈,队列
数据结构·数据库
Wo3Shi4七32 分钟前
双向队列
数据结构·算法·go
Wo3Shi4七36 分钟前
列表
数据结构·算法·go
Wo3Shi4七41 分钟前
链表
数据结构·算法·go
Wo3Shi4七1 小时前
数组
数据结构·算法·go
myloveasuka1 小时前
信号操作集函数
linux·运维·服务器·c语言·c++·vscode
CoovallyAIHub1 小时前
YOLOv13都来了,目标检测还卷得动吗?别急,还有这些新方向!
深度学习·算法·计算机视觉
北方有星辰zz1 小时前
数据结构:栈
java·开发语言·数据结构
zl_dfq1 小时前
数据结构之 【树的简介】(树的(相关)概念、二叉树的概念、部分性质、满二叉树、完全二叉树)
数据结构