目录
1.一维数组
2.二维数组
3.数组越界
4.数组作为函数参数
正文
1.一维数组
1.1 数组的创建
(1)数组的概念:数组是一组相同类型元素的集合;
(2)数组的创建方式:
type_t arr_name [const_n] ;
即数组元素类型+数组名+指定数组大小的常量表达式;
(3)数组的创建实例:
char arr1[7];
float arr2[80];
double arr3[15];
注:C99标准中引入了变长数组的概念,允许数组的大小用变量来指定,如果编译器不支持C99中的变长数组,则不能使用变量来表示数组大小(如常用的Vs2019不支持)
int n=0;
scanf("%d",&n);
int arr[n]={0};
即上文代码所示定义数组的方式在Vs2019下会报错,而在Linux下可以正常运行;
1.2 数组的初始化
(1)数组初始化的概念:在创建数组的同时给数组的内容一些合理的初始值;
(2)数组初始化的实例:
int arr[10]={1,2,3,4};
//不完全初始化,其余元素(arr[4]至arr[9])默认初始化为0;
char ch[ ]={'a','b','c'};
//也可将字符元素表示为其ASCII码值,如char ch[ ]={'a',98,'c'};
int arr[10];
//不初始化时,该数组的10个元素均为随机值;
注:(1)变长数组不支持初始化:
int n=10;
int arr[n]={0};
在支持变长数组运行的编译环境下,变长数组不能初始化,即上文代码不可运行;
(2)数组的大小与初始化:
//1
int arr1[10]={1,2,3,4};
//2
int arr2[ ]={1,2,3,4};
区分以上两个代码:
第一个代码表示前四个元素分别初始化为1,2,3,4其余元素默认初始化为0的长度为10的数组;
第二个代码表示根据初始化赋值为1,2,3,4后确定长度为4的数组;
(3)不同区域的初始化:
(4)字符数组的初始化:
① 未初始化时:
//1
char arr1[ ]="abc";
//2
char arr2[ ]={'a','b','c'};
区分以上两个代码:
第一个代码表示元素分别为a b c \0 四个元素的字符数组(字符串隐藏一个'\0');
第二个代码表示元素分别为a b c 三个元素的字符数组;
② 初始化时:
//1
char arr1[5]="abc";
//2
char arr2[5]={'a','b','c'};
对比以上两个代码:
两个代码均表示元素分别为a b c \0 \0 的长度为5的字符数组;
1.3 一维数组的使用
(1)[ ]是下标引用操作符,下标从0开始,即arr[10]={1,2,3,4},arr[0]=1,0和1称为[ ]的两个操作数;
(2)一维数组元素的访问:
int main()
{
int arr1[100] = { 1,2,3,4 };
int sz = sizeof(arr1) / sizeof(arr1[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
arr1[i] = i + 1;
} //赋值代码
for (i = 0; i < sz; i++)
{
printf("%d ", arr1[i]);
} //打印代码
return 0;
}
1.4 一维数组在内存中的存储
(1)
运行上述代码后发现,每两个相邻元素的地址相差4,是因为一个整型占4个字节;
故而: 一维数组在内存中连续存放,并且随着数组下标的增加,地址由低到高变化;
(2)
运行上述代码后发现,p+1向后跳一个元素即跳4个字节;
2.二维数组
2.1 二维数组的创建
int arr[3][5]; //表示创建一个三行五列的数组;
2.2 二维数组的初始化
(1)
//1
int arr[3][5] = { 1,2,3,4,5,6 };
//初始化情况为:
//arr[0][0]=1,arr[0][1]=2,arr[0][2]=3,arr[0][3]=4,arr[0][4]=5,arr[1][0]=6,
//其余元素均为0;
//2
int arr[3][5] = { {1,2},{3,4},{5,6} };
//初始化情况为:
//arr[0][0]=,arr[0][1]=,arr[1][0]=,arr[1][1]=,arr[2][0]=,arr[2][1]=,其余元素均为0;
(2)二维数组行可以省略,列不能省略;
2.3 二维数组的使用
(1)二维数组的行和列下标均从0开始;
(2)二维数组的访问:
2.4 二维数组在内存中的存储
运行上述代码后发现,二维数组在空间内存中也是连续存放的,并且是一行一行连续存放。
同时这也是为什么二维数组初始化可以省略行不可以省略列的本质解释。
3.数组越界
(1)数组越界的定义:数组下标规定从0开始,若数组有n个元素,则最后一个元素的下标是n-1。
故而数组的下标如果小于0或大于n-1,则数组越界访问,超出了数组合法空间的访问。
(2)数组越界的示例:
4.数组作为函数参数
4.1 冒泡排序函数的错误设计
//写一个冒泡排序的函数,排序arr数组的元素
#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[] = { 9,8,7,6,5,4,3,2,1,0 };
bubble_sort(arr);
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
进行调试监视后,发现函数部分的sz的值为1而非10,即函数体部分未进行for循环。
故而需要思考,main函数中用数组名进行数组的传输存在异议。
4.2 数组名的含义
(1)在大多数情况下,数组名等同于数组首元素地址。
(2)在两种情况下,数组名并非数组首元素地址:
a. sizeof(数组名)时,数组名不是首元素地址,而是表示整个数组,计算的是整个数组的大小;
b. &(数组名)时,数组名也表示整个数组,取出的是整个数组的地址。
证明:
结论第一条的证明:
根据⑦的运行结果,若此时数组名arr仍代表首元素地址,则sizeof(arr)输出结果应该是4或8,
而输出结果却是40,说明sizeof(arr)中arr表示的是整个数组,计算的是整个数组的大小;
结论第二条的证明:
(1)①②与③④两组相同,在+1后地址均增加4,说明数组名与数组首元素地址相同;
(2)而⑤⑥的情况与①②、③④不同,+1后地址增加40,说明&(arr)表示整个数组的地址;
4.3 冒泡排序函数的正确设计
在对数组名进行了一定了解后,再回到对于冒泡函数排序的设计上来。
可以发现,4.1中的程序设计在bubble_sort(arr)时,就已错误,将数组首元素地址传递给了函数。
修改后的正确的冒泡函数设计如下:
#include<stdio.h>
void bubble_sort(int*arr,int sz)
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int flag =1;
int j = 0;
for (j = 0; j <sz-i-1 ; j++)
{
if (arr[j] > arr[j + 1])
{
flag=0;
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
if(1==flag)
{
break;
}
}
}
int main()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]); //在main函数内求sz
bubble_sort(arr,sz); //将sz以参数形式传入函数
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
|| 终