本节书摘来自异步社区《51单片机应用开发范例大全(第3版)》一书中的第1章,第1.3节,作者 张杰,宋戈,黄鹤松,员玉良,更多章节内容可以访问云栖社区“异步社区”公众号查看。
1.3 C51基础知识
1.3.1 C51控制语句
C51语言中,有相关的控制语句,用以实现选择结构与循环结构。
- 选择控制语句:if语句和switch-case语句。
- 循环控制语句:for语句、while语句和do…while语句。
- 转移控制语句:break语句、continue语句和goto语句。
1.选择控制语句
在C51语言中选择结构主要是利用if语句和switch-case语句来实现的。
(1)if语句的3种常用形式。
C51语言中分支结构主要是应用if语句来实现的,if语句是对给定条件进行判断,然后决定执行某个分支。if语句包括if语句、if-else语句、else-if语句3种形式。
-
if语句
if(表达式)语句
含义:如果表达式的值为真,则执行其后的语句;否则不执行该语句后面的语句。
-
if-else语句
if(表达式)
语句1;
else
语句2;
含义:如表达式的值为真,则执行语句1;否则执行语句2。
-
else-if语句
if(表达式1)
语句1;
else if(表达式2)
语句2;
else if(表达式3)
语句3;
…
else if(表达式m)
语句m;
else(表达式m + 1);
含义:依次判断各个表达式的值,如某个值为真时,则执行其对应的语句,然后跳出else-if结构。如果所有的表达式的值均为假,则执行语句m + 1,然后执行后续程序。
【实例6】if语句实例:
void main()
{ int a,b,c,min;
printf("\n please input three number:");
scanf("%d%d%d ",&a,&b,&c);
if(a<b&&a<c) printf("min=%d\n",a );
else if(b<a&&b<c) printf("min=%d\n",b);
else if(c<a&&c<c) printf("min=%d\n",c);
else printf("There at least two numbers are equal\n");
}
(2)switch-case语句。
在C51语言中提供了直接处理多分支的方法,如switch-case语句。
- switch-case语句
switch-case语句的一般形式:
switch(表达式){
case常量表达式1:语句1;
case常量表达式2:语句2;
……
case常量表达式n:语句n;
default :语句n + 1;
}
含义:首先计算表达式的值,然后逐个与每一个case后的常量表达式值进行比较。当表达式的值与某个常量表达式的值相等时,就执行该case后的语句组,然后不再进行判断,继续执行后面所有的语句。如表达式的值与所有case后的常量表达式均不相同时,则执行default后的语句组。
【实例7】switch-case语句实例:
void main()
{ int num; printf("input one number:");
scanf("%d",& num);
switch(num)
{ case 1: printf("num =%d\n", num);break;
case 2: printf("num =%d\n", num);break;
case 3: printf("num =%d\n", num);break;
case 4: printf("num =%d\n", num);break;
default: printf("The number is out of the range\n", num);
}
}
2.循环控制语句
在C51语言中循环结构主要是利用for语句、while语句和do-while语句来实现的。
(1)for语句。
在C语言的循环语句中,for语句使用最为灵活。它常用于循环次数已知的循环控制,也可以灵活用于循环次数不确定的而只给出循环结束条件的情况。
for语句的一般形式:
for(表达式1;表达式2;表达式3)语句;
表达式1 通常在循环开始时用来给循环变量赋初值,一般是赋值表达式。也允许在for语句外给循环变量赋初值,此时可以省略该表达式。
表达式2 通常是循环条件,一般为关系表达式或逻辑表达式。只要这个条件是满足的,循环就得继续下去。表达式2一般是关系表达式或逻辑表达式,但也可以是数值表达式或字符表达式,只要其值非零,就执行循环体。
表达式3 通常是循环增量,用来修改循环变量的值,一般是赋值语句。表达式1和表达式3可以是逗号表达式,即每个表达式都可由多个表达式组成。
含义:求解计算表达式1(循环变量初值)的值;求解表达式2(循环条件)的值,若值为真(非0)则执行循环体一次,否则循环结束,执行for语句下面的语句;执行构成循环体的程序语句;计算表达式3(循环增量表达式)的值,转回求解表达式2;循环结束,执行for语句下面的语句。
【实例8】for语句实例:
void main()
{ for(int a=10;n>0;a --)
printf("%d",a);
}
(2)while语句。
while语句的一般形式:
while(表达式)语句
含义:先判断表达式,后执行语句。
【实例9】while语句实例:
void main()
{ int i=0;
while(i<=10) i++;
}
(3)do…while语句。
do…while语句一般形式:
do 循环体语句
while(表达式);
含义:先执行语句,后判断表达式。
【实例10】do…while语句实例:
void main()
{ int i=0;
do{ i++;}
while(i<=10);
}
3.转移控制语句
break语句、continue语句和goto语句都是限定转向语句,改变程序的正常流向,但是它们不允许用户自己指定转向,而是按程序事先规定的原则向某一点转移。
(1)break语句。
当break语句用于do-while、for、while循环语句中时,可使程序终止循环而执行后面的语句。
break语句的一般形式为:
语句 break;
(2)continue语句。
continue语句只能用在循环体中。其一般格式是:
continue;
含义:continue语句作用是结束本次循环,即跳过循环体重下面尚未执行的语句,转入下一次循环条件的判断与执行。
(3)goto语句。
goto语句也称为无条件转移语句,其一般形式如下:
goto 语句标号;
含义:goto语句的语义是改变程序流向,转去执行语句标号所标识的语句。
1.3.2 C51函数
程序设计中C51程序由一个主函数和若干个函数组成,主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次,所以有经验的开发人员将一些常用的功能模块编写成函数,放在函数库中以供调用,以减少重复程序段的工作量。
1.函数的划分
函数从形式上划分,分为无参数函数和有参数函数及空函数。
(1)无参函数的定义形式
类型标识符 函数名()
{ 声明部分
语句
}
(2)有参函数的定义
类型标识符 函数名(形式参数列表)
{ 声明部分
语句
}
(3)空函数
类型说明符 函数名()
{}
2.函数参数和函数的返回值
函数之间的参数传递,由函数调用时主调函数的实际参数与被调用函数的形式参数之间进行数据传递来实现。
(1)形式参数和实际参数。
形式参数:定义函数时,函数名后面括号中的变量名称为“形式参数”,简称“形参”。
实际参数:调用函数时,函数名后面括号中的表达式称为“实际参数”,简称“实参”。
(2)函数的返回值。
通过函数调用使主调函数能得到一个确定的值,这就是函数的返回值。
3.函数的调用
C51语言中被调用的函数必须是已经存在的函数,可以是库函数,也可以是用户自定义的函数。在确定函数存在的情况下用户可以通过以下方法来使用函数。
(1)函数调用的一般形式。
函数名(实参列表)
对于有参数型的函数,若包含多个实际参数时,则用逗号隔开各参数。其中实参与形参的个数应相等,且类型一致,并按顺序对应的进行数据传递。如果调用的是无参函数,可省去“实参列表”项,但括号不能省。
(2)函数调用的方式。
C51语言中可以通过以下3种方式实现函数调用。
① 函数作为一个语句调用,不要求函数带返回值,只要求函数完成一定的功能操作。
【实例11】语句形式调用实例:
void main()
{ int i=0; while(i<=10) i++; … …
Sum(); /*函数调用*/
}
② 将函数结果作为表达式的一个运算对象,要求函数带回一个确定的值以参加表达式的运算。
【实例12】表达式形式调用实例:
void main()
{ int a,b,i=0; while(i<=10) i++; … …
i=4*Sum(a,b); /*函数调用*/
}
③ 将函数作为另一个函数的参数进行调用。
【实例13】以函数的参数形式调用实例:
void main()
{ int a,b,c,i=0; while(i<=10) i++; … …
i= max(c,Sum(a,b)); /*函数调用*/
}
(3)调用函数的声明和函数原型。
在对一个函数进行调用时不仅需要其已经存在,还必须在调用前在主调函数中对被调用的函数进行声明,如调用的是库函数应在文件开头用#include命令将调用的有关库函数的信息“包含”到本文件中。
【实例14】函数的声明实例:
void main()
{ int max(int x,int y); /*函数的声明*/
int a,b,c,i=0; while(i<=10) i++; … …
i= max(c,Sum(a,b)); /*函数调用*/
}
函数原型的一般形式如下所示。
- 函数类型 函数名(参数类型1,参数类型2……)
- 函数类型 函数名(参数类型1 参数名1,参数类型2 参数名2……)
其中第1种形式是基本的形式,在声明函数时给出参数类型。也可以如第2种形式所示,在函数原型中加上参数名。
(4)函数的嵌套调用。
在C51中函数的定义都是相互独立的,但允在调用时许嵌对函数进行嵌套调用。即在调用一个函数的过程中,允许调用另一个函数,如实例13所示。
(5)函数的递归调用。
在C51中调用函数时,直接或间接地调用该函数本身,即称为函数的递归调用。但递归调用过程中应避免无终止地自身调用。
【实例15】函数递归调用的简单实例:
void fun()
{ int a=1, result,i;
for(i=0;i<10;)
{ i=a+I;
result = fun(); /*函数调用*/
}
return result;
}
1.3.3 C51数组和指针
1.C51数组
所谓数组就是指具有相同数据类型的变量集,并拥有共同的名字。其可以是一维的,也可以是多维的。
(1)一维数组
一维数组的说明格式:
类型 变量名[长度];
(2)多维数组
多维数组的一般说明格式:
类型 数组名[第n维长度] [第n-1维长度]…[第1维长度];
【实例16】数组的实例:
void main()
{ char num[3] [3]={{'','#',''},{'#','','#'},{'','#',''}}; /*定义多维数组*/
int i=0,j=0;
for(;i<3;i++)
{ for(;j<3;j++) printf("%c",num[i][j]);
printf("/n");
}
2.C51指针
(1)指针变量的定义。
在C51语言中,对变量的访问形式之一,就是先求出变量的地址,然后再通过地址对它进行访问,这就是这里所要论述的指针及其指针变量。变量的指针,实际上指变量的地址。
指针变量的一般定义:
类型标识符 *标识符;
其中标识符是指针变量的名字,标识符前加了个“*”号,表示该变量是指针变量,而最前面的“类型标识符”表示该指针变量所指向的变量的类型。一个指针变量只能指向同一种类型的变量,也就是说,不能定义一个指针变量,既能指向一个整型变量又能指向一个双精度变量。
(2)指针变量的引用。
在指针变量中只能存放地址,因此,在使用中不要将一个整数赋给一个指针变量。
(3)指针的运算。
指针允许的运算方式有指针在一定条件下进行比较,指针和整数进行加、减运算,两个指针变量在一定条件下进行减法运算等多种。
【实例17】指针的实例:
void main()
{ int a=3,*p;
p=&a; /*将变量a的地址赋值给指针变量p*/
printf("%d,%d",a,*p); /*输出二者的数值进行对比*/
}
【实例18】数组与指针实例:
void main()
{ int i=3,num[3]={1,2,3},*p;
p=num; /*将数组num[]的地址赋值给指针变量p*/
result =max(p,3); /*函数调用,计算数组的最大值*/
}