码迷,mamicode.com
首页 > 编程语言 > 详细

Linux C 编程学习第六天_数组

时间:2021-06-15 18:05:53      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:rgba   组合   bsp   函数返回   编写   element   帮助   图片   pre   

数组基本操作

和结构体类似,数组(array)也是一种复合数据类型,由一些列相同类型的元素(Element)组成,别觉得只能存储数字啊!

还是和结构体类似,数组的元素存储空间是相邻的,结构体的成员可以是基本数据类型,也可以是复合数据类型,数组的元素也是如此,根据相邻组合规则,我们甚至可以定义一个由四个结构体元素组成的数据,换句话说,就是我们可以定义一个数组,里面的元素是结构体,所以千万别觉得数组只能存储数字。

当然,也可以定义一个结构体里面包含数组。

技术图片

数组类型的长度应该用一个常量表达式来指定,而且这个常量表达式的值必须是整数类型的,数组的元素通常使用下标来索引(Index)

数组的下标是从  0  开始的,数组的下标也可以是表达式,但是表达式的值必须是整型或者字符型的,千万注意下标不能超过数组的长度,C编译器并不检查越界错误,编译能通过但是运行还是会出错,这属于运行时错误,可能会执行到某处突然崩溃,一定要注意。

数组初始化也和结构体一样,未赋值的元素为0。定义的时候初始化它就不需要指定数组长度。

数组的访问也很简单:

技术图片

 这称之为数组的遍历——通过循环将数组的所有元素都依次访问了一遍。

注意,数组不能相互赋值,所以它不能坐为函数参数和函数返回值!!!

但是数组名字可以看成指针,就可以传递数组的参数了,这在之后在学习。

 

数组应用实例:统计随机数

先理解一些问题,计算机的每条指令结果是确定的,所以没有一条指令或者函数会产生随机数,实际上调用C标准库所得到的 “ 随机数 ” 是伪随机数,为什么说是伪随机数,因为它们是由数学公式算出来的确定的数,只不过在统计意义上接近均匀分布(Uniform Distribution)。下属使用中,就不再细分这两个概念了。

C标准库中生成随机数函数是 rand 函数,需要包括 stdlib.h 这个头文件,无参数,每次调用返回一个介于0和 RAND_MAX 的接近均匀分布的整数,在不同的平台上有不同的取值,并且非常大,但是我们在使用中不需要那么大的随机数,所一般会限定在某个范围内,我们先获取并输出10个随机数:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define N 20
 5 
 6 int a[N];
 7 
 8 void gen_random(int upper_bound)
 9 {
10     for (int i = 0; i < N; i++)
11     {
12         a[i] = rand() % upper_bound;
13     }
14 }
15 
16 void print_random()
17 {
18 
19     for (int i = 0; i < N; i++)
20     {
21         printf("%d\n", a[i]);
22     }
23 }
24 
25 int main(int argc, char const *argv[])
26 {
27     gen_random(10);
28     print_random();
29     return 0;
30 }

接着运行:

技术图片

 

 但是这里你会发现一个问题,因为随便运行几次,得到的随机数是一样的。,这个问题稍后再说

在上述代码中,使用了宏定义: #define  将 N 替换成数值 20,像#include 和 #define 这样以 # 开头的语句称为预处理语句,#define 不仅用于定义常量,也可以定义复杂的语法,其次, define 定义是在预处理阶段处理的,像枚举就是在编译阶段处理的。

那么我们为什么使用 #define 把N定义为20,这里我们让函数输出了20个随机数,如果我想要输出更多,输出200个随机数,那么就可以直接在开头的 #define 处修改,那么直接在函数定义中给函数个数值不就行了,也没必要 #define 一个数字,对于这个简单的代码是这个理,但是,如果代码很长,很多个地方都需要调用20,如果想做修改,就得一个一个去修改,一个个去寻找,代码很长的话极其容易出错,如果使用 #define N 20,则只需要在后面改动20这个数字。这里描述的不是很好,我举一个最近的例子:

最近在写简单的arduino的代码,由于调用了大量的引脚:

技术图片

这里数字代表arduino的引脚,在对引脚进行操作的时候,可以直接调用数字,但是也可以直接调用宏,如果我在所有的控制代码中都使用了数字来代替引脚,那么我每次操作的就从图一编程图二:

技术图片

 

 技术图片

这两段代码是一样的作用,当你过段时间来看代码的时候,你会直接先懵逼,这数字代表的啥意思?我咋接线啊,这是宏定义的第一个好处,帮助记忆,你可以把一些一眼看上去不知道是什么的东西宏定义为一眼就能看懂的,方便调用和维护,第二个好处,如果我临时要改变接线,我需要在每一个函数中改变对应的引脚数字,天哪,很多个地方都调用了这些引脚的数字,一个个去改太容易造成混乱了,那么#define 的优点就出来了,我只需要改边宏定义对应的数字就可以,就可以不用在意下面函数的调用,随便更换引脚,因为其他函数的接口并没有发生改变,就是如此的方便。

咳咳,扯远了,我们重新回归一下主题,上述一个一个更改代码,一个一个查找的做法称之为硬编码(Hard coding),确实相当硬核啊,当然我们在写代码的时候尽可能避免硬编码。

然后在多说一些

技术图片

 这里很巧妙的使用了 i  这个变量,它又是循环册数,又是数组下标。

接着,我如果想编写一个函数,它可以统计一个数字出现了多少次,那么可以这样写:

技术图片

这段代码里,每进行一次 for 循环,对比数组所有的数值和 value,如果相等那么 count自加,计算出需要统计的数字个数然后返回。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define N 20
 5 
 6 int a[N];
 7 
 8 void windows_cmd_support_utf8(void)
 9 {
10 #ifdef WIN32
11     system("chcp 65001 & cls"); //cls 用来清除 chcp 的输出
12 #endif
13 }
14 
15 void gen_random(int upper_bound)
16 {
17     for (int i = 0; i < N; i++)
18     {
19         a[i] = rand() % upper_bound;
20     }
21 }
22 
23 int howmany(int value)
24 {
25     int count = 0;
26     for (int i = 0; i < N; i++)
27     {
28         if (a[i] == value)
29         {
30             count++;
31         }
32     }
33 
34     return count;
35 }
36 
37 void print_random()            //遍历
38 {
39 
40     for (int i = 0; i < N; i++)
41     {
42         printf("%d\n", a[i]);
43     }
44 }
45 
46 int main(int argc, char const *argv[])
47 {
48     windows_cmd_support_utf8();
49 
50     gen_random(10);
51     print_random();
52     printf("数字4出现的次数为:%d\n", howmany(4));
53     return 0;
54 }

运行就可以得到数字4在20个随机数中出现的个数,那么如果我还想计算数字2的个数,可以再继续调用 howmany(2),如果还想计算3,4,5呢,你会发现每次调用howmany()函数都会把数组的所有值遍历一边,效率很低,有没有一次就可以计算出所有的个数的呢?接着尝试写一个可以一次性判断0~9出现次数的函数。

技术图片

 

 定义一个数组,存储每一次循环中0~9出现的次数,这里 i 也同样有很多的作用,是循环次数,也是数组histogram[ ] 的角标,也是howmany()函数的输入值。那么在遍历数组的时候就可以顺便输出出现的次数。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define N 20
 5 
 6 int a[N];
 7 int histogram[N];
 8 
 9 void windows_cmd_support_utf8(void)
10 {
11 #ifdef WIN32
12     system("chcp 65001 & cls"); //cls 用来清除 chcp 的输出
13 #endif
14 }
15 
16 void gen_random(int upper_bound)
17 {
18     for (int i = 0; i < N; i++)
19     {
20         a[i] = rand() % upper_bound;
21     }
22 }
23 
24 int howmany(int value)
25 {
26     int count = 0;
27     for (int i = 0; i < N; i++)
28     {
29         if (a[i] == value)
30         {
31             count++;
32         }
33     }
34 
35     return count;
36 }
37 
38 void print_random()            //遍历
39 {
40     for (int i = 0; i < N; i++)
41     {
42         printf("  %d  ",a[i]);
43     }
44     printf("\n");
45     for (int i = 0; i < 10; i++)
46     {
47         printf("数字%d出现的次数为:%d\n", i,histogram[i]);
48     }
49 
50 }
51 
52 int main(int argc, char const *argv[])
53 {
54     windows_cmd_support_utf8();
55     
56     gen_random(10);
57     
58     for (int i = 0; i < N; i++)
59     {
60         histogram[i] = howmany(i);
61     }
62 
63     print_random();
64     
65     return 0;
66 }

运行结果为:

技术图片

 

 第一行为20个随机数,接着输出每个数字出现的次数。

这里我们回到之前提到的一个问题,即使我运行很多次,结果还是和上述一致,这其实正是验证了我们一开始知道的C语言输出的随机数是“伪随机数”,因为它是通过一个公式基于某个初始值计算出来的,所以多次运行的结果是一致的,那么我们如何避免这样的情况,C语言标准库允许我们自己指定一个初值,然后在这个基础上生成伪随机数,这个初值为 Seed ,可以使用 srand函数指定Seed,举个简单的调用例子,调用time函数得到当前系统时间距离1970年1月1日00:00:00的秒数,然后用srand函数指定Seed:

#include <time.h>

srand(time(NULL));

这样就可以得到每次得到不同的伪随机数了,当然可以任意指定Seed,这里只是提供一个方法。

 

Linux C 编程学习第六天_数组

标签:rgba   组合   bsp   函数返回   编写   element   帮助   图片   pre   

原文地址:https://www.cnblogs.com/rezhu-enable/p/14847746.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!