本章节分为:一维数组创建和初始化、二维数组创建和初始化、数组越界、数组作为函数参数。
第一节:一维数组创建和初始化
数组就是一组相同类型元素的集合。
1. 一维数组创建方式:数组的元素类型+数组名+数组大小(需要常量表达式)
int arr[10];
char ch[5];
double data1[20];
double data2[15 + 5];
值得注意的是,C99之前[ ]中只能使用常量。C99之后才支持变长数组,[ ]中可以使用变量,但是这种数组不能初始化。
2. 一维数组初始化:
int main()
{
//不完全初始化,剩余的元素默认初始化为0
int arr1[10] = { 1,2,3 };
//完全初始化
int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr[] = { 1,2,3 };//3个元素
//放进去10个元素之后是否是字符串,取决于末尾是否是\0结束
//否则不能以字符串的形式打印
char arr1[10] = { 'a','b','c' };
//a b c 0 0 0 0 0 0
char arr2[10] = "abc";
//a b c \0 0 0 0 0 0 0
char arr3[] = { 'a','b','c' };//3个元素
char arr4[] = "abc";//4个元素 末尾有\0
return 0;
}
3. 一维数组的使用:
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//[] - 下标引用操作符
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", arr[4]);//打印下标是4的元素 结果是:5
for (i = 0; i < sz; i++)//打印数组每个元素
{
printf("%d ", arr[i]);
}
//倒序打印
for (i = sz - 1; i >= 0; i--)
{
printf("%d ", arr[i]);
}
4. 一维数组在内存中的储存
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
printf("&arr[%d] = %p\n", i, &arr[i]);
}
//& arr[0] = 0000007C5B6FF9A8
//& arr[1] = 0000007C5B6FF9AC
//& arr[2] = 0000007C5B6FF9B0
//& arr[3] = 0000007C5B6FF9B4
//& arr[4] = 0000007C5B6FF9B8
//& arr[5] = 0000007C5B6FF9BC
//& arr[6] = 0000007C5B6FF9C0
//& arr[7] = 0000007C5B6FF9C4
//& arr[8] = 0000007C5B6FF9C8
//& arr[9] = 0000007C5B6FF9CC
可以看到,随时数组下标递增,元素的地址也在有规律的递增,因为int类型是4字节,所以每次增加4。结论是:数组在内存中是连续存放的。
第二节:二维数组的创建和初始化
1. 二维数组的创建
int arr1[3][4];//3行4列
char arr2[5][10];//5行,每行10个字符
2. 二维数组的初始化
//未分组时,每行自动放4个
int arr1[3][4] = { 1,2,3,4,2,3,4,5,3,4,5,6 };
//如果初始化元素不够,剩下自动补0
int arr2[3][4] = { 1,2,3,4,2,3,4,5,3,4};
//每行剩余两个自动补0
int arr3[3][4] = { {1,2},{3,4},{5,6} };
//可以省略行,但不能省略(列)每行有几个元素,如果每列元素不足,自动补0
//这种情况必须初始化,省略列就没法确认基本存放方式
int arr4[][4] = { {1,2,3,4},{5,6} };//等效int arr4[][4] = { 1,2,3,4,5,6 };
3. 二维数组的使用
int arr[3][4] = { 1,2,3,4,2,3,4,5,3,4,5,6 };
int i = 0;
//向二维数组输入数据
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
scanf("%d", &arr[i][j]);
}
}
//打印二维数组
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
4. 二维数组在内存的储存
本质上二维数组还是一维数组,所以每一行的元素所占内存空间大小必须相等,所以每一行的元素个数必须要相等。
int arr[3][4] = { 1,2,3,4,2,3,4,5,3,4,5,6 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
}
//&arr[0][0] = 010FFE20
//&arr[0][1] = 010FFE24
//&arr[0][2] = 010FFE28
//&arr[0][3] = 010FFE2C
//&arr[1][0] = 010FFE30
//&arr[1][1] = 010FFE34
//&arr[1][2] = 010FFE38
//&arr[1][3] = 010FFE3C
//&arr[2][0] = 010FFE40
//&arr[2][1] = 010FFE44
//&arr[2][2] = 010FFE48
//&arr[2][3] = 010FFE4C
第三节:数组越界
数组的下标是0~n-1。C语言本身不做数组下标的越界检查,编译器也不一定报错。所以写代码时,要做好越界检查。
第四节:数组作为函数参数
这里使用冒泡排序作为例子。
这里需要注意,不能在函数内部直接使用sizeof(arr)计算数组大小。因为数组传参时,传递的是数组首元素的地址。
//数组传参的时候,形参有两种写法:
//1.数组形式
//2.指针形式
void bubble(int* arr, int sz)
{
int i = 0;//i是需要交换多少轮
for (i = 0; i < sz - 1; i++)
{
//j是元素下标,从下标为0的元素(也就是第一个元素)开始逐一比较
//第1轮:第1个元素需要交换 元素个数-1次,10-1=9
//第2轮:第2个元素需要交换 元素个数-2次,10-2=9
//....
//第9轮:第9个元素需要交换 元素个数-9次,10-9=1
//结束,总共交换 元素个数-1轮,10-1=9
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 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble(arr, sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
作业
1. 若定义int a[2][3] = { 1,2,3,4,5,6 }; 则值为4的数组元素是()
A.a[0][0]
B.a[1][0]
C.a[1][1]
D.a[2][1]
答案:B
2. 定义了一维 int 型数组 a[10] 后,下面错误的引用是:( )
A.a[0] = 1;
B.a[0] = 5 * 2;
C.a[10] = 2;
D.a[1] = a[2] * a[0];
答案:C
3. 以下能对二维数组a进行正确初始化的语句是:( )
A.int a[2][] = { {0,1,2},{3,4,5} };
B.int a[][3] = { {0,1,2},{3,4,5} };
C.int a[2][4] = { {0,1,2},{3,4},{5} };
D.int a[][3] = { {0,,2},{},{3,4,5} };
答案:B
4. 关于一维数组初始化,下面哪个定义是错误的?( )
A.int arr[10] = { 1,2,3,4,5,6 };
B.int arr[] = { 1,2,3,4,5,6 };
C.int arr[] = (1, 2, 3, 4, 5, 6);
D.int arr[10] = { 0 };
答案:C
5. 关于一维数组描述不正确的是:( )
A.数组的下标是从0开始的
B.数组在内存中是连续存放的
C.数组名表示首元素的地址
D.随着数组下标的由小到大,地址由高到低
答案:D
6. 冒泡排序
实现一个对整形数组的冒泡排序
int main()
{
int arr[10] = { 1,3,2,5,4,8,7,9,6,10 };
int i = 0;//要交换的轮数(n-1)
int j = 0;//每轮要交换的次数(n-1-i)
int sz = sizeof(arr) / sizeof(arr[0]);//数组元素个数
for (i = 0; i < sz - 1; i++)
{
int flag = 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;
flag = 1;
}
}
if (0 == flag)
break;
}
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
7. 使用函数实现数组操作
创建一个整形数组,完成对数组的操作
实现函数init() 初始化数组为全0
实现print() 打印数组的每个元素
实现reverse() 函数完成数组元素的逆置。
要求:自己设计以上函数的参数,返回值。
void init(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
arr[i] = 0;
}
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
void revese(int arr[], int sz)
{
int left = 0;
int right = sz - 1;
while (left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
//memset(arr, 0, sizeof(arr));
init(arr, sz);
print(arr, sz);
revese(arr, sz);
return 0;
}
8. 一维数组】交换数组
将数组A中的内容和数组B中的内容进行交换。(数组一样大)
int main()
{
int arr1[10] = { 0 };
int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i < 10; i++)
{
int tmp = arr1[i];
arr1[i] = arr2[i];
arr2[i] = tmp;
}
for ( i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
for ( i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
9. 下面代码的结果是:( )
int main()
{
char str[] = "hello bit";
printf("%d %d\n", sizeof(str), strlen(str));
return 0;
}
//A. 10 9
//B. 9 9
//C. 10 10
//D. 9 10
//答案:A
10. 下面代码的结果是:( )
int main()
{
int arr[] = { 1,2,(3,4),5 };
printf("%d\n", sizeof(arr));
return 0;
}
//A.4
//B.16
//C.20
//D.5
//答案:B
11. 给出以下定义:
char acX[] = "abcdefg";
char acY[] = { 'a','b','c','d','e','f','g' };
//以下说法正确的是()
//A.数组acX和数组acY等价
//B.数组acX和数组acY的长度相同
//C.sizeof(acX) > sizeof(acY)
//D.strlen(acX) > strlen(acY)
//答案:C
12. 有一个整数序列(可能有重复的整数),现删除指定的某一个整数,输出删除指定数字之后的序列,序列中未被删除数字的前后位置没有发生改变。
输入描述:
第一行输入一个整数(0≤N≤50)。
第二行输入N个整数,输入用空格分隔的N个整数。
第三行输入想要进行删除的一个整数。
输出描述:
输出为一行,删除指定数字之后的序列。
自己方法的思路:遍历数组,如果要删除的数和数组某个数相等则不打印
int main() {
int n = 0;//有几个数
scanf("%d\n", &n);
int i = 0;
int arr[n];//牛客网支持变长数组
//接收n个数字
for (i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
int b = 0;//要删除的数
scanf("%d\n", &b);
for (i = 0; i < n; i++) {
if (b == arr[i])
continue;
printf("%d ", arr[i]);
}
return 0;
}
老师方法的思路:用两个下标变量(i和j)进行比较,i是原数组下标,如果i下标的数不等于要删除的数就放到j下标,最后打印遍历打印j下标的元素
int main() {
int n = 0;//有几个数
scanf("%d\n", &n);
int arr[n];//牛客网支持变长数组
//接收n个数字
int i = 0;
for (i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
int del = 0;//要删除的数
scanf("%d\n", &del);
int j = 0;//j作为下标锁定的位置就是用来存放不删除的数据的
for (i = 0; i < n; i++) {
if (arr[i] != del)
{
//j最开始是0,先试用,后++。如果arr[i]不等于要删除的数,就存到arr[j]里面并++
//这一步是将不等于del的元素移到前面
arr[j++] = arr[i];
//等效下方
//arr[j] = arr[i];
//j++;
}
}
for (i = 0; i < j; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
13. 输入n个成绩,换行输出n个成绩中最高分数和最低分数的差。
输入描述:
两行,第一行为n,表示n个成绩,不会大于10000。
第二行为n个成绩(整数表示,范围0~100),以空格隔开。
输出描述:
一行,输出n个成绩中最高分数和最低分数的差。
自己方法的思路:用冒泡排序将数组从小到大排列,比较第一个元素和最后一个元素的差
int main() {
int n = 0;
scanf("%d", &n);
int i = 0;
int arr[n];
for (i = 0; i < n; i++)
{
scanf("%d ", &arr[i]);
}
//冒泡排序
for (i = 0; i < n - 1; i++)
{
int j = 0;
for (j = 0; j < n - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
int ret = arr[n - 1] - arr[0];
printf("%d\n", ret);
return 0;
}
老师方法的思路:
假设第一个元素最大,将数组里面的元素和它逐一比较,比他大就替换;
假设第一个元素最小,将数组里面的元素和它逐一比较,比他小就替换;
优化:
在向数组输入数据时就可以比较
继续优化:
假设最大值是0,最小值是100,在向数组输入数据时直接比较
int main()
{
int n = 0;
scanf("%d", &n);
int i = 0;
int arr[n];
//输入
for (i = 0; i < n; i++)
{
scanf("%d ", &arr[i]);
}
//找出最大值
int max = arr[0];//假设第一个元素最大
for (i = 1; i < n; i++)//不需要从下标为0的第一个元素开始,因为已经假设了一个元素
{
if (arr[i] > max)
max = arr[i];
}
//找出最小值
int min = arr[0];//假设第一个元素最小
for (i = 1; i < n; i++)
{
if (arr[i] < min)
min = arr[i];
}
int ret = max - min;
printf("%d\n", ret);
//优化版本
int max = arr[0];
int min = arr[0];
for (i = 1; i < n; i++)
{
scanf("%d ", &arr[i]);
if (arr[i] > max)
max = arr[i];
if (arr[i] < min)
min = arr[i];
}
//继续优化
int main()
{
int n = 0;
scanf("%d", &n);
int i = 0;
int arr[n];
int min = 100;//同下
int max = 0;//最大值设置0,因为如果设置成100,那么可能数组里没有数比它大
for (i = 0; i < n; i++)
{
scanf("%d ", &arr[i]);
if (arr[i] > max)
max = arr[i];
if (arr[i] < min)
min = arr[i];
}
return 0;
}