【C language part 4】阵列与字串&函式

阵列

阵列是一群具有相同名称或资料型态的变数集合。

由于整个阵列中的变数均具有相同的名称,因此若要存取阵列中的变数,我们只需要透过阵列的 index 来指定就可以了。

阵列与变数的功能都是用来储存资料,但有所不同的是每一个变数只能储存一项资料,而阵列则是由一连串的主记忆体空间组合而成,所以可以同时连续储放多项资料,亦即一次可以宣告多个变数,而不用一个一个宣告。因此,可以少写许多行程式,并且增加程式的可读性。

阵列定义:

阵列里的每一个元素都必须是同一种资料型态。阵列大小须为常数(constant value)。佔用了连续(contiguous)的记忆体位址。如果我们不会分配任何初始值给阵列,最好在宣告的时候将阵列初始化为零或 null。插入或删除元素时较麻烦,因为需挪移其他元素。用来表示有序串列之一种方式。

阵列的应用

让电脑随机给定四十人的分数,并在萤幕显示出来。

#include <stdio.h>#include <stdlib.h>#include <time.h>int main(){    int i;    int score[40];        srand( time(NULL) );        for(i = 0; i < 40; i++){        score[i] = rand(() % 41) + 60; // 把分数设定在 100~60 之间    }        printf("座号\t分数\n");    for(i = 0; i < 40; i++){        printf("%d\t%d\n", (i+1), score[i]);    }}

阵列格式

根据阵列结构不同,我们可以把阵列分为一维阵列二维阵列多维阵列而表示方法如下:
dataType arrayName[arraySize];dataType arrayName[arraySize] [arraySize];
int score[40]; // 没有宣告初值的阵列int arr[5] = {3, 4, 5, 6, 7}; // 也可以一併宣告初值int arr[] = {3, 4, 5, 6, 7}; // 或是用这种方式让电脑自动决定阵列长度int arr[5] = {0}; // 初始化阵列,所有元素都设为0

但是要切记,阵列的长度要在编译期间就决定好,也就是阵列长度须为常数。如果想要在执行期间,动态生成阵列,要用动态配置记忆体的方式,这边我们等到指标的单元会再提。

int arr[5] = {3, 4, 5, 6, 7};

#include <stdio.h>#include <stdlib.h>#include <time.h>int main(){    int arr[5] = {0, 10, 100, 1000, 5000};        printf("arr[3] = %d\n\n", arr[3]); // arr[3] = 1000}

阵列的空间分配方式

无论是几维的阵列,C语言都会分配一块连续的记忆体空间来处理。(这个概念到未来的指标单元会用到)

int x[10];
分配 10*sizeof(int) 个 bytes

int x[5][10];
分配 5*10*sizeof(int) 个 bytes

但如果是呼叫函式传递参数时,如:

void fun(int x[]){}

这里的阵列 x 就没有分配空间,这样相当于 int *x
这是因为 C语言在呼叫函式传递参数时,无法传递整个阵列,因为阵列可能大的不得了,所以我们传递的是阵列的开头地址,也就是指标。
因此,在参数宣告时,指标和没有宣告大小的阵列可以混用。

範例一 整数阵列

定义一个阵列空间为 10 的整数一维阵列,以乱数填入介于 ab (a < b)之间的整数元素。
ab 为使用者输入的整数。
请列出该阵列的所有元素。承上题,计算该整数阵列之平均值(means)。
#include <stdlib.h>#include <stdio.h>#include <time.h>void main(){    int arr[10] = {0};    int a, b;    srand(time(NULL));    printf("Please enter two number a and b (a < b):\n");    scanf("%d %d", &a, &b);    for(int i = 0; i < 10; i++){        arr[i] =  rand() % (b - a + 1) + a;    }    for(int i = 0; i < 10; i++){        printf("arr[%d] = %d\n", i, arr[i]);    }    /* 第二小题 */    int sum = 0;    float ave = 0;        for(int i = 0; i < 10; i++){        sum += arr[i];    }        ave = sum / 10.0;    print("\nmean of the array: %f", ave);}
Please enter two number a and b (a < b):3 25arr[0] = 25arr[1] = 6arr[2] = 4arr[3] = 12arr[4] = 18arr[5] = 5arr[6] = 3arr[7] = 9arr[8] = 11arr[9] = 21mean of the array: 11.4

多维阵列

一维阵列使用阵列名称与一个 index 来指定存取的阵列元素。
二维阵列使用阵列名称与两个 indices 来指定存取的阵列元素,宣告方式与一维阵列类似。

範例二-泡沫排序法 Bubble Sort

我们先来讲解排序演算法(sorting algorithm),但在这之前,我们又要先来再讲讲何谓演算法?

何谓演算法?

Wiki的定义:
为任何良定义的具体计算步骤的一个序列,常用于计算、资料处理和自动推理。精确而言,演算法是一个表示爲有限长列表的有效方法。演算法应包含清晰定义的指令用于计算函式。
简单讲成一句话:可以解决某些问题的有效方法之有限集合。那么,在程式的领域,我们再把它缩成一个公式:
$$
程式设计 = 资料结构 + 演算法 \
\text{Programming} = \text{Data Structures} + \text{Algorithm}
$$说穿了,演算法就是一种 解决问题的逻辑思维!

排序演算法

所谓排序法,就是将一堆没有排序过的数字由小到大(或大到小)排列好的演算法。
视觉化15种排序法

其中一种程式入门者最常使用的排序演算法-泡沫演算法 Bubble sort

泡沫演算法 Bubble Sort

首先比较最前面两个数字
如果要排序由小到大,那么将较大的往后排
反之,将较小的数字往后排

它重複地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重複地进行直到没有再需要交换,也就是说该数列已经排序完成。这个演算法的名字由来是因为越小的元素会经由交换慢慢「浮」到数列的顶端。

字串 String

C语言其实并没有「string」这种类型的资料型态,但我们通常不会只用「一个字元」啊,一般来说都会使用「字串」。这种时候我们就只能透过字元阵列 char[] 来模拟字串。要注意:字串一定是 char[] 字元阵列;但是 char[] 字元阵列不一定就是字串。在 C 谈到字串的话,一个意义是指字元组成的阵列,最后加上一个空(null)字元 '\0',例如底下这个 “hello” 字串:char text[] = {‘h’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’};之后可以直接使用以下 function 显示在萤幕上:printf(“%s”, text);也可以使用 " " 来包含文字,例如:char text[] = “hello”;虽然在这个例子没有指定空字元 '\0',但是此语法下会自动加上空字元。

範例

我们改成使用 gets() 来读取字串。

所以这里我们可以发现,已经解决刚刚的问题了。
gets() 只有 Enter 键(回车符)才会结束,在 Enter 键以前都会当成字元(包含空白键)。

gets() vs. scanf()

gets(str) 允许输入的字符含有空格。scanf("%s", str) 不允许输入字符串含有空格。

注意:
当你编译包含 gets 的程式时,可能会出现 warning 説 gets 是不安全的,原因是 gets( )scanf( ) 都无法知道字串 s 大小,必须遇到换行符或读到文件结尾为止才接收输入,因此容易导致字元阵列 overflow 的情况。
意思就是说,当你输入的字串数量超过接收字串的阵列大小,就很容易发生 overflow。

函式 Function

到目前为止都只使用一个函式(Function),也就是 main() 主函式,若某些程式码经常使用,我们就可以抽出来让它成为一个新函式好让我们重覆呼叫。这也就是所谓的模组化。什么叫模组化?简单来说,就是把特定功能分出来当成一个模组,需要的时候只要呼叫这个模组就好;而需要修正的时候也只要修正模组即可。函式用来将程式组织为一个小的、独立的运行单元,一个函式可以接受资料(传入参数),并执行其中的算法,最后将结果传回去。

函式的优点

减少撰写重覆的程式码。将程式码以有意义的方式组织起来。在相同的流程下,可藉由参数调整程式的行为。藉由函式库可组织和分享程式码。做为资料结构 (data structures) 和物件 (objects) 的基础。

我们就举几个例子来简单示範如何宣告并且使用函数。

範例

没有输入参数,也没有回传值。

主程式

副程式内容

範例

有输入参数,也有回传值。

主程式 简化了前一页的程式方便讲解

副程式内容


通常我们的副函式会写在整个 program 的最前面(main function 前面),不过也可以写在 main function 的后面,但是一开始要先宣告副函式。


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章