本章节分为:一维数组创建和初始化、二维数组创建和初始化、数组越界、数组作为函数参数。
第一节:一维数组创建和初始化
数组就是一组相同类型元素的集合。
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