【C初阶】数组

目录

1. 数组的概念

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

2.1 数组的创建

2.2 数组的初始化

2.3 数组的类型

3. 一维数组的使用

3.1 数组的下标

3.2 数组的输入输出

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

5. sizeof 计算数组元素个数

6. 二维数组的创建

6.1 二维数组的概念

6.2 二维数组的创建

7. 二维数组的初始化

8. 二维数组的使用

8.1 二维数组的下标

8.2 二维数组的输入输出

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

10. C99中的变长数组(VLA)


1. 数组的概念

数组由数据类型相同一系列元素组成(是一组相同类型元素的集合)。

  • 一系列:1个或者多个;即数组元素个数不能为0
  • 类型相同:数组中存放的数据,类型都是相同的。

需要使用数组时,通过声明告诉编译器,数组内含有多少个元素和这些元素的类型。

数组分为一维数组和多维数组,一般多维数组就是指二维数组。 

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

2.1 数组的创建

普通变量使用的数据类型,数组都是可以使用的,考虑下面的数组:

int math_socer[20];// 整型数组
char name[];       // 字符数组
double rain[50];   // 浮点型数组
  • 方括号([ ])表明 math_socer、name、rain 都是数组,方括号中的数字表明数组中的元素个数。由此可见,方括号中的数字必然为正整数。
  • 数组在创建的时候,可以指定数组的类型( int、char、double等等)和数组的大小以及数组的名字(name、rain等等)。

 数组创建好了,但很明显,现在数组内的值都是随机值。

2.2 数组的初始化

数组通常被用来储存程序需要的数据,这个时候在程序一开始就初始化数组比较好。以下是数组初始化的方法:

数组的初始化一般使用大括号,将数据放在大括号中,用逗号分隔数据。

数组如果进行了初始化,数组的大小就可以省略掉。

#include <stdio.h>
int main()
{
	int arr1[5] = { 1,2,3,4,5 };  // 完全初始化
	int arr2[] = { 1,2,3,4,5 };   // 如果数组初始化了,方括号内的数字可省略。会自动计算数组大小

	int arr3[5] = { 1, 2 };       // 未完全初始化 -- 剩余元素会自动成为0


	char arr4[] = "hello";
	char arr5[] = { 'h','e','l','l','o' };
	// 这两种初始化方式是一样的,只有字符数组可以这样。

	int arr6[5] = { 1,2,3,4,5,6 }; // 超出数组所能接受的范围,这是错误的示范-- 初始化值太多
	return 0;
}

以上是一些初始化的方式与错误。

2.3 数组的类型

去掉数组名就是数组的类型。

注意:数组名前面的类型是数组内元素的类型,切记不要混淆。 

2.2节的代码为例:

(数组类型)int [5]  -- arr1(数组名)

(数组类型)int []  -- arr2(数组名)

其余类似。

3. 一维数组的使用

3.1 数组的下标

C语言规定数组是有下标的,下标是从0开始的,我们可以通过下标来访问数组中的元素。

// 数组元素的访问

#include <stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5 };
	printf("%d", arr[0]);   // 1
	printf("%d", arr[1]);   // 2
	printf("%d", arr[2]);   // 3
	printf("%d", arr[3]);   // 4

	return 0;
}

C语言中提供了一个操作符[ ],这个操作符叫做:下标引用操作符。 (数组名 + 方括号 + 数字)

3.2 数组的输入输出

我们总不能一直一个一个元素访问吧,那多麻烦。那么如何访问整个数组的元素呢?-- for循环

// 访问整个数组的内容
// 正着打印  把条件改一改就可以逆着打印
#include <stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5 };
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

// 1 2 3 4

for循环产生了0~4的下标,一次又一次打印,最终结果为:1 2 3 4 

初始化后的数组我们会打印了,就可以自己输入数组的元素来打印了。

// 自己输入数据并打印出来

#include <stdio.h>
int main()
{
	int arr[5];
	for (int i = 0; i < 5; i++)
	{
		scanf("%d", &arr[i]);
	}
	for (int j = 0; j < 5; j++)
	{
		printf("%d ", arr[j]);
	}
	return 0;
}

// 1 2 3 4 5
// 1 2 3 4 5

就这么简单。可以自己动手试一试。 

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

数组的基本知识学完,我们继续深入了解数组。首先,我们先来了解一下数组在内存中的储存。

// 打印数组元素的地址

#include <stdio.h>
int main()
{
	int arr[5] = { 0 };
	for (int i = 0; i < 5; i++)
	{
		printf("arr[%d] = %p\n", i, &arr[i]); 
        // & -- 取出地址
	}
	return 0;
}

运行该代码:

 从输出的结果分析,随着数组下标的增长,地址是由小到大变化的,且每次增加4(因为整型是4个字节)。这里有小伙伴可能不知道C是啥意思,这是十六进制数(123456789ABCDEF)(即8+4=C,C+4=0,剩余的大家就懂了)。

因此,我们得出结论:数组在内存中是连续存放的。至于了解这个有啥用,等学习到后面的指针自然会知道。(我们只要知道了一个元素的地址,其余元素就可以顺藤摸瓜的找到了)

5. sizeof 计算数组元素个数

在第四小节中,我们只打印了5个元素,如果我们修改了初始化的元素个数,我们就需要改for循环中判断条件,这样是不是有点复杂,那么有没有方法把判断条件和元素个数联系起来。

答案是:有的,兄弟。可以用sizeof。

sizeof是C语言中的关键字,用来计算类型或者变量大小的。那么,就可以用来计算数组的大小。

// sizeof计算数组的大小

#include <stdio.h>
int main()
{
	// 如何计算一个数组的元素个数
	// sizeof(arr)计算的是整个数组的大小  20 * 4 = 80
	// sizeof(arr[0])计算一个元素的长度
	// sizeof(arr) / sizeof(arr[0]) 计算数组的元素个数
	int arr[20] = { 0 };
	long long sz = sizeof(arr) / sizeof(arr[0]);
	printf("%zd\n", sz);  // sizeof 返回类型为size_t类型, 所以用%zd
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

// 20
// 20个0

这样子一搞,不管数组怎么变化,计算出的大小也随着变化。 

6. 二维数组的创建

6.1 二维数组的概念

如果我们把一维数组作为元素,这时候就是二维数组,二维数组作为元素的话就是三维数组,二维数组及以上的数组统称为多维数组。我们一般用到二维数组就够了。

其本质就是“数组中的数组”。

6.2 二维数组的创建

我们该如何定义二维数组呢?

// 定义二维数组

#include <stdio.h>
int main()
{
	int arr[3][5];
	// int -- 类型    -- 表明数组内每个元素类型是整型
	// arr -- 数组名  -- 这个数组的名字
	// [3] -- 行      -- 表明这个数组有3行
	// [5] -- 列      -- 表明每一行都有5个元素

	return 0;
}

注意:方括号内的值为常量值。 

7. 二维数组的初始化

我们知道了如何创建二维数组,只需要在创建的时候给定一些初始值就被称为初始化。

初始化二维数组是建立在初始化一维数组的基础上的。下面是二维数组的初始化形式:

// 二维数组的初始化

#include <stdio.h>
int main()
{
	// 完全初始化
	int arr1[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };

	// 不完全初始化
	int arr2[3][5] = { 1,2 };    
	// 第一行前两个元素初始化为1 2,其它的元素为0

	int arr3[3][5] = { 0 };      
	// 第一行第一个元素初始化为0,其它默认为0, 就是全部初始化为0的意思

	// 按行初始化
	int arr4[3][5] = { {1,2},{3,4},{5,6} };  
	// 把第一行、第二行、第三行前两个元素初始化为1 2 / 3 4 /5 6 其余为0

	// 初始化时可以省略行, 但是不能省略列
	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} };
	return 0;
}

在二维数组的初始化中,我们可以根据自己的目的来选择初始化的方法。 

8. 二维数组的使用

8.1 二维数组的下标

二维数组的访问也是使用下标形式的,只不过是在一维数组的基础上加了列。所以,二维数组是有行和列的,只要锁定了行和列,则数组的元素就被锁定了。

C语言规定:二维数组的下标是从[0][0]开始的。

// 二维数组的下标

#include <stdio.h>
int main()
{
	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };

	return 0;
}

在这里创建了一个三行五列的数组,我们来看看数组内部:

 可以很明显的看出,数组的下标是从[0][0]开始的。所以,假设我们想输出7,则是arr[2][4],可以快速定位到。

8.2 二维数组的输入输出

与访问一维数组类似,我们同样使用循环。

// 二维数组的输入输出

#include <stdio.h>
int main()
{
	int arr[3][5] = { 0 };
	for (int i = 0; i < 3; i++)     // 遍历行 产生行号
	{
		for (int j = 0; j < 5; j++) // 遍历列 产生列号
		{
			scanf("%d", &arr[i][j]);// 输入数据
		}
	}
	for (int i = 0; i < 3; i++)     // 产生行号
	{
		for (int j = 0; j < 5; j++) // 产生列号
		{
			printf("%d ", arr[i][j]);// 输出数据
		}
		printf("\n");
	}
	return 0;
}

// 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7  //输入的数据
// 1 2 3 4 5         // 输出
// 2 3 4 5 6
// 3 4 5 6 7

不难看出,我们只需要知道行数和列数,就可以访问整个数组 。

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

二维数组的储存方式也是连续存放的,我们先打印数组所有元素的地址:

// 打印二维数组各元素的地址

#include <stdio.h>
int main()
{
	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			printf("arr[%d][%d] = %p\n", i, j, &arr[i][j]);
		}
	}
	return = 0;
}

其运行后:

 每一行内部的每个元素都是相邻的,由于是整型,故而差4个字节。所以二维数组中的每个元素都是连续存放的。这也为我们指针访问数组元素奠定了基础。

10. C99中的变长数组(VLA)

前面我们有说过,数组的大小只能填常量值,如果填入变量值会发生什么?

编译器直接报了错误。很显然,这样的语法限制,极大程度的干扰了数组的灵活性,有时候数组大了浪费空间,数组小了容易越界。这让我们很困扰。于是乎:

C99新增了变长数组(variable-length array, VLA),允许使用变量表示数组的维度。如下所示:

int n = a + b;
int arr[n];

由此可见:变长数组有一些限制,变长数组必须是自动储存类别。即变长数组的根本特征是:数组的长度只有在运行时才能知道,所以变长数组不能初始化

注意 变长数组不能改变大小

        变长数组中的“变”不是指可以修改已创建数组的大小。一旦创建了变长数组,它的大小则保持不变。这里的“变”指的是:在创建数组时,可以使用变量指定数组的维度。

 由于变长数组是C语言的新特性,目前完全支持这一特性的编译器不多。这里我所用的VS2022在默认情况下是不能使用的。就没办法给大家做演示了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值