C语言入门篇(六)

男娘i 2024-04-23 20:24 177阅读 0赞

前言
  C 语言支持数组数据结构,数组是用来存储一系列数据,而且是一系列相同类型的变量。

数组

    1. 一维数组
    • 1.1 数组的创建
    • 1.2 数组的初始化
    • 1.3 数组的使用
    • 1.4 数组在内存中的存储
    1. 二维数组
    • 1.1 数组的创建
    • 1.2 数组的初始化
    • 1.3 数组的使用
    • 1.4 数组在内存中的存储
    1. 数组越界
    1. 数组作为函数参数
    • 4.1 数组名你用对了吗?
  • 结束语

1. 一维数组

数组是一组相同类型元素的集合。(存放一组数)

1.1 数组的创建

数组创建方式:

  1. type_t arr_name [const_n];
  2. //type_t 指数组的元素类型
  3. //const_n 常量表达式,指定数组的大小

?数组创建实例:

  1. int arr[9];
  2. //不同数据类型的数组
  3. char arr2[10];
  4. float arr3[9];
  5. double arr4[5];
  6. //下面是一个错误例子:
  7. int n=9;
  8. int arr1[n];//[]中必须是常量表达式

?注:
数组创建,在C99标准之前,[ ]中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化。

1.2 数组的初始化

数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值。

比如:

  1. int arr1[10] = {
  2. 1,2,3,4,5,6,7,8,9,10};//完全初始化
  3. int arr2[10] = {
  4. 1,2,3 };//不完全初始化,剩余的元素默认都是0
  5. int arr3[10] = {
  6. 0 };//不完全初始化,剩余的元素默认都是0
  7. int arr4[] = {
  8. 0 };//省略数组的大小,数组必须初始化,数组的大小是根据初始化的内容来确定
  9. char arr5[]={
  10. 'a','c'9};
  11. char arr6[]="abc";
  12. char arr7[3]={
  13. 'a','b','c'};
  14. int arr8[];//错误

?数组在创建的时候如果想不指定数组的确定的大小就得初始化。

?数组的元素个数根据初始化的内容来确定。

1.3 数组的使用

对于数组的使用我们之前介绍了一个操作符:[],下标引用操作符。它就是数组访问的操作符。

下图是一个长度为 10 的数组,第一个元素的索引值为 0,第九个元素的索引值为 8:
在这里插入图片描述

对数组元素进行索取:

在这里插入图片描述
?实例1:计算数组元素个数

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int arr[10] = {
  5. 1,2,3,4,5,6,7,8,9,10};//数组的不完全初始化
  6. int sz = sizeof(arr) / sizeof(arr[0]); //计算数组的元素个数
  7. printf("%d\n",sz);
  8. return 0;
  9. }

?sizeof:返回一个对象或者类型所占的内存字节数

?实例2:输出数组元素

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int arr[10] = {
  5. 0 };//数组的不完全初始化
  6. //对数组内容赋值,数组是使用下标来访问的,下标从0开始。
  7. int i;//做下标
  8. for (i = 0; i < 10; i++)//定义的数组有10个元素,所以下标是从0-9
  9. {
  10. arr[i] = i;
  11. }
  12. //输出数组的内容
  13. for (i = 0; i < 10; ++i)
  14. {
  15. printf("%d ", arr[i]);
  16. }
  17. return 0;
  18. }

在不知道数组长度的情况下,该如何控制for语句的循环条件?

?实例3:

  1. #include<stdio.h>
  2. int main()
  3. {
  4. int arr[10] = {
  5. 1,2,3,4,5,6,7,8,9,10 };
  6. int i = 0;
  7. int sz = sizeof(arr) / sizeof(arr[0]);
  8. //将i<10改为i<sz
  9. for (i = 0; i < sz; i++)
  10. {
  11. printf("%d ", arr[i]);
  12. }
  13. return 0;
  14. }

?数组是使用下标来访问的,下标是从0开始。

?数组的大小可以通过计算得到。

  1. //计算数组大小
  2. int arr[10];
  3. int sz = sizeof (arr)/sizeof(arr [0]);

1.4 数组在内存中的存储

我们先看一段代码:

  1. #include<stdio.h>
  2. int main()
  3. {
  4. int arr[10] = {
  5. 1,2,3,4,5 };
  6. int sz = sizeof(arr) / sizeof(arr[0]);//计算数组大小
  7. int i = 0;
  8. for (i = 0; i < sz; i++)
  9. {
  10. printf("&arr[%d] = %p\n", i, &arr[i]);//%p -- 用来打印地址
  11. }
  12. return 0;
  13. }

运行结果:

在这里插入图片描述
在内存中的存储地址:
在这里插入图片描述

仔细观察,可以发现后一个元素的地址比前一个元素的地址增4
说明了:数组在内存中是连续存放的,而且由高到低。

2. 二维数组

1.1 数组的创建

  1. int arr[3][4];//3行4列
  2. char arr[3][5];
  3. float arr[1][3];

1.2 数组的初始化

  1. //数组初始化
  2. int arr[3][4] = {
  3. 1,2,3,4};
  4. int arr[3][3] = {
  5. {
  6. 1,2,3},{
  7. 4,5,6},{
  8. 7,8,9}};
  9. int arr[][4] = {
  10. {
  11. 2,3},{
  12. 4,5}};//二维数组如果有初始化,行可以省略,列不能省略

?二维数组的行可以省略,但列不能省

比如:有二维数组

  1. int arr[3][3]={
  2. 1,2,3,4,5,6,7,8,9};

在这里插入图片描述

如果只知道行,无法确定(推出)数组的列数
如果知道了列,就知道了下一行从哪里开始

1.3 数组的使用

二维数组的使用也是通过下标的方式:

  1. #include<stdio.h>
  2. int main()
  3. {
  4. int arr[4][5] = {
  5. {
  6. 1,2,3,4,5},{
  7. 2,3,4,5,6},{
  8. 3,4,5,6,7},{
  9. 5,6,7,8,9} };
  10. printf("%d\n", arr[2][3]);//6
  11. return 0;
  12. }

?实例:

  1. #include<stdio.h>
  2. int main()
  3. {
  4. int arr[4][5] = {
  5. {
  6. 1,2,3,4,5},{
  7. 2,3,4,5,6},{
  8. 3,4,5,6,7},{
  9. 5,6,7,8,9} };
  10. int i ;//用i控制行,下标是0-3
  11. for (i = 0; i < 4; i++)//外循环控制行
  12. {
  13. int j ;//j控制列,下标是0-4
  14. for (j = 0; j < 5; j++)//内循环控制列
  15. {
  16. printf("%d ", arr[i][j]);//输出整个数组
  17. }
  18. printf("\n");//每行打印完后,换行
  19. }
  20. return 0;
  21. }

1.4 数组在内存中的存储

像一维数组一样,这里我们尝试打印二维数组的每个元素:

  1. #include<stdio.h>
  2. int main()
  3. {
  4. int arr[3][4] = {
  5. 0 };
  6. int i = 0;
  7. for (i = 0; i < 3; i++)
  8. {
  9. int j = 0;
  10. for (j = 0; j < 4; j++)
  11. {
  12. printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
  13. }
  14. }
  15. return 0;
  16. }

运行结果:

在这里插入图片描述

可以发现:二维数组在内存中也是连续存储的

3. 数组越界

数组的下标是有范围限制的。
数组的下标规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1

数组的下标如果小于0,或者大于n-1,就是数组越界访问了。

比如这段代码:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int arr[10] = {
  5. 1,2,3,4,5,6,7,8,9,10};
  6. int i = 0;
  7. for(i=0; i<=10; i++)
  8. {
  9. printf("%d\n", arr[i]);//当i等于10的时候,越界访问了
  10. }
  11. return 0;
  12. }

?二维数组的行和列也可能存在越界。

4. 数组作为函数参数

在写代码的时候,需要将数组作为参数传给函数。

比如:实现一个冒泡排序函数将一个整形数组排序。

冒泡排序:依次比较两个相邻的元素的大小,按照升序或降序排列,重复的比较,直到所有元素排列完成。
在这里插入图片描述

代码实现:

  1. //升序排列
  2. void bubble_sort(int* arr, int sz)//这里的arr的本质是指针
  3. {
  4. int i = 0;
  5. for (i = 0; i < sz - 1; i++)//数组下标范围:0-sz-1,
  6. {
  7. int j = 0;
  8. int flag = 1;//假设已经是有序数组
  9. //进行比较
  10. for (j = 0; j < sz - 1 - i; j++)
  11. {
  12. if (arr[j] > arr[j + 1])
  13. {
  14. //交换
  15. int temp = arr[j];
  16. arr[j] = arr[j + 1];
  17. arr[j + 1] = temp;
  18. flag = 0;
  19. }
  20. }
  21. if (flag == 1)
  22. break;
  23. }
  24. }
  25. int main()
  26. {
  27. int arr[10] = {
  28. 0 };
  29. int i ;
  30. int sz = sizeof(arr) / sizeof(arr[0]);//计算数组大小
  31. for (i = 0; i < sz; i++)
  32. {
  33. scanf("%d", &arr[i]);//输入
  34. }
  35. //arr作为数组进行了传参
  36. bubble_sort(arr, sz);//arr 是数组首元素的地址,传递的是首元素的地址
  37. for (i = 0; i < sz; i++)
  38. {
  39. printf("%d ", arr[i]);//输出排好序的数组元素
  40. }
  41. return 0;
  42. }

当数组传参的时候,实际上只是把数组的首元素的地址传递过去了。

所以即使在函数参数部分写成数组的形式: int arr[] ,其表示的依然是一个指针: int *arr

4.1 数组名你用对了吗?

先看一段代码:

  1. //%p--打印地址
  2. int main()
  3. {
  4. int arr[10] = {
  5. 1,2,3};
  6. printf("%p\n", arr);//首元素地址--arr[0]
  7. printf("%p\n", arr+1);//arr[1]
  8. printf("%p\n", &arr[0]);//首元素取地址
  9. printf("%p\n", &arr[0]+1);//arr[1]
  10. printf("%p\n", &arr);//数组的地址,是从首元素地址开始的
  11. printf("%p\n", &arr+1);//数组+1,跳过整个数组
  12. printf("%d\n", sizeof(arr));//整个数组所占内存空间大小
  13. return 0;
  14. }

运行结果:

在这里插入图片描述

?数组名通常情况下就是数组首元素的地址。

但是有2个例外:

? sizeof(数组名),数组名单独放在sizeof()内部,这里的数组名表示整个数组,计算的是整个数组的大小

? &数组名,这里的数组名也表示整个数组,这里取出的是整个数组的地址

除此之外所有遇到的数组名都表示数组首元素的地址


结束语

合理安排时间,就等于节约时间。
  我们下一篇文章再见。
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,177人围观)

还没有评论,来说两句吧...

相关阅读

    相关 C语言入门(五)

    现实生活中,库函数并不能解决所有问题,于是就有了自定义函数。自定义函数和库函数一样,有函数名,返回值类型和函数参数。但是不一样的是这些都是我们自己来设计。statemen...

    相关 语言入门(四)

    > 前言 >   有的时候,我们可能需要多次执行同一块代码。 >   一般情况下,语句是按顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推。 >  

    相关 C语言入门(一)

    > 前言 >   欢迎各位小伙伴,这一篇,只是为了让我们对C语言有一个大概的认识,每个知识点并不会讲的很深,之后我也会持续更新博客,对这些知识进行拓宽,进行更细致的描述。

    相关 C语言

    面试中的套路 ============== 1. 公司要求员工的素质和能力        专业技能 --》第一轮面试通过笔试考察,第二轮面试面谈考察,题嵌入式开发有关一些