目录
1.一维数组
1.1 数组的创建
①数组:一组相同类型元素的集合
②数组的创建方式:
1)type_t arr_name [const_n];
其中type_t 是指数组的元素类型,const_n 是一个常量表达式,用来指定数组的大小
2)创建一维动态数组
int main()
{
int n;
int* a;
scanf_s("%d", &n);
a = (int*)malloc(sizeof(int));
for (int i = 0; i < n; i++)
{
scanf_s("%d", &a[i]);
}
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
return 0;
}
③实例
int arr1[8];
char arr2[5];
float arr3[1];
double arr4[20];
在C99标准之前, [] 中要给一个常量才可以,不能使用变量,C99标准支持变长数
组的概念,数组的大小可以是变量(VS2019不支持C99)
int n = 8;
int arr[n];
1.2 数组的初始化
①完全初始化
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
②不完全初始化
int arr[10] = { 1,2,3,4,5 };
🐖:数组在创建的时候如果想不指定数组的确定的大小就得初始化,数组的元素个数根据初始化的内容来确定
int arr2[] = { 1,2,3,4,5 };
相当于
int arr2[5] = { 1,2,3,4,5 };
③字符数的初始化
char ch1[5] = { 'b','i','t' };
char ch2[] = { 'b','i','t' };
ch1初始化为:b i t \0 \0
ch2初始化为:b i t初始化为:b i t
char ch1[5] = "bit";
char ch2[] = "bit";
ch1初始化为:b i t \0 \0
ch2初始化为:b i t \0
char arr1[] = "abc";
char arr2[3] = { 'a','b','c' };
arr1初始化为:a b c \0
arr2初始化为:a b c
char ch1[] = "bit";
char ch2[] = { 'b','i','t' };
printf("%s\n", ch1);
printf("%s", ch2);
输出:
bit
bit烫烫烫烫蘠it
这是因为在遇到 \0 时才会停止打印,ch1初始化时末尾已有 \0 ,而ch2没有,因此在打印ch2时会一直向后打印,直到遇到 \0 才会停止打印
同理,ch2的长度为随机值
char ch1[] = "bit";
char ch2[] = { 'b','i','t' };
printf("%d ", strlen(ch1));
printf("%d", strlen(ch2));
输出:3 15
1.3 一维数组的使用
①数组下标从0开始
[ ]:下标引用操作符
arr[4]:arr数组中的第五个元素
②计算数组的元素个数
int sz = sizeof(arr)/sizeof(arr[0]);
③对数组内容赋值,数组是使用下标来访问的,下标从0开始
int i = 0;//下标
for(i=0; i<10; i++)
{
arr[i] = i;
}
④输出数组的内容
for(i=0; i<10; ++i)
{
printf("%d ", arr[i]);
}
1.4 一维数组在内存中的存储
int main()
{
int arr[10] = { 0 };
int i = 0;
for (i = 0; i < 10; i++)
{
printf("&arr[%d]=%p\n", i, &arr[i]);//以16进制输出地址
}
return 0;
}
输出:
&arr[0]=0093FDFC
&arr[1]=0093FE00
&arr[2]=0093FE04
&arr[3]=0093FE08
&arr[4]=0093FE0C
&arr[5]=0093FE10
&arr[6]=0093FE14
&arr[7]=0093FE18
&arr[8]=0093FE1C
&arr[9]=0093FE20
①一维数组在内存中是连续存放的
②随着数组下标的增长,地址是由低到高变化的
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;//数组名是数组首元素的地址
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", *p);
p++;
}
return 0;
}
输出:1 2 3 4 5 6 7 8 9 10
2.二维数组
2.1 二维数组的创建
①
int arr[3][4];
char arr[3][5];
double arr[2][4];
②二维动态数组的创建
int** a;
int n;
scanf_s("%d", &n);
a = (int**)calloc(sizeof(int*), n);
for (int i = 0; i < n; i++)
{
*(a + i) = (int*)calloc(sizeof(int), n);
}
2.2 二维数组的初始化
①完全初始化
int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
②不完全初始化(后面补0)
int arr[3][4] = { 1,2,3,4,5,6,7,8 };
int arr1[3][4] = { {1,2},{4,5} };
🐖:二维数组如果有初始化,行可以省略,列不能省略
int arr[][4] = { {2,3},{4,5} };
2.3 二维数组的使用
二维数组的使用也是通过下标的方式,行、列下标都是从0开始
arr[1][2]表示第2行第3列的数字
int main()
{
int a[3][3] = { 1,2,3,4,5,6,7,8,9 };
int i = 0, j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
return 0;
}
2.4 二维数组在内存中的存储
int main()
{
int a[][4] = { {1,2} ,{3,4},{5,6} };
int i = 0, j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
printf("&a[%d][%d]=%p\n", i, j, &a[i][j]);
}
}
return 0;
}
输出:
&a[0][0]=00C3F8D8
&a[0][1]=00C3F8DC
&a[0][2]=00C3F8E0
&a[1][0]=00C3F8E4
&a[1][1]=00C3F8E8
&a[1][2]=00C3F8EC
&a[2][0]=00C3F8F0
&a[2][1]=00C3F8F4
&a[2][2]=00C3F8F8
二维数组在内存中也是连续存储的
int main()
{
int a[][4] = { {1,2} ,{3,4},{5,6} };
int i = 0, j = 0;
int* p = &a[0][0];
for (i = 0; i < 9; i++)
{
printf("%d ", *p);
p++;
}
return 0;
}
输出:1 2 0 3 4 0 5 6 0
3.数组越界
数组的下标是有范围限制的。数组的下标规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1,所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问
C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的
4.数组作为函数参数
4.1 冒泡排序函数的错误设计
错误示例:
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[] = {3,1,7,5,8,9,0,2,4,6};
bubble_sort(arr);//是否可以正常排序?
for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
这是因为形参arr本身是指针,数组传参的时候,实际上传递的是数组首元素的地址
4.2 数组名是什么
数组名是数组首元素的地址
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}
输出:
001FFE90
001FFE90
特列1:sizeof(数组名)--数组名表示的是整个数组,计算的是整个数组的大小,单位是字节
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));
return 0;
}
输出:40
特列2:&数组名--数组名表示的是整个数组,取出的是整个数组的地址
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n", &arr);
printf("%p\n", &arr[0]);
return 0;
}
输出:
00F8FAF8
00F8FAF8
00F8FAF8
int main()
{
int arr[10] = { 0 };
printf("%p\n", &arr);
printf("%p\n", &arr+1);
printf("%p\n", arr);
printf("%p\n", arr+1);
return 0;
}
输出:
005FFCAC
005FFCD4
005FFCAC
005FFCB0
4.3 冒泡排序函数的正确设计
void sort(int arr[],int sz)
{
int i = 0, j = 0;
for (i = 0; i < 10; i++)
{
for (j = 0; j <sz-1-i ; j++)
{
if (arr[j] > arr[j + 1])
{
int t = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = t;
}
}
}
}
int main()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
sort(arr,sz);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
输出:0 1 2 3 4 5 6 7 8 9