深圳市华胄科技有限公司 >> MCU专题 >> 单片机编程


单片机c语言,10小时学会C 语言 (七)



提交者 电子007  在  2008-3-17 15:12:36 

上一篇 下一篇
单片机c语言,10小时学会C 语言 (七)


第七章 数组与指针


数组是由一群相同型态的变量所组成,当你需要一堆相同型态的变量时,用数组是最适合的。例如,要储存全班 50 位同学的成绩,那就需要 50 个变量,如果要一个一个宣告,那就太没有效率了。这时就需要用数组了。指针则是指向变量或数组地址的运算子,任一变量或数组的数值均可经由指标的运算获得。


◎ 数组的宣告


数组宣告的格式如下:
┌─────────────────────────────────┐
│变量型别 变量名称[元素个数]; │
└─────────────────────────────────┘


以储存全班 50 位同学的成绩为例,用整数来存成绩:
┌────────────────────────────────────┐
│int score[50]; │
└────────────────────────────────────┘


C 语言中,数组的索引值是由 0 开始的,所以这 50 个变量为:score[0], score[1], score[2], ..., score[48], score[49] 。


以下的范例:读取一周的气温,再求出其平均值。
┌────────────────────────────────────────────────────────────────┐
│temper.c │
├────────────────────────────────────────────────────────────────┤
1│#include /* 宣告 printf(),scanf() 的原型 */ │
2│void main(void) │
3│{ │
4│ int t[7]; │
5│ int day, sum; │
6│ │
7│ for( day = 0 ; day < 7 ; day++ ) │
8│ { │
9│ printf("Enter the temperature for day %d : ", day+1 ); │
10│ scanf("%d", &t[day]); │
11│ } │
12│ │
13│ sum = 0; │
14│ for( day = 0 ; day < 7 ; day++ ) │
15│ sum = sum + t[day]; │
16│ │
17│ printf("Average temperature = %f\n", sum/7. ); │
18│} │
├────────────────────────────────────────────────────────────────┤
│Enter the temperature for day 1 : 22 │
│Enter the temperature for day 2 : 20 │
│Enter the temperature for day 3 : 18 │
│Enter the temperature for day 4 : 19 │
│Enter the temperature for day 5 : 23 │
│Enter the temperature for day 6 : 24 │
│Enter the temperature for day 7 : 26 │
│Average temperature = 21.714286 │
└────────────────────────────────────────────────────────────────┘


在第四章中,我们曾经列出各种变量型态的指针,以上面的例子:
位 址 记 忆 体 指 标 假设地址
├────────────────┤
&t[0] ───→│ t[0] │←── t + 0 ( 1000 )h
├────────────────┤
&t[1] ───→│ t[1] │←── t + 1 ( 1002 )h
├────────────────┤
&t[2] ───→│ t[2] │←── t + 2 ( 1004 )h
├────────────────┤
&t[3] ───→│ t[3] │←── t + 3 ( 1006 )h
├────────────────┤
&t[4] ───→│ t[4] │←── t + 4 ( 1008 )h
├────────────────┤
&t[5] ───→│ t[5] │←── t + 5 ( 100A )h
├────────────────┤
&t[6] ───→│ t[6] │←── t + 6 ( 100C )h
├────────────────┤


我们利用第 10 行 scanf("%d", &t[day]); 读取数据,这里用的是每一个数组元素的地址 &t[day] ,day 由 0 到 6 。


我们也可以改用指标的方式: scanf("%d", t+day );这里的 t 是数组变量的名称,也就一个指标常数(constant pointer),在宣告数组变量的同时,就宣告了这个指标常数,只是这个指标常数的数值不是由你决定的,而是在程序执行时,它的数值才会确定,一但确定,就不会改变。t + day 的 day 是 t 指标的增加值,假设 t 为 ( 1000 )h,那 t + 1 是 ( 1001 )h 吗?


C 语言在作指针运算时,会依指标的型别不同,而改变递增或递减的数值。以 t + 1 来说, t 是一个整数的指标常数,在 TC2 中 一个整数占有 2 bytes,所以 t + 1 的数值是 ( 1002 )h ,而不是 ( 1001 )h 。同理,t + 2 的数值是 ( 1004 )h 。


在上例第 17 行, printf("Average temperature = %f\n", sum/7. );不知道你有没有注意到 sum/7. 在 7 后面的一点 ( . ) ?


这并不是Keyin 错误,而是故意的。因为 sum 是一个整数变量,若写成 sum/7 表示整数除以整数,那结果还是整数。故意写成 sum/7.就变成整数除以实数,那结果会是实数。即然是平均值,通常会有小数,所以我们用 %f 来秀出数据。


◎ 字符串


字符串是一堆字符所组成的,它是一个字符数组,只是字符串它还要有个 '\0' 字符,作为字符串结束记号。例如,我们要用一个字符串存 DOS 的文件名:DOS 的檔名是主檔名最多 8 个字符,扩展名最多 3 个字符,中间以句号 ( . )分隔,所以需要 8 + 3 + 1 = 12 个字符来存盘名。但是别忘了字符串要有 '\0'的结束字符,所以,总共需要 12 + 1 = 13 个字符:


char filename[13];


你可以用以下的程序片断来询问文件名:
printf("Enter the file name : ");
scanf("%12s", filename );


scanf 是要变量的地址,而 filename[13] 这个变量的地址就是 filename ,你也可以用 &filename[0] 。另外,用 %12s 这个句柄,表示读入的字符串只取前面 12 个字符再加上 '\0' 字符,传给后面所指定的地址。如果你不加, 12 而用 %s 的话,当使用者输入超过 13 个字符时,将会发生不可预期的后果。


以下的范例:读取一个字符串并作输出。
┌────────────────────────────────────────────────────────────────┐
│string.c │
├────────────────────────────────────────────────────────────────┤
1│#include /* 宣告 printf(),scanf() 的原型 */ │
2│void main(void) │
3│{ │
4│ char name[13]; │
5│ │
6│ printf("Enter your name please : "); │
7│ scanf("%12s", name ); │
8│ printf("Good day, Mr. %s.", name ); │
9│} │
├────────────────────────────────────────────────────────────────┤
│Enter your name please : Lee │
│Good day, Mr. Lee. │
└────────────────────────────────────────────────────────────────┘


你可以将第 7 行的 %12s 改为 %s ,并且在执行程序时,输入一个较长的字符串,看看会发生什么事?


◎ 二维及多维数组


C 语言除了一维数组外,也可以依需要宣告二维或以上的变量数组:
┌──────────────────────────────────────────────────────────────┐
│变数型别 变量名称[第一维元素个数][第二维元素个数]; │
└──────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│变数型别 变量名称[第一维元素个数][第二维元素个数][第三维元素个数]; │
└────────────────────────────────────────────────────────────┘


不过会用到三维数组以上的机会蛮少的。以计算学生成绩为例,用一维数组 int score[50]; 我们只能记录一科的成绩,用二维数组 int score[50][7]; 就能记录七科的成绩,或者是记录单一科目的期中考、期末考、平常成绩、作业成绩等等。


以下是课本的范例(加上范围判断):秀出使用者所指定坐标的位置。
┌────────────────────────────────────────────────────────────────┐
│demo.c │
├────────────────────────────────────────────────────────────────┤
1│#include /* 宣告 printf(),scanf() 的原型 */ │
2│void main(void) │
3│{ │
4│ char matrix[5][10]; │
5│ int x,y; │
6│ │
7│ for( y=0 ; y<5 ; y++ ) /* 设定数组初值 */ │
8│ for( x=0 ; x<10 ; x++) │
9│ matrix[y][x] = '.' ; │
10│ │
11│ printf("Enter the coordinate(0 0) - (9 4) : "); │
12│ scanf("%d %d", &x, &y ); /* 读取指定坐标 */ │
13│ │
14│ for( ; !( ( x>=0 || x<=9 ) && ( y>=0 || y<=4 ) ) ; ) │
15│ { │
16│ printf("\aInvalid Value!!\n"); │
17│ printf("Please enter the coordinate(0 0) - (9 4) : "); │
18│ scanf("%d %d", &x, &y ); /* 读取指定坐标 */ │
19│ } │
20│ matrix[y][x] = '*' ; /* 设定指定坐标 */ │
21│ │
22│ for( y=0 ; y<5 ; y++ ) /* 秀出数组值 */ │
23│ { │
24│ for( x=0 ; x<10 ; x++) │
25│ printf("%c", matrix[y][x] ); │
26│ printf("\n"); │
27│ } │
28│} │
├────────────────────────────────────────────────────────────────┤
│Enter the coordinate(0 0) - (9 4) : 5 3 │
│.......... │
│.......... │
│.......... │
│.....*.... ← 因为索引值是由 0 开始所以 * 在 6,4 │
│.......... │
└────────────────────────────────────────────────────────────────┘


第 14 行到第 19 行是利用一个 for 循环来判断输入的数值是否在要求的范围。在使用数组时,最好要注意一下使用索引值的范围,因为 C 不会做数组边界检查,当你使用大于你所宣告的索引值时,在语法上,并不会有任何的错误。但是当你使用索引值超过你所宣告的的数组时,你有可能改变到别的变量,甚至是程序代码。轻微的话,只是程序结果错误,严重的话,可能导致当机。


☆ 两维数组的指针 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆


以 int s[50][3]; 为例
位 址 记 忆 体 指 标 假设状况
├────────────┤
&s[0][0] →│ s[0][0] │← *(s + 0) + 0 ← s + 0 ← s ( 1000 )h
├────────────┤
&s[0][1] →│ s[0][1] │← *(s + 0) + 1 ( 1002 )h
├────────────┤
&s[0][2] →│ s[0][2] │← *(s + 0) + 2 ( 1004 )h
├────────────┤
&s[1][0] →│ s[1][0] │← *(s + 1) + 0 ← s + 1 ( 1006 )h
├────────────┤
&s[1][1] →│ s[1][1] │← *(s + 1) + 1 ( 1008 )h
├────────────┤
&s[1][2] →│ s[1][2] │← *(s + 1) + 2 ( 100A )h
├────────────┤
&s[2][0] →│ s[2][0] │← *(s + 2) + 0 ← s + 2 ( 100C )h
├────────────┤
... ... ...
├────────────┤
&s[48][2] →│ s[48][2] │← *(s +48) + 2 (30h*3+2)*2 ( 1124 )h
├────────────┤
&s[49][0] →│ s[49][0] │← *(s +49) + 0 ← s +49 ( 1126 )h
├────────────┤
&s[49][1] →│ s[49][1] │← *(s +49) + 1 ( 1128 )h
├────────────┤
&s[49][2] →│ s[49][2] │← *(s +49) + 2 ( 112A )h
├────────────┤


s 是一个二维指标常数。


一个一维指标,我们必须在指标前加一个星号 ( * ) 才能取得一维数组内的变量值,同样地,在二维指标,我们必须在指标前加二个星号,才能取得二维数组内的变数值。若是二维指标前的星号少于二个,例如,没有星号或只有一个,那它所表示的就还是一个指标。另外,二维指标前如果有一个星号,那就相当是降了一维,而成为一个一维指标。


○ 二维指标的递增值


一个一维指标,如果它所指的变量型态占有 n 个 byte ,那这个一维指标的递增值就是 n 。


一个二维数组: vartype Array[ X ][ Y ]; 如果 vartype 占有 n 个 byte,那Array 这个二维指标的递增值就是 Y * n ,也就是 Y 个 vartype 所占的空间。Array 是指向二维数组的开端 &Array[0][0],而 Array+1 正好指向 &Array[1][0],同理 Array+i 是指向 &Array[i][0]。


如前所述,在二维指标前加一个星号就会变成一维指标。所以, *Array 是个一维指标、*(Array+1) 是一维指标、...、*(Array+i) 是一维指标、...、*(Array+(X-1)) 是一维指标,而这些一维指标都是指向第二维数组开始的地址。


其中的 0≦ i ≦(X-1),如同决定 Array[X][Y] 中第一维(X)的位移量(Offset)。这些一维指标的递增值 *(Array+i)、...、*(Array+i)+j、...、*(Array+i)+(Y-1)就指向第二维的每一个变量。


其中的 0≦ j ≦(Y-1),如同决定 Array[X][Y] 中第二维(Y)的位移量(Offset)。所以, *(Array + i) + j 就是指向 Array[i][j] 这个变量,同时*( *(Array + i) + j ) 就是 Array[i][j] 这个变量。


★ C 语言不会作数组边界(Boundary)检查,例如,你宣告 int s[50][7];可是你可以使用 s[0][8]、s[51][2] 或 s[100][200]。


○ 用指标的方式,修改上例,你看懂了吗?
┌────────────────────────────────────────────────────────────────┐
│demoptr.c │
├────────────────────────────────────────────────────────────────┤
1│#include /* 宣告 printf(),scanf() 的原型 */ │
2│void main(void) │
3│{ │
4│ char matrix[5][10]; │
5│ int i,x,y; │
6│ │
7│ for( i=0 ; i<5*10 ; i++ ) /* 设定数组初值 */ │
8│ *((*matrix)+i) = '.' ; │
9│ │
10│ printf("Enter the coordinate(0 0) - (9 4) : "); │
11│ scanf("%d %d", &x, &y ); /* 读取指定坐标 */ │
12│ │
13│ for( ; !( ( x>=0 || x<=9 ) && ( y>=0 || y<=4 ) ) ; ) │
14│ { │
15│ printf("\aInvalid Value!!\n"); │
16│ printf("Please enter the coordinate(0 0) - (9 4) : "); │
17│ scanf("%d %d", &x, &y ); /* 读取指定坐标 */ │
18│ } │
19│ matrix[y][x] = '*' ; /* 设定指定坐标 */ │
20│ │
21│ for( y=0 ; y<5 ; y++ ) /* 秀出数组值 */ │
22│ { │
23│ for( x=0 ; x<10 ; x++) │
24│ printf("%c", *( *(matrix + y) + x) ); │
25│ printf("\n"); │
26│ } │
27│} │
├────────────────────────────────────────────────────────────────┤
└────────────────────────────────────────────────────────────────┘



单片机教程,五系列(55讲)电子书全集下载

论坛精选:
■ 单片机c语言,10小时学会C 语言 (一)
第一章 C 语言简介与Turbo C 的使用
■ 单片机c语言,10小时学会C 语言 (二)
第二章 C 程序的结构
■ 单片机c语言,10小时学会C 语言 (三)
第三章 常数与变数
■ 单片机c语言,10小时学会C 语言 (四)
第四章 基本输出入函式
■ 单片机c语言,10小时学会C 语言 (五)
第五章 流程图与抉择指令
■ 单片机c语言,10小时学会C 语言 (六)
第六章 循环与自动重复
■ 单片机c语言,10小时学会C 语言 (七)
第七章 数组与指针
■ 单片机c语言,10小时学会C 语言 (八)
第八章 函数与呼叫
■ 单片机c语言,10小时学会C 语言 (九)
第九章 档案存取

1 楼  提交者:Guest 在 2008-3-17 18:51:36
sadasdasdas
2 楼  提交者:Guest 在 2008-3-18 8:27:01
dsf
3 楼  提交者:dataie 在 2008-3-18 9:24:27
kankan
4 楼  提交者:陈春 在 2008-3-18 11:41:58
hjhgjh
5 楼  提交者:king 在 2008-3-18 15:54:11
ok
6 楼  提交者:Guest 在 2008-3-18 19:08:56

7 楼  提交者:浪人 在 2008-3-18 20:54:24
辛苦了
8 楼  提交者:卫立 在 2008-3-18 22:50:56
卡们
9 楼  提交者:木木林 在 2008-3-19 10:18:39
DSD
10 楼  提交者:han2002asd 在 2008-3-19 12:40:10
vb 
11 楼  提交者:anny2008 在 2008-3-19 16:56:41
12 楼  提交者:中山盈亮 在 2008-3-20 11:23:25
不错
13 楼  提交者:Guest 在 2008-3-20 13:36:52
r
14 楼  提交者:goldskin 在 2008-3-20 21:48:36
gan
15 楼  提交者:梦蝶秋 在 2008-3-21 11:46:15
16 楼  提交者:youminbuluo 在 2008-3-21 21:24:41
谢谢分享
17 楼  提交者:理工朱仕勇 在 2008-3-21 21:58:09
18 楼  提交者:理工朱仕勇 在 2008-3-21 21:58:17
19 楼  提交者:理工朱仕勇 在 2008-3-21 21:58:21
20 楼  提交者:理工朱仕勇 在 2008-3-21 21:58:24
21 楼  提交者:高臣 在 2008-3-22 13:18:56
学习
22 楼  提交者:luxs 在 2008-3-22 13:58:46
谢谢分享
23 楼  提交者:Guest 在 2008-3-22 20:06:36
很好啊
24 楼  提交者:liuyiqiangqq 在 2008-3-22 21:53:09
25 楼  提交者:liuyiqiangqq 在 2008-3-22 21:53:13
26 楼  提交者:有点意思 在 2008-3-22 23:44:02
good hao
27 楼  提交者:Guest 在 2008-3-23 0:27:01

28 楼  提交者:shw0320 在 2008-3-25 11:14:58
29 楼  提交者:hanozi 在 2008-3-25 11:46:40
kankan
30 楼  提交者:Guest 在 2008-3-25 13:15:42
zz
上一篇 下一篇
当前第〖1〗页 共有22页 转到第 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22