文章目录
1 概念
数组是用来存储一组相同数据类型的数据的。
数组是一个构造类型。
数组中的每个数据称为数组的元素或者数组的成员。
数组的元素在内存上是连续的。不管几维数组,都是连续的。
2 一维数组
2.1 概念
所谓的一维数组就是下标只有一个的数组。
一维数组的元素在内存上是连续。
2.2 定义一维数组的格式
存储类型 数据类型 数组名[下标];
存储类型:先不用管,不写默认的就是 auto
数据类型:数组中每个元素的数据类型,既可以是基本类型,也可以是构造类型 (数组除外)
数组名:是一个标识符,要符合标识符的命名规范
下标:在定义数组的时候,下标一般是一个常量,表示数组元素的个数
在其他场景下,可以是常量、变量、表达式,表示访问数组中第几个元素
例:
1 int s[5]; //定义了一个一维数组 数组名叫s 数组中共有5个元素
2 //每个元素都是一个 int 类型的变量
2.3 一维数组的性质
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 //定义了一个一维数组 数组名叫s 数组中共有5个元素
6 //每个元素都是一个 int 类型的变量
7 int s[5];
8
9 //一维数组的大小 == 单个元素的大小 * 元素的个数
10 printf("sizeof(s) = %ld\n", sizeof(s)); //20 == sizeof(int) * 5
11 //此条为计算数组的长度
12 //一维数组访问元素的方式
13 // 数组名[下标] 注意:下标从0开始
14 //当取出数组中某个元素时 对该元素的操作 就和操作普通变量是一模一样的
了
15 s[0] = 10;
16 s[1] = 20;
17 s[2] = 30;
18 s[3] = 40;
19 s[4] = 50;
20 printf("s[0] = %d\n", s[0]);//10
21 printf("s[1] = %d\n", s[1]);//20
22 printf("s[2] = %d\n", s[2]);//30
23 printf("s[3] = %d\n", s[3]);//40
24 printf("s[4] = %d\n", s[4]);//50
25
26 //注意:数组名是一个常量 不能被赋值 也不能++
27 //s = 100; //错误的
28 //s++; //错误的
29
30 //一维数组的元素在内存上是连续的
31 // & 取地址符 表示获取变量在内存上的地址编号
32 // 对于多字节的变量 取地址 取到的是编号最小的那个 称为 首地址
33 // printf 使用 %p 可以打印变量的地址 十六进制
34 printf("&s[0] = %p\n", &s[0]);//依次相差4字节 因为数组是int类型的
35 printf("&s[1] = %p\n", &s[1]);
36 printf("&s[2] = %p\n", &s[2]);
37 printf("&s[3] = %p\n", &s[3]);
38 printf("&s[4] = %p\n", &s[4]);
39
40 //数组一旦定义好了 就不能整体赋值了
41 //只能一个元素一个元素的赋值了
42 int s2[5];
43 //s2 = s;//数组名是常量 不能被赋值
44 //s2[5] = s[5];//错误的 越界访问
45
46 //遍历一维数组
47 int i = 0;//做为数组下标使用
48 //for(i = 0; i < 5; i++){
49 for(i = 0; i < sizeof(s)/sizeof(s[0]); i++){
50 printf("%d ", s[i]);
51 }
52 printf("\n");
53
54 return 0;
55 }
2.4 一维数组的初始化
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 //定义了一维数组 没有初始化 里面存的也是随机值
6 //int s[5];
7
8 //完全初始化
9 //int s[5] = {10, 20, 30, 40, 50};
10
11 //不完全初始化
12 //这种初始化的方式是从左到右依次初始化 没有初始化的元素 都用0来初始
化
13 //int s[5] = {10, 20};
14
15 //全部初始化成0 ‐‐‐‐最常用的方式
16 //int s[5] = {0};
17
18 //省略下标的初始化
19 //这种写法 编译器会根据给定的元素个数自动计算需要给数组分配多大的内
存空间
20 int s[] = {10, 20, 30, 40, 50};
21
22 //遍历一维数组
23 int i = 0;
24 for(i = 0; i < 5; i++){
25 printf("%d ", s[i]);
26 }
27 printf("\n");
28
29 return 0;
30 }
2.5 关于一维数组访问越界的问题(要特别注意)
1 #include <stdio.h>
2
3 #define N 5
4
5 int main(int argc, const char *argv[])
6 {
7 int s[N];
8
9 //数组越界访问的问题 编译器不会检查
10 //需要程序员自己检查
11 //数组越界导致的问题是不可预知的
12 //可能不报错
13 //也可能段错误
14 //也有可能修改了不该修改的数据
15 s[5234] = 123;
16 printf("%d\n", num);
17
18 return 0;
19 }
练习:
1.定义一个一维数组,类型为 int ,长度(元素的个数)为10
从终端给数组的10个元素赋值
找出数组中最大的元素及最大元素的下标,并输出。
1 int s[10];
2 int i = 0;
3 for(i = 0; i < 10; i++){
4 scanf("%d", &s[i]);
5 }
3 二维数组
3.1 二维数组
所谓的二维数组,就是下标有两个的数组。
3.2 格式
存储类型 数据类型 数组名[行数][列数];
二维数组的元素在内存上也是连续的。
二维数组本质也是一维数组,有了行号,只是多了一种按行访问元素的方式。
二维数组的列数很重要,因为他决定了按行操作时,每行跨过的元素的个数。
3.3 二维数组的性质
3.4 二维数组的初始化
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 //二维数组如果不初始化 里面也是随机值
6 //int s[3][4];
7
8 //以行为单位
9 //完全初始化
10 //int s[3][4] = {{1,2,3,4}, \
11 {5,6,7,8}, \
12 {9,10,11,12}};
13 //不完全初始化 没有初始化的位 也是用0来初始化
14 //int s[3][4] = {{1,2},{5},{9,10,11}};
15
16 //不以行为单位
17 //完全初始化
18 //int s[3][4] = {1,2,3,4,\
19 5,6,7,8,9,\
20 10,11,12};
21 //不完全初始化 没有初始化的位 也是用0来初始化
22 //int s[3][4] = {1,2,5,9,10,11};
23**最常用的初始化方法:**
24 //全部初始化成0 ‐‐常用的用法
25 //int s[3][4] = {0};
26
27 //省略下标的初始化
28 //行数能省略 但是列数不能省略 因为列数决定了按行操作时跨过的元素的个
数
29 int s[][4] = {1,2,3,4,5,6,7,8,9};
30 //这种写法即使元素不足整行 也会按整行分配空间 不够的元素用0初始化
31 printf("sizeof(s) = %ld\n", sizeof(s));//48
32
33 //遍历二维数组
34 int i = 0;
35 int j = 0;
36 for(i = 0; i < 3; i++){
37 for(j = 0; j < 4; j++){
38 printf("%d ", s[i][j]);
39 }
40 printf("\n");
41 }
42
43 return 0;
44 }
练习:
1.定义一个3行4列的二维数组,并以行为单位完全初始化;
找出数组中最大的元素,及最大元素的行号、列号、并输出。
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 int s[3][4] = {{1,2,3,4},
6 {5,6,7,888},
7 {9,10,11,12}};
8 int max_h = 0;
9 int max_l = 0;
10
11 //遍历二维数组 比较
12 int i = 0;
13 int j = 0;
14 for(i = 0; i < 3; i++){
15 for(j = 0; j < 4; j++){
16 if(s[max_h][max_l] < s[i][j]){
17 max_h = i;
18 max_l = j;
19 }
20 }
21 }
22 printf("max_h = %d, max_l = %d, max_value = %d\n",
23 max_h, max_l, s[max_h][max_l]);
24
25 return 0;
26 }
2.使用二维数组保存杨辉三角的值并输出 10行10列
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 int s[10][10] = {0};
6 int i = 0;
7 int j = 0;
8 //循环给数组赋值
9 for(i = 0; i < 10; i++){
10 s[i][0] = 1;
11 for(j = 1; j <= i; j++){
12 s[i][j] = s[i‐1][j] + s[i‐1][j‐1];
13 }
14 }
15
16 //遍历 输出
17 for(i = 0; i < 10; i++){
18 for(j = 0; j <= i; j++){
19 printf("%‐4d", s[i][j]);
20 }
21 printf("\n");
22 }
23
24 return 0;
25 }
4 字符数组和字符串
字符串数组:char类型的数组
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 //字符数组:数组中每个元素都是一个char类型的变量
6 char s1[5] = {'h', 'e', 'l', 'l', 'o'};
7 int i = 0;
8 for(i = 0; i < 5; i++){
9 printf("%c", s1[i]);
10 }
11 printf("\n");
12
13 //将字符串存储在字符数组中可以有下面的写法
14 char s2[6] = {"abcde"}; //字符串结尾都有一个隐藏字符 '\0'
15 printf("s2 = [%s]\n", s2);//abcde
16 char s3[6] = "12345"; //常用的写法
17 printf("s3 = [%s]\n", s3);//12345
18 char s4[] = "hqyj";//sizeof(s4) == 5 因为结尾的 '\0' 也回被算进去
19 printf("s4 = [%s]\n", s4);//hqyj
20 //%s的意思是按照字符串形式输出
21 //注意:如果不是字符串 就不能使用 %s 输出了
22 //因为 %s 是通过找 '\0' 来确定结束的 不是字符串 就不一定有'\0',则%s会一直往后找
23 //有可能会出现 越界的情况 如前面的 s1 就不行
24 printf("s1 = [%s]\n", s1);// hello+不确定的 且一定越界访问了
25
26 char s5[6] = {'h', 'e', 'l', 'l', 'o'};
27 printf("s5 = [%s]\n", s5);//这样是可以的
28 //因为不完全初始化 没有初始化的元素默认都用0初始化 而 0 就是 '\0'
29
30 // 0 '\0' '0'
31 // 这三个零中 前两个是一样的 ascii码就是0 而第三个'0'的ascii码是 48
32
33 return 0;
34 }
5 字符串处理函数
strlen strcpy strcat strcmp
5.1 strlen
1 功能:
2 计算字符串的长度(字符串中第一个'\0'之前的字符的个数)(不包括 '\0')
4 头文件:
5 #include <string.h>
6 函数原型:
7 size_t strlen(const char *s);
8 参数:
9 s:要计算长度的字符串
10 返回值:
11 计算的结果
例:
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(int argc, const char *argv[])
5 {
6 char s1[32] = "hello";
7 //可以直接把结果输出到终端
8 printf("strlen(s1) = %ld\n", strlen(s1));//5
9
10 //也可以定义变量来保存计算的结果
11 int ret = strlen(s1); //涉及到隐式强转,这里被认为是安全的
12 printf("ret = %d\n", ret);//5
13
14 //strlen计算长度时遇到 '\0' 就结束了
15 char s2[32] = "abcd\0qwertoiu";
16 printf("strlen(s2) = %ld\n", strlen(s2));//4
17
18 //也可以直接计算字符串常量的长度
19 printf("strlen(\"abcdef\") = %ld\n", strlen("abcdef"));//6
20
21 //如果不是字符串 就不能使用strlen计算长度了
22 char s3[5] = {'h', 'e', 'l', 'l', 'o'};
23 //错误的用法 strlen会一直向后找 遇到'\0'才结束
24 //printf("strlen(s3) = %ld\n", strlen(s3));
25
26 //要注意 strlen 和 sizeof 的 区别
//strlen是函数 是计算第一个'\0'前字符的个数
//而siziof()是C语言的关键字 是计算占用的内存空间的大小
27 //char s1[32] = "hello";
28 printf("strlen(s1) = %ld\n", strlen(s1));//5
29 printf("sizeof(s1) = %ld\n", sizeof(s1));//32
30
31 return 0;
32 }
练习:
自己实现 strlen 函数的功能。
明确知道数据范围的起点和终点,用for循环遍历较多;否则用while循环,如下
1 #include <stdio.h>
2 int main(){
3 char s[64] = "hello world";
4 int i = 0;
5 //表达式 使用下面三种写法 都可以
6 //while(s[i] != '\0'){
7 //while(s[i] != 0){
8 while(s[i]){
9 i++;
10 }
11 printf("len = %d\n", i);
12 return 0;
13 }
5.2 strcpy
字符串在定义好之后无法整体赋值,想要赋值或者修改只能在对应位置一个一个改
1 功能:
2 字符串的拷贝 将 src 拷贝给 dest
3 //要保证 dest 足够大
4 头文件:
5 #include <string.h>
6 函数原型:
7 char *strcpy(char *dest, const char *src);
8 参数:
9 src:源字符串
10 dest:目标字符串
11 返回值:
12 目标字符串dest,我们一般不关心
例:
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(int argc, const char *argv[])
5 {
6 char s1[32] = "beijing";
7 char s2[32] = "hqyj";
8
9 printf("前:s1 = [%s]\n", s1);//beijing
10 printf("前:s2 = [%s]\n", s2);//hqyj
11
12 strcpy(s1, s2);//将s2拷贝给s1 先写目标再写源。要保证s1足够大
13
14 printf("后:s1 = [%s]\n", s1);//hqyj
15 printf("后:s2 = [%s]\n", s2);//hqyj
16 //也可以将字符串常量拷贝给数组
char s3[32] = {0};
strcpy(s3,"hello");
17 //s1中超过的字符串还在s1中 只不过通过字符串的方式访问不到了
18 printf("s1[4] = [%d][%c]\n", s1[4], s1[4]);// 0
19 printf("s1[5] = [%d][%c]\n", s1[5], s1[5]);// n
20 printf("s1[6] = [%d][%c]\n", s1[6], s1[6]);// g
21
22 return 0;
23 }
练习:
自己实现 strcpy 函数的功能。
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 char s1[32] = "beijing";
6 char s2[32] = "hqyj";
7 printf("前:s1 = [%s]\n", s1);//beijing
8 printf("前:s2 = [%s]\n", s2);//hqyj
9
10 //你自己的操作
11 int i = 0;
12 while(s2[i] != '\0'){
13 s1[i] = s2[i];
14 i++;
15 }
16 s1[i] = s2[i];//将s2的 '\0' 也复制给s1
17
18 printf("后:s1 = [%s]\n", s1);//hqyj
19 printf("后:s2 = [%s]\n", s2);//hqyj
20
21 return 0;
22 }
5.3 strcat
1 功能:
2 字符串的拼接 将src拼接到dest后面
3 //会覆盖dest结尾的'\0'
4 //注意:要保证 dest 足够大
5 头文件:
6 #include <string.h>
7 函数原型:
8 char *strcat(char *dest, const char *src);
9 参数:
10 src:源字符串
11 dest:目标字符串
12 返回值:
13 目标字符串dest,我们一般不用
例:
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(int argc, const char *argv[])
5 {
6 char s1[32] = "hello";
7 char s2[32] = "12345678";
8 printf("前:s1 = [%s]\n", s1);//hello
9 printf("前:s2 = [%s]\n", s2);//12345678
10
11 strcat(s1, s2);//将s2追加到s1的后面
12
13 printf("后:s1 = [%s]\n", s1);//hello12345678
14 printf("后:s2 = [%s]\n", s2);//12345678
15
16 return 0;
17 }
练习:
自己实现 strcat 函数的功能。
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 char s1[32] = "hello";
6 char s2[32] = "12345678";
7 printf("前:s1 = [%s]\n", s1);//hello
8 printf("前:s2 = [%s]\n", s2);//12345678
9
10 //你自己的操作
11 //先找到 s1 的 '\0' 的下标
12 int i = 0;
13 while(s1[i] != '\0'){
14 i++;
15 }
16 //再一位一位的追加
17 int j = 0;
18 while(s2[j] != '\0'){
19 //s1[i++] = s2[j++]; //把下面三行换成这种写法也行
20 s1[i] = s2[j];
21 i++;
22 j++;
23 }
24 s1[i] = s2[j];//将s2的 '\0' 也追加给s1
25
26 printf("后:s1 = [%s]\n", s1);//hello12345678
27 printf("后:s2 = [%s]\n", s2);//12345678
28
29 return 0;
30 }
5.4 strcmp