➡️➡️➡️
@TOC
🏅🏅🏅1. 一维数组的创建和初始化
✅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];
注意:代码2 是不可以成功创建数组的,[]
中const_n
是count
,不是一个常量表达式,会报错数组创建,在C99标准之前,
[]
中要给一个常量才可以,不能使用变量
C99标准支持了变长数组的概念,数组的大小是通过变量来决定的,因此代码2只能在支持C99标准的编译器下运行
✅1.2数组的初始化
数组的初始化是指:在创建数组的同时给数组的内容一些合理初始值(初始化)
数组在创建的时候如果想不指定数组的确定的大小就得初始化。数组的元素个数根据初始化的内容来确定
我们看一些数组:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
//不完全初始化
int arr1[10] = {1,2,3,4};
//完全初始化
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";
return 0;
}
我们对这些数组进行监视:
arr1[]
不完全初始化,剩余未初始化的元素默认初始化为0
在C语言char
类型数组中,字符是以ASCII码形式存储的,arr4[]
和arr5[]
在内存中的值是相同的
arr6[]
字符串对数组初始化,除了有效字符以外,末尾还会有一个\0
作为字符串结束的标志
✅1.3 一维数组的使用
[]
是下标引用操作符,用来进行数组的访问
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
return 0;
}
通过
arr[]
引用下标就能访问数组了
int main()
{
int arr[10] = { 1,2,3 };
int sz = sizeof(arr) / sizeof(arr[0]);//数组总长度除以数组单个元素
printf("%d\n", sz);// 10
return 0;
}
总结:
数组是使用下标来访问的,下标是从0开始
- 数组的大小可以通过计算得到
✅1.4 一维数组在内存中的存储
我们打印一个数组的地址:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i=0;i<sz;i++)
{
printf("arr[%d]=%p\n",i,&arr[i]);
}
return 0;
}
运行结果:
地址码是十六进制的,整形数据大小为4字节
F828 + 4 = F82C
F82C + 4 = F830
此处产生进位... ... ... ...
仔细观察输出的结果,我们发现,随着数组下标的增长,元素的地址,也在有规律的递增
由此可以得出 结论:数组在内存中是连续存放的
🏅🏅🏅2. 二维数组的创建和初始化
✅2.1二维数组的创建
数组创建:
int arr[3][4];
char arr[3][5];
double arr[2][4];
✅2.2二维数组的初始化
创建一个数组并初始化:
int main()
{
int arr[3][3] = {1,2,3,4,5,6,7,8,9,};
return 0;
}
值的存放:
还可以进行分组:
int main()
{
//不完全初始化
int arr[3][3] = { {1,2},{3,4} };
return 0;
}
未初始化的部分还是默认初始化为0
再来看一个初始化:
二维数组如果有初始化,
行可以省略,列不能省略
✅2.3二维数组的使用
二维数组的使用也是通过下标的方式
代码演示:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int arr[3][3] = {1,2,3,2,3,4,3,4,5 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 3; j++)
{
printf("%d ", arr[i][j]);
//scanf("%d ",&arr[i][j]);
//可以用来输入数组元素
}
printf("\n");
}
return 0;
}
运行结果:
✅2.4二维数组在内存中的存储
可以把二维数组理解为:一维数组的数组
一维数组:
int arr[];
arr[i];//0~9
二维数组:
int arr[3][3];
arr[0][j];
arr[1][j];
arr[2][j];
可以将arr[0],arr[1],arr[2]
直接看作成数组名,这样二维数组可看作一维数组的数组
我们对二维数组元素取地址:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int arr[3][3] = {1,2,3,2,3,4,3,4,5 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 3; j++)
{
printf("&arr[%d][%d]=%d ",i,j,&arr[i][j]);
}
printf("\n");
}
return 0;
}
我们可以看出:二维数组也像一维数组一样元素是连续存放的,每个元素地址都差4
int arr1[12];int arr2[3][4];
在内存中的布局方式是一样的,只是访问形式不同
🏅🏅🏅3. 数组越界
数组的下标是有范围限制的数组的下规定是从0开始的,如果数组有
n个元素
,最后一个元素的下标就是n-1
数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问
C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的
二维数组的
行和列也可能存在越界
🏅🏅🏅4. 数组作为函数参数
在写代码的时候,会将数组作为参数传给函数
✅4.1冒泡排序的错误设计
冒泡排序核心思想:两个相邻的元素进行比较一趟冒泡排序让一个数据来到最终应该出现的位置上
代码演示:
#define _CRT_SECURE_NO_WARNINGS
#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-1-i; j++)
{
if (arr[j] > arr[j + 1])
{
//交换
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
//数组
//把数组的数据排成升序
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
//0 1 2 3 4 5 6 7 8 9
int sz = sizeof(arr) / sizeof(arr[0]);
//冒泡排序的算法,对数组进行排序
bubble_sort(arr);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);//结果是 9 8 7 6 5 4 3 2 1 0
}
return 0;
}
打印结果是 9 8 7 6 5 4 3 2 1 0
结果和预期不同,这是为什么呢?
我们对函数中的sz
监视:
可以看出sz
值为1,那么sz-1=0
,因此无法进入循环,所以结果出现了问题
分析:
数组名本质上是数组首元素的地址
,因此将数组传参,应该由指针来接收
所以函数中arr看似是数组,其实是指针变量
x86环境中sizeof(arr)=4
并且sizeof(arr[0])=4
,因此sz=1
✅4.2数组名是什么?
数组名是数组首元素的地址
有两个例外:
sizeof(数组名)
,计算整个数组的大小,sizeof
内部单独放一个数组名,数组名表示整个数组&数组名
,取出的是数组的地址。
&数组名,数组名表示整个数组
1:
int n = sizeof(arr);//40
2:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);//arr就是首元素的地址
printf("%p\n", arr+1);
printf("--------------\n");
printf("%p\n", &arr[0]);//首元素地址
printf("%p\n", &arr[0]+1);
printf("--------------\n");
printf("%p\n", &arr);//数组的地址
printf("%p\n", &arr+1);
return 0;
}
运行结果:
给数组地址加一会跳过整个数组
除此1,2两种情况之外,所有的数组名都表示数组首元素的地址
✅4.3冒泡排序的正确设计
sz
不能放在函数里计算,当数组传参的时候,实际上只是把数组的首元素的地址传递过去了
#define _CRT_SECURE_NO_WARNINGS
#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 - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
//交换
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
//数组
//把数组的数据排成升序
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
//0 1 2 3 4 5 6 7 8 9
//冒泡排序的算法,对数组进行排序
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr,sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);//0 1 2 3 4 5 6 7 8 9
}
return 0;
}
🔚🔚🔚
🆕🆕🆕
下次利用数组实现 三子棋和扫雷游戏