第五章 数组

定义

数组是一组相同类型元素的集合,但我们需要创建多个相同类型的变量时,只需要创建一个类型的数组,就相当于同时创建很多相同类型的变量。


一维数组

数组如何创建

从定义来入手看一下数组的创建:

c 复制代码
type_t arr_name[const_n];
  • type_t是指元素的类型;
  • arr_name是数组名;
  • const_n是一个常量表达式,用来指定数组的大小;

可以简易为:

元素类型 数组名元素个数

eg:

c 复制代码
int arr[10] 

意思是:创建一个名为arr数组,数组中存储着10个元素,每个元素类型为int类型

变长数组

在创建数组时候,我们可能会想过使用以下方法创建数组

c 复制代码
int n=10;
int arr[n];

当然这种方法是不可行的

原因:在c99标准之前,数组的大小只能是常量表达式,在c99标准中引入了变长数组的概念,使得数组的大小可以是变量,但这样的数组不能初始化,vs2019或vs2022这样的编译器(IDE)不支持c99中变长数组,但gcc编译器可以。

数组初始化

一维数组在创建时 ,未给出确定的数组大小值,则该数组必须得初始化,数组的大小根据初始的内容来确定。故数组的初始化是指,在创建数组的同时给数组的内容一些合理的初始值。

用法示例

c 复制代码
   int arr1[10] = { 1 };
   int arr2[] = { 1,2,3,4 };
   int arr3[5] = { 1,2,3,4,5 };
   char arr4[3] = { 'a',98,'c' };
   char arr5[] = { 'a','b','c' };
   char arr6[] = "abcdef";

一维数组的使用

  • 我们一般使用操作符: (下标引用操作符)来对数组中的某个位置的元素进行访问;
  • 数组元素的下标是从0开始

用法示例

从键盘输入十个数,并将他们打印在屏幕上

c 复制代码
#include<stdio.h>
int main()
{
   int arr[10] = { 0 };
   int sz = sizeof(arr) / sizeof(arr[0]);
   int i = 0;
   for (i = 0; i < sz; i++)
   	scanf("%d", &arr[i]);
   for (i = 0; i < sz; i++)
   	printf("%d ", arr[i]);
   return 0;
}

我们一般用关键字sizeof来求数组的长度

  • sizeof(arr)表示整个数组的大小
  • sizeof(arr[0])表示计算数组中首元素的大小,即每个元素的大小
  • 数组元素个数=数组总大小/数组每个元素大小

一维数组的存储

数组在内存中是怎样存储的呢?我们先来看一段代码:

c 复制代码
#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++)
		printf("&arr[%d]=%p\n", i, &arr[i]);
	return 0;
}

注意:%p是打印地址的格式输出符号

这段代码是将数组每个元素的地址打印出来,结果如下:

由结果而知,随着数组下标的增长,元素的地址是在由规律的递增,并且相邻元素地址相差4,正好是一个int类型的大小,所以我们得知,数组在内存中是连续存放的。


二维数组

二维数组的创建

二维数组的创建与一维数组非常相似

c 复制代码
type_t arr_name[row][col];
  • type_t是指元素的类型;
  • arr_name是数组名;
  • row是一个常量表达式,用来指定数组的行数;
  • col是一个常量表达式,用来指定数组的列数;

用法示例

c 复制代码
int arr[3][4];//创建一个3行4列的整形二维数组
char arr1[3][5];//创建一个3行5列的字符二维数组
double arr3[2][4];//创建一个2行4列的浮点型二维数组

二维数组的初始化

c 复制代码
//数组初始化
int arr[3][4] = {1,2,3,4};//将第一行赋值1,2,3,4,其余行的数默认为0;
//表示第1行{1,2},第2行{4,5}
//最终效果:
//1 2 0 0
//4 5 0 0
//0 0 0 0
int arr[3][4] = {{1,2},{4,5}};
int arr[][4] = {{2,3},{4,5}};//二维数组如果有初始化,行可以省略,列不能省略
  • 数组的不完全初始化,其他内容默认为0
  • 二维数组初始化时,行可以省略,列不能省略

二维数组的使用

二维数组的访问用 数组名 的形式

用法示例

c 复制代码
#include<stdio.h>
int main()
{
	int arr[3][5];
	int i = 0, j = 0;
	for (i =0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			arr[i][j] = 3 * i + 5 * j;
		}
	}
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

二维数组的存储

像之前一样,通过打印各个元素的地址来观察一下:

c 复制代码
#include<stdio.h>
int main()
{
	int arr[3][4];
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("&arr[%d][%d]=%p\n", i, j, &arr[i][j]);
		}
	}
	return 0;
}

通过观察发现:

  • 二维数组每行元素里相邻元素地址相差4,刚好为一个int类型大小
  • 每行最后一个元素与下一行第一个元素地址也相差4
    由此可见,二维数组和一维数组一样,在内存中也是连续存储的。

数组的越界访问

我们在创建数组时候,都知道下标是由范围限制的。

  • 数组的下标规定是从0开始,如果数组由n个数组组成,那么元素的下标范围就是0到-1
  • 所以当数组的下标小于0或者大于n-1,就是数组越界访问,超出了数组合法空间的访问

注意:C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的。

数组越界的例子

c 复制代码
#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\n", arr[i]);//当i等于10的时候,越界访问
	return 0;
}

数组越界访问,我们无法知道越界访问的空间是否存在危险,也无法预料产生的其他后果。

数组作为函数参数

  • 通常情况下,数组名是首元素地址
  • sizeof(数组名):计算的是整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组
  • &数组名:取出的是数组的地址,&数组名,数组名表示整个数组
c 复制代码
#include<stdio.h>
int main()
{
	int arr[5] = { 0,1,2,3,4 };
	printf("  arr=%p\n", arr);
	printf("arr+1=%p\n", arr + 1);
	printf("\n");
	printf("  &arr[0]=%p\n", &arr[0]);
	printf("&arr[0]+1=%p\n", &arr[0] + 1);
	printf("\n");
	printf("  &arr=%p\n", &arr);
	printf("&arr+1=%p\n", &arr + 1);
	return 0;
}

冒泡排序

适用条件:整型数组进行升序排序

用法示例

错误示例

c 复制代码
#include <stdio.h>
void bubble_sort(int arr[])
{
	int sz = sizeof(arr) / sizeof(arr[0]);
	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 tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int arr[] = { 5,3,7,6,1,8,9,2,4,0 };
	bubble_sort(arr);
    int i = 0;
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

这段代码星相信很多小伙伴看不出什么问题,但是运行结果时却是错误的,原因就在于sizeof(arr)计算的是数组的大小,而将arr传递进函数内部时,arr就不再时一个数组,而是一个地址,也就是数组首地址,所以我们用sizeof计算一个地址大小时,会产生很大的误差。

正确示例

c 复制代码
#include<stdio.h>
void bubble_sort(int arr[], int sz)
{
	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 tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int arr[] = { 5,3,7,6,1,8,9,2,4,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	bubble_sort(arr, sz);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}
相关推荐
Scott9999HH8 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔8 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社9 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海9 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖10 小时前
JDK 26 新特性详解
java·开发语言
马优晨11 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区12 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大13 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai13 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说13 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json