前面梳理完函数和递归的知识后,来进行数组知识的梳理
对函数有疑惑的同学,可以看我之前的文章:c语言基础知识帮助理解(详解函数)_总之就是非常唔姆的博客-CSDN博客 c语言基础知识帮助理解(函数递归详解)_总之就是非常唔姆的博客-CSDN博客 想做点游戏的同学可以看: 三子棋小游戏(可改棋盘大小)_总之就是非常唔姆的博客-CSDN博客 探索经典游戏:扫雷小游戏_总之就是非常唔姆的博客-CSDN博客 希望能帮助到大家!
c语言中数组是一种数据结构,用于存储相同数据类型的一组元素。它提供了一种有序的方式来存储和访问多个数据项undefined 即——数组是一组相同类型元素的集合
数组的创建形式:type name const_n 其中:
实例 :
需要注意的是: C99 之前数组只能是常量指定大小,C99 之后引用了变长数组的概念,数组的大小是可以使用变量指定的,但是VS2022、2019 不支持C99的边长数组的 我自己是用的19,便不再讲解边长数组的相关内容。
int main()
{
int arr1[10];
int arr2[2 + 3];//这两种情况均未报错
int x = 0;
scanf("%d", &x);
int arr3[x];//这种情况就是变长数组,因为2019不支持,便会报错
return 0;
}
数组的初始化是指在声明数组时为其赋予初始值
初始化的方式:
逐个元素初始化: 可以逐个为数组的每个元素赋值,用逗号分隔每个元素的值,并用大括号括起来。例如:
int arr[5] = {1, 2, 3, 4, 5};
部分元素初始化: 可以只初始化数组的一部分元素,其余元素将被自动初始化为0。例如:
int main()
{
int arr[4] = { 1,2 };
for (int i = 0; i < 4; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
结果如下:
int main()
{
int arr[] = { 1,2 };
printf("%d", sizeof(arr) / sizeof(arr[1]));//我们输出arr的大小
return 0;
}
结果:
char str[] = "Hello";
需要注意字符串与字符数组的区别:
1.字符串初始化后会在末尾自动添加一个\0作为字符串结束的标志
2.因为1的原因计算大小使会比看起来相同的字符数组大1,如下
int main()
{
char arr1 []= "hello";
char arr2[] = { 'h','e','l','l','o' };
printf("%d\n", sizeof(arr1) / sizeof(arr1[1]));//我们输出arr1的大小
printf("%d", sizeof(arr2) / sizeof(arr2[1]));//我们输出arr2的大小
return 0;
}
看起来二者均为hello,但是
我们可以清楚地看到多了一个\0在字符串后面,大小也如我所说:
对于数组的使用我们使用这个操作符: [] ,下标引用操作符。它其实就数组访问的操作符
int main()
{
//需要注意的是:数组下标是从0开始的
char arr1 []= "hello";
char arr2[] = { 'h','e','l','l','o' };
//对应的下标: 0 1 2 3 4
printf("%c", arr2[0]);//来输出一个h看看吧
return 0;
}
其他经常使用的对数组的处理:
int arr[]={1,2,4};
int sz=sizeof(arr)/sizeof(arr[0])-1;
for (i = 0; i <= sz; i++)//这就是数组的遍历,此为遍历输出,也可以遍历输入
{
printf("%d ", arr[i]);
}
总结:
接下来我们探讨数组在内存中的存储 ,利用%p来打印地址:
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;
}
仔细观察后我们发现:随着数组下标的增长,元素的地址,也在有规律的递增
由此可以得出结论:数组在内存中是连续存放的
//二维数组创建
int arr1[1][4];
char arr2[3][5];
double arr3[2][3];
//二维数组初始化
int arr1[3][4] = {1,2,3,4};//这种初始化在一行满了后就换到下一行
int arr2[3][4] = {{1,2},{4,5}};//这种初始化已经规定一行的元素,不够的来填0
int arr3[][4] = {{2,3},{4,5}};//需要注意的是:二维数组如果有初始化,行可以省略,列不能省略
通过调试来直接观察各个数组的元素情况
二维数组的使用也是通过下标的方式
二维数组我们完全可以看成矩阵:
例如:int arr3={{1,2,3},{3,4,5},{5,6,7}};
我们可以看成:
那样的话:通过对应的行号和列号的下标就能访问到对应的元素了
那么二维数组的遍历:
int main()
{
int arr[2][3] = { {1,4},{2,3} };
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d ", arr[i][j]);
}
}
return 0;
}
int main()
{
int arr[3][4];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("&arr[%d][%d]的地址是: %p\n", i, j, &arr[i][j]);
}
}
return 0;
}
每一个之间的差值是4(一个整形的大小):通过结果我们可以分析到,其实二维数组在内存中也是连续存储的
三.数组越界
数组的下标是有范围限制的。undefined 数组的下规定是从 0 开始的,如果数组有 n 个元素,最后一个元素的下标就是 n-1 。undefined 所以数组的下标如果小于 0 ,或者大于 n-1 ,就是数组越界访问了,超出了数组合法空间的访问。undefined C 语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就 是正确的 所以我们在写代码时,要自己做越界的检查。
int main()
{
int arr[8] = { 1,2,3,4,5,6,7,8 };
for (int i = 0; i <= 10; i++)
{
printf("arr[%d]=%d\n",i, arr[i]);//当i等于8开始后就已经越界了,但是编译器没有报错
}
return 0;
}
可以看出,越界后数组储存的就是随机值了,所以还是要避免数组越界
数组名是数组首元素的地址。(有两个例外) 1. sizeof( 数组名 ) ,计算整个数组的大小, sizeof 内部单独放一个数组名,数组名表示整个数undefined 组。undefined 2. & 数组名,取出的是数组的地址。 & 数组名,数组名表示整个数组。 除此1,2两种情况之外,所有的数组名都表示数组首元素的地址。
当数组传参的时候,实际上只是把数组的首元素的地址传递过去了,有时我们必须要在外面先知道长度后,再传参时把那个长度一起传过去
希望本文对你理解和使用一维数组有所帮助。通过不断的练习和实践,你将能够熟练地使用一维数组,并将其应用于解决实际问题中。祝大家在C语言的学习和编程实践中取得进步!