您的当前位置:首页正文

【持续更新】C语言 第六天学习笔记(数组上)

来源:华拓网

一、【掌握】数组简介

思考:

     苍老师的班级里有5个学生,这次参加了语文考试,写一个程序把这5个人的成绩保存起来,怎么做呢?

我们发现,如果用一个变量来接收成绩,变量始终保存的是最后一次的输入。如果用5个变量来保存,代码会比较多而且很不利于扩展,万一以后学生有500人呢?

所以,我们迫切地需要有一种变量,能够保存好多个不同的值。

这种变量,就叫数组!

数组的定义格式:

数据类型   数组名[可以存储的数据个数]

语义:数据类型给出了这个数组只能存什么类型的数据,后面中括号[]里面填的是正整数,表示这个数组可以存放多少个这种类型的数据

例:int arr[10]
代表这个数组只能存10个int类型的数据

其他类型的数组

char arr[5];
float arr[5];
double arr[5];

数组在内存中的存储形式:(简易形象版)

内存中的存储形式

解释:
1.先在内存中开辟一段空间

2.然后把这段空间N等份(如果你要存3个就划分为3等份)

3.这3个小空间的类型根据你之前申明的类型确定

4.实际存数据的就是这些小空间

数组的三个专业术语:

1.元素:数组之中划分的小空间里存的数据,就叫元素

2.下标/索引:为了区分每个小空间,给每个小空间都从0开始,依次递增1的做了编号,这个编号就叫做数组的下标/索引

3.长度:就是数组可以存储多少个数据,一般在申明的时候就给出了长度,比如int arr[3],代表这个数组的长度为3,可以存放3个数据

数组的赋值与取值操作

1) 赋值:

因为数组中实际存储数据的实际是内存中的每个小空间,所以应该是给小空间里赋值,那么数组里也许有多个小空间,怎么确定给哪个小空间赋值呢?通过下标来赋值

语法:

数组名[下标]
= 数据;

例:

int arr[5];

arr[0]
= 10; //代表给数组中第一个元素赋值

注意:

赋值的时候,元素的下标千万不要越界(即超过数组的小空间编号),编译器不会报错,但是实际使用时可能会出不可预知的错误

2)取值:

因为数组中的数据是存在每一个小空间里的,那么多小空间,我们到底要取哪一个呢?所以这时也需要通过下标来确定

语法:

数组名[下标];

例:

int arr[3];

arr[0] = 10

int num
= arr[0]; //此时num的值为10

注意:

取值的时候下标也千万不要越界,否则也可能出现未知的错误

一般情况下,我们所说的数组都是指一位数组,即我们现在所学的这个数组。后面还会学习二维数组和了解一下多维数组。

二、【掌握】数组的详细使用

1、数组初始化的方法(赋值方法)

1)先定义数组,再赋值

例:

int arr[3];

arr[0] = 10;

arr[1] = 15;

arr[2] = 14;

解释:因为数组中实际存储数据的实际是内存中的每个小空间,所以应该是给小空间里赋值,那么数组里也许有多个小空间,怎么确定给哪个小空间赋值呢?就是通过数组的下标来赋值。所以上面的方法是给小空间一个一个地赋值

2)定义数组的同时初始化(赋值)

A、完全初始化

int nums[5] = { 1, 2, 3, 4, 5 };

B、不完全初始化,没有提供数据的默认初始化为 0

int nums[10] = { 1, 2, 3, 4, 5 };

C、省略数组长度,由编译器自动判断

int nums[] = { 1, 2, 3, 4, 5 };

D、指定元素个数,同时给指定元素进行初始化

int nums[5] = {[4] = 3,[1] = 2};

解释:以上三种方法都是在数组申明时直接按顺序给每个小空间赋值数据。

如图所示

其他注意:不管是先定义数组,还是数组定义并初始化。只要数组一经定义,里面就有值,里面默认的值都为0(如果是字符型数组,那么就是ascii码中0所对应的字符'\0'即为空)

2、引用元素

什么叫引用元素:

引用数组元素表示使用数组中的每一个变量

用法:

使用下标引用数组中指定的变量

语法:

数组名[ 下标]

例如:

int  nums[] = { 1, 2, 3 };

printf("%d\n",
nums[0]);

printf("%d\n",
nums[1]);

printf("%d\n",
nums[2]);

 

引用数组元素和使用指定类型变量一样,可以读取数据赋值等

1)读取数据

2)获取数据(打印,计算)

3)自增等

3、遍历数组元素

遍历的意思:就是访问每一个元素

使用 for 循环对数组进行遍历

for
(int i = 0; i < length; i++) {

printf("%d\n",
nums[i] );

}

三、【掌握】数组的越界

1、数组的越界

生活中的越界

例图1

数组中的越界

例图2

越界访问的情况:

新版本的xcode编译不会报错,运行中会报错

总结:

一个长度为n的数组,最大下标为n-1,
下标范围:0~n-1

精华:不要乱约别人的女朋友(访问自己不该访问的内存),否则后果很严重(运行异常)

【理解】数组练习

1、苍老师的班级里有10个学生,现要求输入每个学生的成绩,算出总分是多少,平均值是多少,最高分和最低分

2、假设有数组int a[10] = {1,2,3,4,5,6,7,8,9,10},按照从第一个元素到最后一个元素输出(遍历)元素值,然后再从最后一个元素到第一个元素输出(遍历)元素值

3、让用户输入数组的长度,然后再依次让用户输入这个数组的每一个元素的值,最后再遍历这个数组

4、在一个数组中查找指定元素第一次出现的下标,如果没有这个元素就打印-1

四、【掌握】数组作为函数的参数

思考:

如果有一个函数,需要传入一个int类型的参数,那么,
我们能不能把一个int类型的数组的元素传过去呢?

答案是可以的。

当有一个元素需要传入基本类型(int,long,float,double,char等)的数据作为参数时,
可以传入同类型的数组的元素,如果类型不一致时会发生强制转换。
因为数组的元素就相当于是某一类型的变量值。

1、数组元素作函数实参

数组元素就是下标变量,它与普通变量并无区别
因此它作为函数实参使用与普通变量是完全相

同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值传送。

如图所示
思考&实现1:

判别一个整数数组中各元素的值,若大于0 则输出该值,若小于 等于0则输出0值(判断过程使用函数实现)

代码

2、数组名作为函数参数

当函数的形参是一个数组时,那么我们的实参必须传入一个数组(数组名)

如图所示

注意:此时在函数内部改了某个元素的值,外部数组元素也会发生改

如下图

如图所示

这是为什么呢?
具体原因涉及到指针的概念,明天解释,今天大家只要知道当数组作为实参传入函数时,在函数内部对数组元素进行修改,外部的数组也会收到影响!

思考:如果要写一个函数,函数的功能是将传入的int类型数组中每个元素都加10,怎么做?

常规思考如下:


常规思考

根据我们所学的内容会发现:由于当数组作为函数形参时,外部可以传入任意长度的数组,那么在函数内部中就不好处理了,循环次数写大了会造成越界,写小了会造成不能充分地操作每一个元素,那么怎么办呢?

解决之道:
一般当函数形参是一个数组时,还会再加一个参数用来传入数组的长度。

如图所示

但是,这种方法需要程序员能完整记得自己定义这个数组时给的长度,这样十分不科学。如果哪天定义数组后又写了很长一段代码才开始调用函数,这时程序员要回过头找定义数组的长度很费时间,那么有没有一种方法帮我们解决呢?

解决之道:sizeof(数组名) / sizeof(类型)

例:int arr[3] = {1,2,3}; sizeof(arr) / sizeof(int)

解释:由于数组是由多个同类型的小空间组成,所以只要先算出数组占用内存的总大小再除以每个空间占用的大小,就可以得到有多少个小空间(元素)