数组
- 定义:把若干个相同类型的变量,存放在一块连续的内存中
- 其中的每一个变量叫做元素,也是数组的最小单位
- 数组中的元素从0开始,其中每一个元素都是一个变量
- 构造类型:将基本类型构建成为的类型
- 数组:相同类型的数据存放在一个集合中,这种的构造类型数组
- 结构体:将不同类型的数据放在一个集合中
定义数组
1 |
|
- 数组中的元素个数由[]中的数值决定
- 每个元素的类型由数组前面的类型觉得
- 定义数组的时候[]中的值,只能是常量
- 使用时候,[]中的值可以是变量
- 数值数组不能整体操作 ,如果我们想要全部打印出来可以使用循环
- 如果数组中的元素没有初始化,是随机值
数组的初始化
1 |
|
- 如果数组只初始化部分的元素,其他的元素初始化为0
1 | int num[3] = {0}; // 初始化所有的元素为0 |
数组的大小
- 获取数组中元素的个数
1 |
|
- 这样我们在for循环中就可以直接写数组的长度来作为,循环的结束条件
数据在内存中的地址
数据在内存中如何存储
- 启动一个程序系统会给这个程序分配一快内存空间,内存的最小单位是一字节
- 内存中的每一个字节都会由一个编号,这个标号我们把他叫做内存地址
- 比如我们定义一个char类型的变量就会占用一个字节,会由一个定义
- 如果我们定义一个int 类型的变量,会占用4个字节,数据在内存中的地址是他的起始地址
数组的地址和数组名
- 列子:在内存中我们定义一个int数组,其中包含5个元素:int a[5];
- 数组名a代表数组,也代表第0个元素的地址
- 所以说数组名是一个常量,是一个地址,不能被赋值
- &a : 整个数组的地址
- 在数值上 取地址&a[0],a,&a 相等
- &a[0]+1 取地址 a + 1 元素的地址加1 跨过一个元素
- a + 1 元素的地址加1 跨过一个元素
- &a + 1: 整个数组的地址加1 ,跨过整个数组
1 |
|
数组练习求数组最大值
1 |
|
数组逆序
1 |
|
数组排序-冒泡排序的原理
- 相邻两个元素比较,前面的比后面的大,两元素交换
- 例如我们有 :4,76,8,9,3
- 第一轮比较4次:4,8,9,3,76
- 第二轮比较3次:4,8,3,9,76
- 第三轮比较2次:4,3,8,9,76
- 第四轮比较1次:3,4,8,9,76
- 一共有n个元素,一共比较n-1轮,每比较一轮,下一轮少比较一次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int main()
{
int a[5] = {2,5,7,3,-2};
int n = sizeof(a) / sizeof(a[0]);
for (int i = 0; i < n - 1; i++)
{
//因为每次比较的次数都要减一,刚好每次i+1
for (int j = 0; j < n - 1 - i ; j++)
{
if(a[j] > a[j + 1])
{
int tmp = a[j + 1];
a[j + 1] = a[j];
a[j] = tmp;
}
}
}
for (i = 0; i < n;i++)
{
printf("%d ",a[i]);
}
return 0;
}
二维数组
- int a[2] [4]定义了一个二维数组,二位数组中有两个一维数组,每个一维数组有四个元素
a[0] [0] | a[0] [1] | a[0] [2] | a[0] [3] |
---|---|---|---|
a[1] a[0] | a[1] a[1] | a[1] a[2] | a[1] a[3] |
1 |
|
- 如果我们需要输出二维数组,需要使用双重循环
二位数组的初始化
1 |
|
给二位数组的部分元素初始化,其他元素为0
定义数组中的列必须要写,可以省略行的下标
求二位数组的行和列
1 |
|
二位数组的行数需要使用总大小除以行的大小
二位数组的列数需要使用行的大小除以一个元素的大小即可
二位数组的数组名称
int a[2] [3]
a[0] [0] :第零行第零个元素
&a[0] [0]:第零行第零个元素的地址 = 01
a[0] :代表第0行一维数组的数组名,a[0] = &a[0] [0] = 01
&a[0] 代表第0行的地址 01
a:二位数组数组名,代表二位数组,代表着首行的地址&a[0]
&a:二位数组的地址
关于各项加一其代表的意义
&a[0] [0] +1 元素地址加1,跨过一个元素
a[0] + 1 元素地址加1,跨过一个元素
&a[0] + 1 行地址加1,跨过一行
a + 1 行地址加1 ,跨过一行
&a +1 二位数组地址加1,跨过整个数组
代码的验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main()
{
int a[3][4];
printf("%u\n",&a[0][0]);
printf("%u\n",a[0]);
printf("%u\n",&a[0]);
printf("%u\n",a);
printf("%u\n",&a);
printf("--------\n");
printf("%u\n",&a[0][0]+1);
printf("%u\n",a[0]+1);
printf("%u\n",&a[0]+1);
printf("%u\n",a+1);
printf("%u\n",&a+1);
return 0;
二维数组的练习
1 | float a[5] [3] = {{80,75,54},{32,45,78},{34,54,78},{23,43,6},{34,56,76}}; |
求各科成绩的平均分
统计各科不及格的人数
代码演示
1 |
|
多维数组
- int a [2] [3] [4]:定义了一个三维数组,有两个二维数组,每个二维数组有三个一维数组,每个一维数组有四个元素
- 关于初始化和打印和二维数组类似
字符数组
- 每个元素是char类型
1 |
|
本质上里面存储的是accil码值
初始化部分元素其他元素为0
我们是用%s来打印字符串
如果我们使用%s来打印字符数组,我们需要在后面加上\0
如果没有\0就是普通的字符数组,含有\0也叫字符串
字符串就是字符数组中有\0字符的数组
因为有\0的字符数组 操作起来方便
字符数组的初始化
1 |
|
如上的代码因为没有\0所以会出现乱码的情况
所以我门更加常用的的是使用双引号来直接赋值字符串
1 |
|
- 没有\0就会一直向后面打印,出现乱码
scanf输入字符串
使用%c只能读取一个字符
所以如果我梦想要实现输入字符串,就需要先定义一个数组
因此我们能就需要是用%s来获取一个字符串,\n后结束
1 |
|
需要注意的一点:遇到\n后会结束,遇到空格也会结束
如果我们的数组大小小于输入的字符,机会造成内存污染
gets
- gets是一个库函数
1 |
|
gets遇到\n会结束但是遇到空格不会结束
gets也会造成内存污染
fgets
库函数:从键盘读取一个字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
char num[134] = "";
fgets(num,sizeof(num),stdin);
int x = strlen(num);
num[x-1] = 0;
int i = 0;
while (num[i] != '\0')
{
i++;
}
printf("%s\n",num);
return 0;
}最大可以读取sizeof(num) -1 个元素
fgets会把回车读取,如果我门不想让函数输出那个回车我们可以使用strlen来获取字符数组的长度,将最后一个元素改为0即可
相对于scanf和gets 更加的安全,但是会读取回车
我们不仅可以使用strlen来获取最后一个元素来改为0,我们也可以使用循环来找到\0的位置,将前面的回车改为\0也可以达到相同的结果
strlen
- 库函数:求字符数组的字符个数
- 参数是要的是字符数组的首元素的地址
字符数组的输出
1 |
|
- fputs:第一个参数是数组的首元素地址,stdout是标准输出(屏幕)
字符串的追加
1 |
|
- 以上的代码实现了将str2追加到str1的后面
猜数字
1 |
|
课后练习
字符串大小写转换
1 |
|
字符串比较
1 |