8

c语言入门15,C语言的设计精神是:相信每个C程序员都是高手,数组的介绍

 3 years ago
source link: https://blog.popkx.com/c-language-entry-15-c-language-design-spirit-is-i-believe-every-c-programmer-is-a-master-the-introduction-of-an-array/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

上一节介绍了 C 语言中的结构体,它是一种复合数据类型,有了结构体,C 语言可以应对各种复杂的数据模型,比如上一节的平行四边形问题。但是有些问题,就算是结构体,也很难解决。请看下面这个问题:

小明班级有 60 个人,期末考试出成绩后,用 C 语言找出这 60 个人的最高得分。

8079eb4dc6a2e3858c303dfebcf7fc7f.png

这当然不是什么难题,会判断两个数的大小就能解决这个问题。只不过,这 60 个人的成绩怎么用 C 语言描述呢?定义 60 个变量?这样是不是太麻烦了?就算不嫌麻烦,比较两个数大小的逻辑怎么写呢,每两个变量就得写一个 if ?

好在,C 语言有数组这个好东西

和结构体类似,数组也是一种复合数据类型,数组是由一系列相同类型的元素组成的。比如上面 60 人的成绩得分,每一个人的得分在 C 语言中都可以用 float 来定义,属于同一数据类型,所以这 60 个人的成绩得分,在 C 语言中可以定义为:

float score[60];

score 后面的 [60] 表示一共有 60 个 score 这样的(即 float 类型的)数据,所以 60 个同学的成绩得分,C 语言定义这么一个数组就可以了,并不需要定义多个变量。如果人数更多,把 60 改的更大就可以解决。

0133f2e7bb84a41f438595110d6c0af8.png

我们用方框表示数组的存储单元(元素),一系列方框在一起组成了数组。方框里面的数字是成绩得分,方框外面的数字是数组的下标,每个存储单元可以用数组名+下标访问:score[0],score[1],score[28] 等等。

注意,在定义数组时,float score[60]; 这里的 60 表示数组长度,而在访问时, score[60] 这里的 60 是指 score 数组的第 60 个元素。

和我们平常数数不同,数组元素是从“第0个”开始数的,大多数编程语言都是这么规定的。这样规定使得访问数组元素非常方便,比如 score 数组中的每个元素占 4 个字节,则 score[i] 位于从数组开头跳过 4 * i 个字节的存储位置。score[i] 也可以做左值,i 也可以是表达式:

int i = 10;
score[i+2] = 76.0;
score[3] = score[i-4];

只要确保下标都是整数,这些都是合法的。

48e1b32ecdf6a714812b4a49a5c82d44.png

C 语言数组如何初始化

数组的初始化结构体相似,例如:

float score[60] = {68.0, 84.2, };

如果定义数组同时初始化它,可以不指定数组长度,例如:

float score[] = {68.0, 84.2, 77.7};

这时,编译器会根据初始化信息确定 score 数组的长度为 3。不过,结构体可以互相赋值,数组却不能互相赋值:

int a[3];
int b[3] = {1,2,3};
a = b;  // 非法

既然数组不能互相赋值,也就不能用数组类型作为函数的返回值。这部分内容,我打算在介绍完指针后再详解。

f8e35dcd4845e552a44a11ba0490cb59.png

使用 C 语言数组解决上述问题

好了,说了这么多,来看一个实例吧,我们使用 C 语言数组来记录小明班同学成绩,然后找到最高的成绩得分:

#include <stdio.h>

int main()
{
    int i = 0;
    float score[6] = {68.12, 66.22, 78.54, 98.18, 60.00, 59.50};
    float max_score = 0;
    for(i=0; i<6; i++){
        if(max_score < score[i])
            max_score = score[i];
    }
    printf("max score is : %0.2f\n", max_score);
    return 0;
}

例子只使用了 6 个成绩做演示,原理是通的。

12fd2cb1669b7ab5869458e5b9886361.png

使用 C 语言数组注意事项

使用数组下标不能超出数组的长度范围,这一点在使用变量做数组下标时尤其要注意。C编译器并不检查 score[-1] 或是 score[100] 这样的访问越界错误,编译时能顺利通过,运行时却会出错。有时候这种错误很隐蔽,发生访问越界时程序可能并不会立即崩溃,而执行到后面某个正确的语句时却有可能突然崩溃。所以,从一开始写代码时就要小心避免出问题,事后依靠调试来解决问题的成本是很高的。

现在给出例子还较早,已介绍的内容不足以解释,以后会给出例子的。

所以属于运行时错误。但有时候这种错误很隐蔽,发生访问越界时程序可能并不会立即崩溃,而执行到后面某个正确的语句时却有可能突然崩溃(在“段错误”一节中我们会看到这样的例子)。所以,从一开始写代码时就要小心避免出问题,事后依靠调试来解决问题的成本是很高的。

fef7b602c947ff4d884bdad42321c347.png

你可能想问:为什么 C 编译器对这么明显的错误都不做处理?理由一,这种错误并不总是显而易见的,以后会讲到通过指针而不是数组名来访问数组的情况,指针指向数组的什么位置只有运行时才知道,编译时无法检查是否越界,而运行时检查数组访问越界会影响性能,C 语言是极其重视效率的编程语言,所以干脆不检查了;理由二, C99 Rationale 指出,C语言的设计精神是:相信每个C程序员都是高手,不要阻止程序员去干他们需要干的事,高手们使用count[-1]这种技巧其实并不少见,不能当作错误


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK