【C语言】数组详解

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

1.1 数组的创建

数组是一组相同类型元素的集合。

数组的创建方式:

type_t   arr_name  [const_n];

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

数组的创建:

//代码1
int arr1[10];

//代码2
char arr2[10];
float arr3[1];
double arr4[5];
double arr5[2+3];

//代码3
int n = 10;
int arr6[n];//数组什么时候可以正常创建呢?

注:

  • 代码3的数组什么时候可以正常创建呢?
  • 在支持C99标准的编译器环境下编译。
  • C99中引入了变长数组的概念,变长数组支持数组大小使用变量来指定。变长数组不是数组的长度可以变化,而是数组的大小可以用变量来指定。
  • VS2019和VS2022都不支持C99的变长数组,但是很多的OJ 刷题平台是支持的。

1.2 数组的初始化

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

#include <stdio.h>
int main()
{
    
    
	//数组的初始化
	int arr1[10] = {
    
     1 };
	//不完全初始化,第一个元素初始化为1,其余元素初始化为0
	int arr2[10] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	//完全初始化,这里的每一个元素都有被赋值
	char arr3[5] = {
    
     'a','b','c' };
	//在内存中存储了a,b,c,0,0
	char arr4[5] = "abc";
	//在内存中存储了a,b,c,\0,0
	// \0的ASCII值是0,所以arr4在内存中存储了a,b,c,0,0,但是它实际上和arr3在内存中的存储是不一样的。
	int arr5[] = {
    
     1,2,3,4 };
	//没有给定元素个数时,数组的元素个数根据初始化的内容来确定,此时元素个数为4
	char arr6[] = {
    
     'a','b','c' };
	//在内存中这里只存储了a,b,c 三个字符
	char arr7[] = "abc";
	//在内存中这里存储了a,b,c,\0四个字符,字符串的结束标志是\0,所以\0也要存储的数组中
	char arr8[3] = {
    
     'a',98,'c' };
	//这里的98是b的ASCII值,所以这里存储了a,b,c三个元素
	return 0;
}

我们调试起来看一下:
在这里插入图片描述

1.3 一维数组的使用

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

//代码1:
#include <stdio.h>
int main()
{
    
    
	int arr[10] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	int i = 0;//对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:int i = 0;做下标
	for (i = 0; i < 10; i++)
	{
    
    
		printf("%d ", arr[i]);//arr[i]表示数组的一个元素,而不是创建数组
	}
	return 0;
}
//代码2:
#include <stdio.h>
int main()
{
    
    
    int arr[10] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	//计算数组的元素个数
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
    
    
		printf("%d ", arr[i]);
	}
	return 0;
}

在这里插入图片描述

总结:

  • 数组是使用下标来访问的,下标是从0开始。
  • 数组的大小可以通过计算得到。
int arr[10];
int sz = sizeof(arr) / sizeof(arr[0]);

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

接下来我们探讨数组在内存中的存储

#include <stdio.h>
int main()
{
    
    
	int arr[10] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	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 打印的是十六进制数,十六进制通常用数字0、1、2、3、4、5、6、7、8、9和字母A、B、C、D、E、F(a、b、c、d、e、f)表示,C表示12,十六进制中的10,在十进制中表示16。

仔细观察输出结果,我们可以看到每个地址相差4,因为这里的数组是int 类型的数组,一个int 类型在内存中占4字节。随着数组下标的增长,元素的地址,也在有规律的递增。
由此可以得出结论:

  • 数组在内存中是连续存放的
  • 随着数组下标的增长,地址也是由低到高变化的
    在这里插入图片描述

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

2.1 数组的创建

二维数组是一个几行几列的数组。

#include <stdio.h>
int main()
{
    
    
	//二维数组的创建
	int arr1[3][4];
	char arr2[3][5];
	double arr3[2][4];
	return 0;
}

2.2 数组的初始化

#include <stdio.h>
int main()
{
    
    
	//二维数组初始化
	int arr1[3][4] = {
    
     1,2,3,4,5 };
	//逐个初始化,按顺序初始化,前面初始化为1,2,3,4,5,后面都初始化为0
	int arr2[3][4] = {
    
     {
    
    1,2},{
    
    3,4},{
    
    5} };
	//指定行初始化
	int arr3[][4] = {
    
     1,2,3,4,5 };
	//这里是有两行三列
	//二维数组初始化时,行可以省略,但是列不可省略
	return 0;
}

我们调试起来看一下:
在这里插入图片描述

2.3 二维数组的使用

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

//按行打印
#include <stdio.h>
int main()
{
    
    
	int arr[3][4] = {
    
     {
    
    1,2},{
    
    3,4},{
    
    5} };
	int i = 0;//行
	for (i = 0; i < 3; i++)
	{
    
    
		int j = 0;//列
		for (j = 0; j < 4; j++)
		{
    
    
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

在这里插入图片描述

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

在这里插入图片描述

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

#include <stdio.h>
int main()
{
    
    
	int arr[3][4] = {
    
     {
    
    1,2},{
    
    3,4},{
    
    5} };
	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;其实二维数组在内存中也是连续存储的
  • 我们将二维数组想象成一维数组,二维数组的第一行为arr[0][j],第二行为arr[1][j],第三行为arr[2][j];我们就可以把arr[0],arr[1],arr[2]分别作为三个一维数组的数组名。
    在这里插入图片描述

3. 数组越界

数组的下标是有范围限制的。
数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。
C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以程序员写代码时,最好自己做越界的检查。
二维数组的行和列也可能存在越界。

示例1:

#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;
}

运行结果:
在这里插入图片描述

我们这里运行出来没有报错,但是我们要知道我们的代码错了,下标为10 的数是什么我们不知道,这里访问的不是我们数组里面的数了,这里就形成了越界访问。编译器也有可能没有发现这个bug,编译器没有报错,不代表它是对的。
编译器在这里报了警告:在这里插入图片描述

示例2:

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

运行结果:
在这里插入图片描述

我们的代码越界访问了,跨行越界,一行访问了五个元素,直接混乱了。
每一行在打印的时候都会相后越界一个元素,到第三行的时候向后越界访问的不是我们数组里面的数了。
在这里插入图片描述

4. 数组作为函数参数

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

5.数组名

数组名是什么?
数组名本质是:数组首元素的地址

因为数组名本质是:数组首元素的地址
所以数组作为函数参数的时候,不是把整个数组的传递过去。
数组在传参的时候,传递的是首元素的地址,那么数组的形参就应该是指针变量来接收。

代码

#include <stdio.h>
int main()
{
    
    
	int arr[10] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	int* p = &arr[0];
	int i = 0;
	printf("%p\n", arr);//arr是数组名,数组名是首元素地址
	printf("%p\n", arr+1);//首元素地址+1
	printf("%p\n", &arr[0]);//&arr[0]存的是首元素地址
	printf("%p\n", &arr[0]+1);//首元素地址+1
	printf("%p\n", &arr);//数组的地址
	//&arr,取出的是数组arr的地址,但是取出的地址也是首元素的地址,但是本质不一样。
	printf("%p\n", &arr + 1);//数组的地址+1
	//这里数组地址+1,加的不是4,而是40
	printf("%d\n", *arr);
	//数组首元素地址对应的元素
	printf("%p\n", &arr + 1);
	//取出数组arr的地址,指针指向这个数组的下一个元素 
	printf("%p = %p\n", p + i, &arr[i]);
	//p+i=arr[i]
	//p+i 就是下标为i元素的地址,通过对p+i解引用,找到下标为i的元素
	printf("%d\n", sizeof(arr));
	//sizeof(arr),arr表示整个数组
	return 0;
}

运行结果:
在这里插入图片描述

补充:

  1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
  2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。
  3. 除此1,2两种情况之外,所有的数组名都表示数组首元素的地址。

本章到这里就结束啦,如果有哪里写的不好的地方,请指正。
如果觉得不错并且对你有帮助的话请给个三连支持一下吧!
Fighting!!!✊

猜你喜欢

转载自blog.csdn.net/qq_68661624/article/details/126533234
今日推荐