目录
前言
这一小节呢,开始对C语言的数组进行讲解,从一维数组开始出发,接着讲解二维数组,对数组的概念进行一个简单的认识。
一、一维数组
1.1 数组的创建
- 所谓数组,数组就是一组相同类型的元素的集合。
- 数组的创建方式如下所示:
type_t arr_name [const_n];
//type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小
数组创建的实际例子:
//代码1
int arr1[10];
//代码2
int count = 10;
int arr2[count];//数组时候可以正常创建?
//代码3
char arr3[10];
float arr4[1];
double arr5[20];
需要注意的一点:当我们创建数组的时候,[ ]里面必须要给一个常量值才可以表示,不可以使用变量。在C99之后才支持变长数组的概念,数组的大小可以使用变量指定,但是数组不可以初始化。
1.2 数组的初始化
- 数组的初始化:就是在数组创建的同时给数组里面的内容设定一些合理的初始值。
举个例子就是:
int main()
{
int arr1[10]; // 创建一个大小为10的int类型数组
char arr2[20]; // 创建一个大小为20的char类型数组
float arr3[1]; // 创建一个大小为1的float类型数组
double arr4[] = {0}; // 创建一个不指定大小的double类型数组(需要初始化)
return 0;
}
字符数组的初始化
int main()
{
char ch1[5] = {'b', 'i', 't'};
char ch2[] = {'b', 'i', 't'};
char ch3[5] = "bit"; // 'b', 'i', 't', '\0', '0'
char ch4[] = "bit"; // 'b', 'i', ''t, '\0'
return 0;
}
字符数组初始化的两种写法:
如果字符数组带上双引号 " " 一般会自己带上 \0 。 花括号内部需要自己加上 \0 。
int main()
{
char ch5[] = "bit"; // b, i, t, \0 【自带斜杠0】
char ch6[] = {'b', 'i', 't'}; // b i t 【不自带斜杠0】
printf("%s\n", ch5);
printf("%s\n", ch6);
return 0;
}
没有 \0的时候,strlen读取的字符的时候不会知道什么时候结束,strlen:遇到 \0的时候就会自动停止。
int main()
{
char ch5[] = "bit"; // b, i, t, \0 【自带斜杠0】
char ch6[] = {'b', 'i', 't'}; // b i t 【不自带斜杠0】
printf("%d\n", strlen(ch5));
printf("%d\n", strlen(ch6));
return 0;
}
当然,如果我们手动加上一个 \0的话,这样子就不会是随机值了;
int main()
{
char ch5[] = "bit"; // b, i, t, \0 【自带斜杠0】
char ch6[] = {'b', 'i', 't', '\0'}; // b, i, t, + '\0' 【手动加上斜杠0】
printf("%d\n", strlen(ch5));
printf("%d\n", strlen(ch6));
return 0;
}
这样的话,运行的结果就是3 3了。
1.3 数组的使用
-
下标引用操作符:[ ] ,即数组访问操作符;
-
来举一个简单的例子来看一看就知道了:
-
打印一组数组
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for(i = 0; i < sz; i++)
printf("%d ", arr[i]);
return 0;
}
总结:
① 数组的访问是通过下标来访问的,下标是从0开始的。
② 可以通过计算来得到数组的大小。
1.4 数组的存储
接下来按地址的格式打印:%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;
}
运行的结果如下图所示:
仔细观察输出的结果可以知道:随着数组下标的增长,元素的地址也在有规律的变化。
结论:数组在内存当中是连续存放的。
二、二维数组
2.1 二维数组的创建
二维数组的创建如图所示:
二维数组的创建:
int main()
{
int arr[3][4]; // 创建一个3行4列的int型二维数组;
/*
0 0 0 0
0 0 0 0
0 0 0 0
*/
char arr[3][5]; // 创建一个3行5列的char型二维数组;
double arr[2][4]; // 创建一个2行4列的double型二维数组;
return 0;
}
2.2 二维数组的初始化
初始化:在创建数组的同时要给数组的内容设置一个合理的初始值;
注意的事项:
- 二维数组在初始化的时候,行可以省略,但是列绝对不可以省略;
- 二维数组在内存当中也是连续存放的;
初始化演示:
int main()
{
int arr[3][4] = {1,2,3,4,5};
/*
1 2 3 4
5 0 0 0
0 0 0 0
*/
int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; // 完全初始化
int arr2[3][4] = {1,2,3,4,5,6,7}; // 不完全初始化 - 后面补0;
int arr3[3][4] = {{1,2}, {3,4}, {4,5}}; // 指定;
/*
1 2 0 0
3 4 0 0
4 5 0 0
*/
return 0;
}
关于“行可以省略,但是列绝对不可以省略”
int main()
{
int arr1[][] = {{2,3}, {4,5}}; // error
int arr2[3][] = {{2,3}, {4,5}}; // error
int arr2[][4] = {{2,3}, {4,5}}; // √
return 0;
}
2.3 二维数组的使用
我们在打印二维数组的时候,同样是通过下标的方式,只不过相对于一维数组来说,在打印二维数组的时候一般利用两个for循环。
int main()
{
int i = 0;
int j = 0;
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++)
printf("%d", arr4[i][j]); // 二维数组[行][列];
printf("\n"); // 换行;
}
}
二维数组在内存当中的存储
int main()
{
int arr[3][4];
int i = 0;
int j = 0;
for(i = 0; i < 3; i++) {
for(j = 0; j < 4; j++)
printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
return 0;
}
通过仔细观察输出的结果,我们可以发现二维数组在内存当中其实也是连续存放的;
因此我们可以得到这个结论:不论是一维数组还是二维数组,在内存当中都是连续存放的;
三、数组作为函数传参
3.1 关于数组名
其实数组名就是数组首元素的地址(只有两个例外);
- 例外1:sizeof(数组名),最后计算的是整个数组的大小
- 例外2:&数组名,取出来的是整个数组的大小
验证:
int main()
{
int arr[10] = {0};
printf("%d\n", sizeof(arr));
return 0;
}
最后输出的结果是 >> 40
3.2 冒泡排序
冒泡排序的核心思想:相邻的两两元素进行比较,如果满足条件则交换;
- 先确认总共需要的趟数;
- 写下来一趟冒泡排序的过程;
- 最后进行交换;
需要注意的一些点:
- int arr [ ] 本质是来讲依然是指针,int * arr;
- 数组在传递参数的时候,实际上传递的是数组的首元素地址;
- sz变量不能够在函数内部计算,需要在外部计算好了之后再传递进去;
例子:编写一个bubble_sort( ) 函数,升序排列,int arr [ ] = {9,8,7,6,5,4,3,2,1,0}
#include <stdio.h>
void bubble_sort (int arr[], int sz) // 形参arr本质上是指针 int* arr
{
/* 确认趟数 */
int i = 0;
for(i = 0; i < sz; i++)
{
/* 一趟冒泡排序干的活 */
int j = 0;
for(j = 0; j <= (sz-1-i); j++) // -1:最后一趟不用排,-i:减去已经走过的趟
{
/* 如果前面数比后面数大,就交换 */
if(arr[j] > arr[j + 1])
{
/* 创建临时变量交换法 */
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main(void)
{
int arr[] = {9,8,7,6,5,4,3,2,1,0};
int sz = sizeof(arr) / sizeof(arr[0]);
/* 冒泡排序 */
bubble_sort(arr, sz); // 数组传参的时候,传递的是首元素的地址
/* 打印数组 */
int i = 0;
for(i=0; i<=sz; i++)
printf("%d ", arr[i]);
return (0);
}
最后输出的结果: 0 1 2 3 4 5 6 7 8 9
算法的优化:我们可以设置一个变量来判断数组是否有序,如果已经有序,则就不需要冒泡排序了。
#include <stdio.h>
void bubble_sort (int arr[], int sz)
{
int i = 0;
for(i = 0; i < sz; i++)
{
int j = 0;
int falg = 1; // 标记1,假设这一趟冒泡排序已经有序
for(j = 0; j <= (sz-1-i); j++)
{
if(arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0; // 仍然不有序,标记为0
}
}
if(flag == 1)
break; // 已经有序了,就不需要再冒泡排序了
}
}
int main(void)
{
int arr[] = {9,8,7,6,5,4,3,2,1,0};
int sz = sizeof(arr) / sizeof(arr[0]);
/* 冒泡排序 */
bubble_sort(arr, sz);
/* 打印数组 */
int i = 0;
for(i=0; i<=sz; i++)
printf("%d ", arr[i]);
return (0);
}