2019-05-21 22:37:36 qq_35379989 阅读数 192

无论是51、arduino还是stm32,在大学期间常用的单片机都是以C语言为基础的,这里列出C语言基础的一些语句函数,希望可以帮助初学者。

目录

一、语言基础

1.1、C语言概述

1.2、C语言语法基础

1.3、 C语言的数据类型

1.4 C语言运算符与表达式

二、数据的输入和输出

2.1 字符输入输出函数

2.2 格式输入输出函数

三、选择结构程序设计语句

3.1 if语句

3.2 switch语句

四、循环结构程序设计

4.1 while语句

4.2 do...while语句

4.3 for语句

4.4 循环体结构的嵌套

4.5 break语句和continue语句在循环结构中的应用

4.6 综合实例:

五、函数与编译预处理

5.1 函数概述

5.2 函数的定义和说明

5.3 函数的调用

5.4 函数的参数

5.5 函数的嵌套调用和递归调用

5.6 变量的存储类型

5.7 内部函数和外部函数

5.8 编译预处理命令


一、语言基础

1.1、C语言概述

#include<stdio.h>
#include<stdlib.h>
int main()
{
int num1.num2;
num1=1;num2=2;
printf(“num1+num2=%d”,num1+num2)
}

(1)头文件: #include语句是预处理指令,并不是执行语句,制定了程序引用的头文件(调用库功能)。

(2)主函数:包括一个main()函数。int表示main()返回一个整数,void表示main不接受任何参数。

(3)函数结构:任何函数,包括主函数main(),都由函数说明和函数体,两部分组成

函数类型 函数名(参数表)
{
    函数体(执行语句)
}

符号//之后是程序的注释信息,仅在一行内有效

/*和*/可跨越多行进行注释

1.2、C语言语法基础

(1)字符集

C语言具有4类字符集:

英文字母:大小写各26,共52个;

阿拉伯数字:0-10,共10个;

下划线:_ ;

特俗符号:由1-2个字符组成,如:+、-、*、/、%、++、--、<、>、=、>=、<=、==、!=、&&、||、&、|、~、^、>>、<<、()、[]、{}、?:、.、,、:

除字符串和注释外,C语言程序只能用字符集中的字符来书写。

(2)标识符:标识变量名、符号常量名、函数名、类型名、文件名等的有效字符序列,

C语言标识符只能有=由字母、数字、和下划线组成,且第一个字符必须为字母或者下划线。

(3)关键字:具有特定含义的标识符,C语言中的关键字都用小写字母表示,共有32个;

auto、break、case、char、const、continue、default、do、double、else、enum、extern、float、for、goto、if、int、long、register、return、short、signed、sizeof、static、struct、switch、typedef、union、unsigned、void、volatile、while

(4)常量:程序运行过程中,其值不能改变的量

(5)变量:程序运行过程中其值可以改变的量

1.3、 C语言的数据类型

1.3.1、 C语言的数据类型

 1、整型变量:不含小数部分的数值型数据;由机器中数据的长度分为基本整型(int)、短整型(short)和长整型(long);同样整型长度的数据又分为无符号(unsigned)和有符号(signed)

其中long int、short int、unsigned int中的关键字int可以省略。

关键字

字节数

取值范围

char

1

-128~127      即-2^7~(2^7-1)

unsigned char

1

0-255         即0~(2^8-1)

short[int]

2

-32768~32767  即-2^15~(2^15-1)

unsigned short[int]

2

0~65535       即0~(2^16-1)

int

4

-2147483648~2147483647 即-2^31~(2^31-1)

unsigned [int]

4

0~4294967295  即0~(2^32-1)

long [int]

4

-2147483648~2147483647 即-2^31~(2^31-1)

unsigned [int]

4

0~4294967295  即0~(2^32-1)

2、整形常量:十进制数值表示方法与数学上相同;八进制数值在数码前面加数字0;十六进制在数码前面加0x

1.3.2 实型数据

     1、实型变量:带有小数点的数,也称为浮点数。实行数据有:单精度实数(float)、双精度实数(double)、长双精度实数(long double)

关键字

字节数

精度

float

4

6~7      即(-3.4x10^-38)~3.4x10^38

double

8

15~16    即(-1.7x10^-308)~1.7x10^308

long double

16

18~19    即(-1.2x10^-4932)~1.2x10^4932

double型变量的值的最大有效位数通常是float型的两倍。

2、实型常量:一般不分float和double,任何一个实型数据既可以赋给float变量,又可以赋给double变量

 (1)十进制小数形式:由数字和小数点组成,如3.1415、-6.5、.3

 (2)指数形式:3.12E-6表示3.12x10^-6(十进制小数+e或E+十进制整数三部分组成);e或E前必须有数字,e或E后必须是整数;精度又称为有效位由于float的精度为7,前7位有效,0.1234567E+8

1.3.3 字符型数据

    1、字符型变量:字符型变量用来存放一个字符,占用一个字节,

如:char c1,c2;

     2、字符型常量:一种是一对单引号括起来的一个字符如’A’表示大写字母A,’ ‘表空格;另一种是单引号括起来的由反斜杠(\)引导的一个字符或一个数字序列

字符形式

功能

\n

换行

\t

制表字符

\b

退格

\r

回车

\\

反斜杠字符

\’

单引号字符

\”

双引号字符

\ddd

1~3位八进制数表示的字符

\xhh

1~2位16进制表示的字符

   3、字符串常量:用双引号括起来的字符序列,“guoqing”C语言中每个字符串都是以’\0’为结束标记的;不能将字符串常量赋给一个字符变量。每一个字符均以ASCII码存放,最后一个为空字符(二进制00000000,纪委null或\0,”a”为两个字节)

1.4 C语言运算符与表达式

类型

示例

算术运算符

+、-、*、/、%

关系运算符

>、<、==、>=、<=、!=

逻辑运算符

!、&&、||

位运算符

<<、>>、~、|、^、&

赋值运算符

=

条件运算符

?、:

逗号运算符

指针运算符

*、&

求字节数运算符

sizeof

强制类型转换运算符

(类型)

分量运算符

.(点)、->

下标运算符

[ ]

其它

函数调用运算符()

 1.4.1 算术运算符和算术表达式

  1、算术运算符:+、-、*、/、%(其中+、*、/为双目符即要求两个操作数,-为单目符可仅需一个操作数取负值)

   (1)两个操作数都是整型运算结果为整型,只要有一个是实型结果为实型。如果被除数或除数有一个是负值舍入方向不确定,多数机器结果向零取整,如-5/3=-1(余-2),少数结果为-2(余1)

   (2)求余运算要求两个操作数都是整数

   (3)*、/、%优先级高于+、-运算,算术运算符的结合顺序为从左至右

  2、自增运算符与自减运算符:++、--(自增与自减操作数只能是变量,且只能是整型或字符型也可用于指针变量)

   (1)将自增自减运算符放在变量前面,其作用先给变量加一或减一,然后再使用该变量值:x=++a为a=a+1,;x=a;

   (2)将自增或自减放在变量的后面,其作用是先使用该变量的值,然后再给变量加一或减一:x=a++为 x=a; a=a+1;

   (3)自增或自减的结合方向为从右向左,这与运算符的运算方向相反,如-i++意为-(i++)

1.4.2 赋值运算

 1、赋值运算符:”=”,将一个数据或一个表达式的值赋给一个变量;

 2、赋值类型转换:左右两边变量类型不一致,但都是数值型或字符型时,全将赋值运算符右边的值类型自动转换成与左边相同的类型;

 3、必须把复合赋值符右边的表达式看成一个整体,先求右边表达式值,再和左边的变量做相关运算:a+=x+y*3为a=a+(x+y*3);

1.4.3 关系运算符

 1、关系运算符(六个):<(小于) <=(小于等于) >(大于) >=(大于等于) ==(等于) !=(不等于);

 2、优先级:==和=!同级,前四个优秀级高于后两个,算术运算符的优先级高于关系运算符的优先级,关系运算符高于赋值运算符:a=b

二、数据的输入和输出

C语言本身没有提供输入和输出语句,C语言编译系统中的stdio.h头文件包含了标准输入和输出有关变量的定义及相应的宏定义

2.1 字符输入输出函数

字符输入函数是getchar,函数原型:int getchar(void); 函数功能:从设备输入一个字符,函数的返回值是该字符的ASCII码值

字符输出函数putchar 函数原型:int puchar(int);

示例程序:

#include<stdio.h>
main()
{
 int i=97,j;
 char ch=’a’;
 j=getchar();
 putchar(i);
 putchar(j);
putchar(‘\n’);
 putchar(ch); 
}  

输入b,结果为

ab
a

字符串输入函数gets(s);  字符串输出函数:puts(s);

 #include<stduio.h>
 int main(void)
 {
  char s[5];
  gets(s);
  puts(s);
 }  

输入abcde 输出abcde

2.2 格式输入输出函数

scanf是具有格式控制输入的函数,函数格式:scanf(“格式控制字符串”,地址表);

格式控制字符串必须用英文状态的双引号括起来,主要由%和格式字符组成,作用是将输入的数据转换成指定的格式后存入地址表所指向的变量中。

d 用来输入十进制整数、c用来输入单个字符、s用来输入字符串、f用来输入实数

需注意:

(1)格式控制字符串中除格式字符外没有其他字符,两个数据之间允许以一个或多个空格隔开,也可以按回车键、跳格键隔开;

如:scanf(“%d%d%d”,&a,&b,&c);

 下面输入数据的方式都是正确的

13  1  23
13
1
23

 对于:scanf(“x=%d,y=%d,z=%d”,&x,&y,&z);

输入为:x=123,y=456,z=789

(2)可以指定scanf函数输入数据所占的宽度,系统将自动按指定宽度来截取数据。

   scanf(“%3d%4d%3d”,&x,&y,&z)  输入1234567890,则x为123,y为4567,z为890

(3)格式字符’%’后面使用‘*’时,表示该对应的数据被禁止使用

      scanf(“%3d%*4d%3d”,&x,&y,&z); 输入1234567890 x为123,4567呗跳过,890赋给y

  (4)用scanf()输入实数,格式说明符为%f,但不能规定精度

  (5)格式字符串必须在地址表中有一个变量与之对应,并且格式格式字符必须与相应变量一致,如果输入不一致,scanf()将停止处理,其返回值为0,若为%c格式,空格字符和转义字符都作为有效字符输入

  格式输出函数printf可用来输出任何类型数据,而且可以同时输出多个不同类型的数据,一般调用形式为: printf(“格式控制字符串”,输出表);

三、选择结构程序设计语句

3.1 if语句

1、单分支if语句 格式:

 if(表达式)
   语句;

表达式为真,执行语句,表达式为假,不执行语句。

2、双分支if else语句:一般格式:

if(表达式) 语句1;
else(表达式) 语句2;

如果表达式的值为真(非0)执行表达式1,如果表达式值为假(0),执行语句2;

#include<stdio.h>
main()
{
 float score;
 printf(“input score\n”);
 scanf(“%f”,&score);
 if(score>=60)
  printf(“pass\n”);
 else
  printf(“fall!\n”);
}

3、多分支选择语句
         一般格式:

 if(表达式) 语句1;
 else if(表达式2) 语句2;
  else if 
     ....
       else 语句n+1;

首先求表达式1的值,如果值为真(非0),则执行语句1,后面的语句不再执行,if语句结束,否则再求表达式2的值,如果为真,则执行语句2

#include<stdio.h>
main()
{
 float socre;
 printf(“input score:”);
 scanf(“%f”,&score);
 if(score>=90)
  printf(“A\n”);
   else if(score>=80)
   printf(“B\n”);
else if(score>=70)
printf(“C\n”);
 else if(score>=60)
  printf(“D\n”);
}

4、if语句嵌套:如果if(表达式)或else后面的语句又包含一个或多个if语句,就称为if语句的嵌套。

 if语句两层嵌套结构如下:

if(表达式1) 
 if(表达式1_1)  语句1_1;
 else           语句1_2;
else
 if(表达式2_1) 语句2_1;
 else          语句2_2;
#include<stdio.h>
main()
{
 int x,y;
 printf(“input x:”);
 scanf(“%d”,&x);
 if(x<=0)
  if(x<=-10)
   y=x+2;
  else
   y=x-2;
else
 if(x<=10)
  y=x*2;
 else
  y=x/2;
printf(“y=%d”,y);
}

 注意:

 (1)if后面的表达式,一般为逻辑表达式或关系表达式,可以为任何数据类型(整型、实型、字符型、指针数据型)

 (2)对于双分支if else语句,else语句不能单独使用,它必须和if子句配合使用

 (3)如果if或else后面包括多条语句,需要将这多条语句用{ }括起来构成复合语句

 (4)if与else配对原则:从最内层开始,else总是与它上面相距最近且尚未配对的if配对。

3.2 switch语句

 3.2.1、switch一般形式:

switch(表达式)
{
 case 常量表达式1: 语句1;
 case 常量表达式2: 语句2;
 ......
 case 常量表达式3: 语句3
 default          : 语句n+1;
}

计算表达式的值,并逐个与其后的常量表达式值做比较,当值与某个常量表达式的值相等时,即执行其后的语句,然后不再进行判断,继续执行后面所有case后的语句。如果表达式的值与所有case后的常量表达式均不相同,则执行default后的语句。

#include<stdio.h>
main()
{
 int x;
 scanf(“%d”,&x);
 switch(x)
 { case 1:printf(“Spring\n”);
  case 2:printf(“Summer\n”);
  case 3:printf(“Autumn\n”);
  case 4:printf(“Winter\n”);
 }
}

在程序中输入1,则输出结果为

Spring
Summer
Autumn
Winter

3.2.2、break语句

为了实现在执行满足条件的语句后就使流程跳出switch结构,break语句可以达到这个目的。

switch(表达式)
{ case 常量表达式1: 语句1; break;
 case 常量表达式2: 语句2; break;
 .......
 case 常量表达式n: 语句n; break;
 default          ; 语句n+1;
}
#include<stdio.h>
main()
{
 int x;
 switch(x)
 { case 1:printf(“Spring\n”); break;
  case 2:printf(“Summer\n”); break;
  case 3:printf(“Autumn\n”); break;
  default:printf(“Winter\n”); break;
 }
}

例程:输入两个整数和运算符,要求计算结果。

#include<stdio.h>
void main()
{
 int num1,num2;
 char sign;
 printf(“input expression:\n”);
 scanf(“%d%c%d”,&&num1,&sign,&num2);
 switch(sign)
 {
  case ‘+’:printf(“%d\n”,num1+num2); break;
  case ‘-’:printf(“%d\n”,num1-num2); break;
  case ‘*’:printf(“%d\n”,num1*num2); break;
  case ‘/’:printf(“%d\n”,num1/num2); break;
  default:print(“input error\n”);
 }
}

注意:

 (1)case后的各常量必须各不相同,且必须是整数或者字符型;

 (2)case后允许有多个语句,可以不用{ }括起来;

 (3)case子句出现的顺序不会影响运行结果;

 (4)如果多种情况需公用一组执行语句,可用case的常量表达式将多种情况列出,在最后一种情况之后安排需要执行的语句。

 switch(grade)
 { case 9:
  case 8: printf(“Good\n”);
  case 7: 
  case 6: printf(“pass\n”);
  default: printf(“Fail\n”);
}

grade的值为9或8时,输出good!;grade的值为7或6时,输出Pass!;grade的值不是9/8/7/6中的任何一个时,输出Fail!

四、循环结构程序设计

4.1 while语句

一般表达式:

while(表达式)

循环体结构;

如果表达式的值非0,就执行循环体语句,然后再计算表达式的值,由表达式的值决定是否再次执行循环体语句,直到表达式的值为0时推出循环。

例程:

#include<stdio.h>
main()
{
 float score,sum=0,ave=0;
 int count=0;
 scanf(“%f”,&score);
 while(score>=0)
 { sum=sum+score;
  count++;
  scanf(“%f”,score);
 }
 if(count!=0) ave=sum/count;
 printf(“ave=%.2f\n”,ave);
}

编写程序,判断一个数是否为素数

#include<stdio.h>
main()
{
 int m,i=2;
 scanf(“%d”,&m);
 while(m%i!=0&&i<=m-1)
   i++;
 if(i==m)
   printf(“%d is prime\n”,m);
 else
   printf(“%d isn’t prime\n”,m);
}

4.2 do...while语句

一般格式:

do

  循环体结构;

while (表达式);

先执行一次循环体语句,然后计算表达式,如果表达式的值非0,则重复执行一次循环体语句,直到表达式的值为0时推出循环,语句结束。do...while的特点是先执行再判断。

例程:

#include<stdio.h>
main()
{
 float score,sum=0,ave=0;
 int count=0;
 scanf(“%f”,&score);
 if(score>=0)
  do
  { sum=sum+score;
   count++;
   scanf(“%f”,score);
  } while(score>=0);
 if(count!=0) ave=sum/count;
 printf(“ave=%.2f\n”,ave);
}

注意:

(1)while中的表达式通常是关系表达式或逻辑表达式,表达式的值可以为任意值;

(2)循环体中必须要有能使循环体结束的语句,否则形成无限循环;

(3)while语句先判断表达式的值,若表达式的值一开始就为0,循环体语句一次都不执行;do...whilw语句的循环体至少执行一次。

例程:根据公式s=1=1/(1+2)+1/(1+2+3)+1/(1+2+3+4)+...+1/(1+2+3+4+..+n)

#include<stdio.h>
main()
{
 int n,k,t=0;
 double s=0.0;
 printf(“\n please enter n:”);
 scanf(“%d”,&n);
 k=1;
 do
 { t=t+k;
  s=s+1.0/t;
  k++;
 } while(K<=n);
 printf(“\n The result is %lf\n”,s);
}

4.3 for语句

for语句不仅适用于循环次数确定的情况,还适用于循环次数不确定而只给出循环结束条件的情况。

一般格式:

for(表达式1;表达式2;表达式3;)

  循环体语句;

首先求表达式1的值,然后求表达式2的值,如果表达式2的值为真(非0),则执行循环体语句,接着求表达式3的值,然后再求表达式2的值,如此反复,直达表达式2的值为0;

例程:

#include<stdio.h>
main()
{
 int i,n;
 long fac;
 scanf(“%d”,&n);
 fac=1;
 for(i=1;i<=n;i++)
  fac=fac*i;
 printf(“\n%d!=%ld\n”,n,fac);
}

说明:

(1)如果在for语句之前给循环体变量赋了初值,则表达式1可以省略,但其后的分号不能省略,如果3个表达式都省略,循环体中的语句就会无限次循环,即死循环;

(2)逗号表达式在for语句中的运用。for语句中的表达式1和表达式3都可以使用逗号表达式,特别是在两个循环变量控制控制循环的情况下,例如:

int i,j,sum=0;
for(i=1,j=100;i<=j;i++,j--)
sum=sum+i+j;

例程:输入一个整数n,计算n(包括n)以内能被5或7整除的所有自然数的倒数之后并输出。

#include<stdio.h>
main()
{
 int i,n;
 double sum=0.0;
 printf(“\nInput n: “);
 scanf(“%d”,&n);
 for(i=1;i<=5;i++)
  if(i%5==0||i%7==0)
  sum=sum+1.0/i;
 printf(“sum=%lf\n”,sum);
}

4.4 循环体结构的嵌套

在循环体语句中又包含一个完整的循环体结构,称为循环体结构的嵌套。

例程:编写程序输出如下图形:

*
**
***
****
*****
#include<stdio.h>
main()
{
 int i,j;
 for(i=1;i<=5;i++)
   {
for(j=1;j<=1;j++)
 printf(“*”);
printf(“\n”);
}
}

例程:编写程序求100~1000之间素数的个数。

#include<stdio.h>
main()
{
 int m,i,k,count=0;
 for(m=101;m<1000;m+=2)
 {
  i=2;
  while(m%i!=0&&i<=m-1)
   i++;
  if(i==m)
   count++
  }
 printf(“The prime number is %d\n”);
}

4.5 break语句和continue语句在循环结构中的应用

  1. break语句

一般格式:、break;

break语句是限定转向语句。break语句常在switch语句和循环结构中出现。在循环结构中通常与if语句在一起使用,一旦瞒住条件就使程序立即退出循环体结构,转而执行循环结构后面的语句。

例程:从键盘上连续输入数据,如果是正数,则累加;如果是负数,则程序结束。

#include<stdio.h>
main()
{
 int x;
 long sum=0;
 for( ; ; )
 { scanf(“%d”,&x);
  if(x>=0) sum+=x;
  else break;
 }
 printf(“sum=%ld\n”,sum);
}

2、continue语句

一般格式:

continue;

continue语句被称为继续语句。continue一般也与if语句一起使用,一旦条件成立,就跳过循环体中continue语句之后的语句段,提前结束本次循环体的执行,接着进行下一次循环条件的判断。

例程:编写程序输出100~200之间能被7整除的数。

#include<stdio.h>
main()
{ int n;
 for(n=100;n<=200;n++)
 { if(n%7!=0;
  continue;
  printf(“%5d”,n);
 }
 printf(“\n”);
}

break语句和continue语句的区别是,一旦条件满足,break语句则结束整个循环,不再进行循环条件的判断;而continue语句只是结束本次循环,接着进行下一次循环条件的判断。

break语句:

for(n=1;n<=10;n++)
{
 if(n==5)
  break;
 printf(“%3d”,n);
}

运行结果:1 2 3 4

continue语句:

for(n=1;n<=10;n++)
{
 if(n==5)
  continue;
 printf(“%3d”,n);
}

运行结果:1 2 3 4 6 7 8 9 10

4.6 综合实例:

编写程序输出所有的水仙花数:水仙花数是指3位数的各位数字的立方和等于这个数本身

#include<stdio.h>

main()

{ int unit,ten,hundred,n;

 for(n=100;n<1000;n++)

 {

  hundred=n/100;

  ten=n/10-hundred*10;

  unit=n%10;

  if(n==unit*unit*unit+ten**ten*ten+hundred*hundred*hundred)

   printf(“%6d”,n);

 }

}

编写程序求解百钱买百鸡问题:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。

设变量a、b分别代表鸡翁、母鸡的个数,鸡雏的个数为100-a-b。a在0~19,b在0~33。

#inlcude<stdio.h>
main()
{
 int a,b,c;
 for(a=0;a<=19;a++)
  for(b=0;b<=33;b++)
  { c=100-a-b;
   if(5.0*a+3.0*b+c/3.0==100)
   printf(“a=%d,b=%d,c=%d\n”,a,b,c);
  }
}

 

五、函数与编译预处理

C语言源程序是由函数组成的。前面的程序大都只有一个主函数main(),在C语言程序设计中,通常将一个较大程序分成几个功能单一的子程序模块,用函数来实现每个子程序的1功能。C语言程序由一个或多个函数构成,其中有且只有一个名为main()的主函数,C语言总是从main()函数开始执行,最后在main()函数结束整个程序的运行。

5.1 函数概述

(1)一个C源程序必须有且只有一个主函数main()。C程序总是从main()函数开始执行,调用其他函数后总是回到main()函数,最后在main()函数中结束整个程序;

(2)一个C程序由一个或多个源文件组成——可分别编写、编译和调试;

(3) 一个源文件由一个或多个函数组成,可为多个C程序公用;

(4)C语言是以源文件为单位而不是以函数为单位编译的;

(5) 在C语言中,所有函数(包括主函数)。一个函数的定义,可以放在程序中的任意位置,主函数main()之前或之后。但在一个函数的函数体内,只能调用其他函数,不能再定义另一个函数,即不能嵌套定义;

(6)主函数名main()是系统定义的,是运行时首先调用的函数,它可以调用其他函数,但不能被其他函数调用了其他函数间可以相互调用,也允许嵌套调用。习惯上把调用者称为主调函数。函数可以自己调用自己,称为递归调用;

(7) 函数定义上看可分为库函数和用户定义函数两种:
                 1 库函数:由C系统提供,用户无需定义,只需在程序前写出该函数原型的头文件即可;

      2 用户定义函数:用户按需编写的函数,不仅要在程序中定义函数本身,而且还必须在主函数模块中对该被调函数进行类型说明,才能使用;

 (8)从主调函数与被调函数之间数据传送角度来看,函数又分为无参函数和有参函数两种。

对库函数一般调用形式

函数名(参数表)

例程:

#include<math.h>
#include<stdio.h>
main()
{
 double a,b;
 scanf(“%lf”,&a);
 b=sin(a);
 printf(“6.4lf”,b);
}

include命令必须以#开头,系统提供的文件以.h为后缀,文件名用一对双引号或者一对尖括号<>括起来,二者的区别是:<math.h>表示编译时只按系统标准方式检索文件目录,而用”math.h”时,编译系统先从目标文件所在的子目录中找math.h文件,若找不到在用尖括号方法搜索

注意:include是命令,不是语句,结尾没有分号。

5.2 函数的定义和说明

5.2.1 函数的定义格式

[函数返回值的类型名] 函数名([类型名 形式参数1,类型名 形式参数2,...])
/*函数首部*/
{
 [说明部分;]  /*函数体*/
 [语句部分;]
}

其中[]内为可选项。

注意:函数名、一对圆括号和花括号不能省略。

1、无参数的一般形式

无参函数的一般形式为:

函数返回值的类型名 函数名(void)
{ [说明语句部分;]
 [可执行语句部分;]
}

新标准中,函数不可以默认参数表,如果不需要参数,则用void表示,主函数main()除外。

例程:构造一个输出一行“*”的函数

void printstar()
{  printf(“***********\n”);
}

2、有参函数的一般形式

有参函数的一般形式为:

函数返回值的类型名 函数名(数据类型 参数[数据类型 参数2...])
{ [说明语句部分;]
 [可执行语句部分;]
}

有参比无参多了一个参数表。将函数定义中的参数表称为形式参数表

例程:构造一个求两个双精度数之和的函数。

double add(double x,double y)
{ double s;
 s=x+y;
 return s;
}

注意:

  (1) 函数名和形式参数都是用户命名的标识符。同一程序中,函数名必须唯一;形式参数只要在同一函数中唯一即可,可以与其他函数的变量同名;

  (2)C语言规定,不能在一个函数的内部再定义函数

 对函数类型名的说明,必须与return语句中返回值表达式的类型一致。如果不一致,则以函数类型为准,由系统自动进行转换,如果省略函数标准类型,系统一律按照int类型处理。

例程:求两个数中的大数(例中函数调用时使用了类型转换)

#include<stdio.h>
max(float x,float y)
{
 float z;
 z=x>y?x:y;
 return z;
}

main()
{
 float a=1.5,b=0.5;
 float c;
 c=max(a,b);
 printf(“max is %f\n”,c);
}

运行结果: max is 1.000000

C语言中函数补充内容:

  (1) 空函数:无参数且函数体为空的函数,一般形式为:

[函数类型] 函数名(void) {}

例如:

dump() {}

 (2) 带参数的形式参数表中类型和变量必须成对出现,如下定义是错误的:

  double add(double x,y)

5.2.2 函数的返回值

函数的返回值就是return返回语句中的表达式的值。

return语句格式:

return(表达式); 或  return 表达式;  或  return;

功能:

 (1) 把return后面的表达式的值返回给调用函数

 (2)把控制转向调用函数

例如:return(x);  return x+y;  return; 都是合法的

注意:void型的函数中不能包括带值得return语句;主体函数体内不能出现return语句。

 (1) 当函数没有return语句时,以结束函数的大括号作为返回点。这时的返回值是系统给的不确定值,】。假如为了明确表示不返回值,可以用void定义成无(空)类型;

 (2)在同一函数中可根据需要在多处出现return语句,但函数第一次遇到return时就立即停止执行,并返回到主调函数。

例程:编写程序使两个字符s1和s2相等时,返回1,否则返回-1

int find_char(char s1,char s2)
{
 if (s1==s2)
  return 1;
 return -1;
}

以下程序是合法的

#include<stdio.h>
double add(double x,double y)
{
 double s;
 s=x+y;
 return s;
}

main()
{
 double a,b,c;
 a=10;b=20;
 c=add(a,b)                   /*1*/
 printf(“%lf”,add(a,b));      /*2*/
 add(a,b);                    /*3*/
}

在/*1*/中,add的返回值被赋予c,在/*2*/行中,返回值实际上没有赋给任何变量,单被printf所使用。在/*3*/行中,返回值被丢弃不用

5.2.3 函数的说明

 1、函数说明也称为函数声明,是函数调用前的准备。在首次调用某函数前,使用函数说明语句使C语言编程程序了解函数返回值类型,这个信息对于程序能否正确运行影响极大,因为不同类型的数据有不同的长度和内部表示方法,在ANSI新标准中,采用函数原型方式,对被调函数进行说明,格式如下:

函数类型 函数名(数据类型[参数名1][,数据类型[参数名2]...]);

其中[]内为可选项。若没有参数,可用void明确说明。

函数说明语句就是函数定义中的函数首部加上分号,这些内容称为函数原型,例如:

float max(float x,float y);

等价于

float max(float,float);

函数说明的例子如下:

void srand(unsigned int seed);

函数srand 无返回值,仅有一个unsigned int类型的参数

说明:

 (1) 函数说明可以是一条独立的语句,也可以与普通变量一起出现在同一个说明语句中,如:

float x,max(float,float);

  (2)在函数名前没有说明函数类型时,默认为int类型,如int dump(int); 等价于dump(int);

2、函数说明的位置

(1)C语言规定,被调用函数的说明位置处在被调用前并且在所有函数的外部时,则后面所有外置上都可以对该函数进行调用。

(2)函数说明放在调用函数内的说明部分,这时其作用只在本调用函数内部。

例程:

#include<stdio.h>
main()
{
 float a=1.5,b=0.5;
 float max(float,float);
 float c;
 c=max(a,b);
 printf(“max is %f”,c);
}

float max(float x,float y)
{
 float z;
 z=x>y?x:y;
 return z;
}

运行结果 max is 1.500000

5.3 函数的调用

一般形式为:

函数名([实际参数表])

[]内为可选项。当实际参数多于一个时,各实际参数间以逗号隔开。实际参数可以是常量、变量或表达式,如max(float x,float y)的调用可为max(2,3)、max(3+4.2,7*a)、max(a,b)等

 调用时,首先计算实参表达式的值,然后把这些值按顺序一一传给对应的形参。当函数无参数时,实参列表就位空。

说明:

 (1)调用函数时,函数名必须与具有该功能的自定义函数名完全一致;

 (2) 实参的个数必须与所调用函数的形参个数相等;

 (3)实参表中包括多个参数,对参数的求值顺序因系统而异,有的系统自左向右,有的系统则相反,VC6.0、Turbo C 和MS C是按自右向左的顺序进行

#include<stdio.h>
main()
{
 int a=1,b,f(int,int);
 b=f(a,++a);
 printf(“%d”,b);
}

int f(int x,int y)
{
 int z;
 if(x>y) z=1;
 else
   if(x==y) z=0;
   else z=-1;
 return(z);
}

运行结果0

在一个函数中调用另一个函数需要具备的条件

(1)被调函数已经存在(库函数或用户自定义)

(2)使用库函数或其他文件中的函数,应在文件开头用#include命令将有关编译处理信息包含到文本中。

(3)对被调用的函数进行说明

5.4 函数的参数

函数中的参数分为形参和实参

(1)形参与实参:调用函数时形参才分配内存单元,同时实参将数据传给实参,调用结束后形参所占内存单元被释放,实参单元保持原值;

(2)实参可以是变量、常量、表达式

(3)实参和形参应个数相等、类型系统

(4)调用函数时,主调函数和被调函数之间有数据传递关系,实参对形参的数据传递是单向的,只能由实参传给形参,反之则不行,即形参的改变不会影响实参

 例程:编写程序实现从两整数中求较大数

#include<stdio.h>
float max(float x,float y);
main()
{
 float a,b;
 float c;
 scanf(“%f”,&a,&b);
 c=max(a,b);
 printf(“a=%f,b=%f,c=%f\n”,a,b,c);
 }

float max(float x,float y)
{
 float z;
 z=x>y?x:y;
 printf(“x=%f,y=%f\nz=%f\n”,x,y,x);
 return(z);
}

输入:2,3

运行结果:

x=2.000000 y=3.000000
z=3.000000
a=2.000000 b=3.000000
max=3.000000

(1)在上面的max函数中,假若把z=x>y?x:y;改为z=++x>++y?x:y;若执行时输入2,3,执行后结果为:

x=3.000000,y=4.000000
z=4.000000
a=2.000000,b=3.000000
max=4.000000

(2)多次调用时,形参分配到的内存单元已经被收回,故形参分配到的内存单元不一定系统

(3)形参和实参分配存储单元的时刻与作用范围不同,分配到的存储单元也不同,故形参和实参可以同名

例程:

#include<stdio.h>
main()
{
 int x=10,y=30;
 printf(“Before swap:x=%d y=%d\n”,x,y);
 swap(x,y);
 printf(“After swap :x=%d y=%d\n”,x,y);
}

int swap(int x,int y)
{
 int t;
 t=x;x=y;y=t;
 printf(“In swap function:x=%d y=%d\n”,x,y);
}

运行结果:

Before swap:x=10 y=30
In swap function:x=30 y=10
After swap:x=10 y=30

程序执行到语句swap(x,y)时,进行参数传递,形参变量x,y进行了交换,执行完毕收回形参x,y的存储单元,返回到主函数,主函数中实参x,y没有变化

5.5 函数的嵌套调用和递归调用

函数的嵌套调用是指,在执行被调用函数时,被调用函数又调用了其他函数。

例程:

#include<stdio.h>
int dif(int x,int z);
int max(int x,int y,int z);
int min(int x,int y,int z);
void main()
{
 int a,b,c,d;
 scanf(“%d%d%d”,&a,&b,&c);
 d=dif(a,b,c);
 printf(“Max-Min=%d\n”,d);
}

int dif(int x,int y,int z);
{
 return max(x,y,z)-min(x,y,z);
}

int max(int x,int y,int z)
{
 int r;
 r=x>y?x:y
 return(r>z?r:z);
}

int min(int x,int y,int z)
{
 int r;
 r=x<y?x:y;
 return(r<z?r:z);
}

运行结果:输入 5 9 7后

Max-Min=4

5.5.2 函数的递归调用

1、递归的概念:一个函数在它的函数体内,直接或间接地调用自己,满足以下三个条件,可使用递归法:
(1) 可以把求解问题转化成一个新问题,这个新问题与原来问题的解法相同,只是处理的对象的值有规律地递增或递减;

(2)可以应用这个转化过程使问题得到解决;

(3)必定有一个明确的结束递归的条件(一定要有递归出口)

例程:用递归法求n!

#include<stdio.h>
main()
{
 int n;
 float s;
 float f(int);
 printf(“Input n=”);
 scanf(“%d”,&n);
 s=f(n);
 printf(“%d!=%.0f”,n,s);
}

float f(int x)
{
 int t;
 if(x==0) t=1;
 else t=f(x-1)*x;
 return t;
}

运行结果:

Input n=3
3!=6

在求n!中,既可以使用递推法也可以使用递归法:

 递推方法:0!=1->1!=0!X1->2!=1!x2.....n!=(n-1)!xn

 递归方法:首先回推:欲求n! 先求(n-1)! .... 0!;

           再递推:直到1!->2!...n!

递归和迭代之间的选择,一般情况,当一个问题既可以选择递推又可以使用递归应该避免使用递归,因为迭代避免了一些列函数调用和返回中所涉及的参数传递的时间耗费和返回值的额外开销,故比递归方法快,占用空间小。但有些问题很难建立一个迭代方法,用递归方法却很容易,如汉诺塔问题:

汉诺塔问题:有三个塔,每个都放若干个盘子。开始所有盘子都在A上,盘子从上到下,按直径增大,设计一个盘子移动号顺序使得A上的所有盘子借助于塔B移动到C上

(若只有一个盘子直接从A到C,若有一个以上:1、把n-1个盘子依照题目中的规则从A借助于塔C移动到塔B,2、将剩下一只盘直接从A到C,3、再次将B塔上的n-1个盘子借助于塔A搬到塔C)

#include<stdio.h>
void hanoi(int m,int a,int b,int c)
{
 if(n==1)
  printf(“%d->%d”,a,c);
 else
 {
  hanoi(n-1,a,c,b);
  printf(“%d->%d”,a,c);
  hanoi(n-1,b,a,c);
 }
}

main()
{
 int n;
 printf(“input n:”);
 scanf(“%d”,&n);
 hanoi(n,1,2,3);
}

例程:反向输出一个整数

反向输出一个正整数的算法归纳为:

if(n为一位整数)
 输出n;
else
 { 输出n的个位上的数字;
   对剩余数字组成的新整数重复”反向输出操作”;
 }
#include<stdio.h>
void main()
{
 void printn(int x);
 int n;
 printf(“Input n=”);
 scanf(“%d”,&n);
 if(n<0)
 {
  n=-n;putchar(‘-’);
 }
 printn(n);
}

void printn(int n)
{
 if(x>=0&&x<=9)
 printd(“%d”,x);
else
 {
  printf(“%d”,x%10);
  printfn(x/10);
 }
}

5.6 变量的存储类型

5.6.1 变量的存储类型

C语言中的变量必须先定义后使用,变量的类型决定了计算机为变量预留多少存储空间。C语言中变量分为全局有效、局部有效和在复合语句内有效3中。

一个完整的变量说明格式如下:

[存储类型] 数据类型 变量表; 或 数据类型 [存储类型] 变量表;

C语言中变量有4中存储类型:自动变量(auto)、寄存器变量(register)、静态变量(static)、外部变量(extern)。

根据它们在内存中的位置,又分为自动和静态两类。其中auto、register描述的时自动,存储在动态存储区;static、extern描述的时静态类,存储在静态存储区。

用户程序的存储一般分为三个区,如下表:

动态存储区(堆栈)

静态存储区

程序代码区

静态存储区存放的变量在编译时分配存储单元,程序结束才收回存储单元。动态存储区的变量会在程序运行期间根据需要随时动态分配存储空间。

C语言中所有的变量都有自己的作用域。变量说明的位置不同,其作用域也不同据此将C语言中的变量分为局部变量(内部变量)和全局变量(外部变量)

5.6.2 局部变量

在函数内部或复合语句内部定义的变量称为局部变量。函数的形参也属于局部变量。局部变量的作用域时本函数内部或复合语句内部。所以局部变量也称“内部变量”。

局部变量分为:自动变量、寄存器变量、静态局部变量。

主函数定义的局部变量只能在主函数中使用,其他函数不能使用。同时,主函数也不能使用其他函数定义的局部变量,这一点是与其他语言不同的。

 1. 自动变量

在函数内部或复合语句内部定义的变量,如果没有写明存储类,或使用了auto说明符,系统就认为所定义的变量属于自动变量类别,有时也称为(动态)局部变量、

形参是被调用函数的局部变量。形参默认的关键字是auto,但不能将auto直接加在形参前面。

自动变量生存期为:函数调用时,分配存储单元,函数返回时,收回存储单元;复合语句执行前分配存储单元,复合语句执行后收回存储单元。自动变量的初始化是:每一次调用,形参都以实参为初值。所以未赋初值的自动变量“无定义”,其值不定。

注意:复合语句内部,所在函数的同名局部变量被屏蔽掉,只有复合语句内部的同名变量有效,如下程序:

#include<stdio.h>
main()
{
 int x=1;
 { int x=2;
  { int x=3;
   printf(“%d”,x);
  }
  printf(“%d”,x);
 }
 printf(“%d”,x);
}

运行结果:

3
2
1

3个x各有自己的存储空间和作用域,互不冲突,其中内层x屏蔽外层x的访问。

2 寄存器变量

register类型变量存放在CPU的寄存器中,它们属于自动变量。运行程序中,访问位于寄存器中的值比访问内层中的值快很多。

例程:计算的值。i=0,1,2...9

#include<stdio.h>
double power(int x,register int n)
{
 register int i;
 int p=1;
 for(i=0;i<n;i++)
  p=p*x;
 return(p);
}

main()
{
 register int i;
 for(i=1;i<10;i++)
  printf(“i=%d:%.0lf\t,%.0lf\n”,i,power(2,i),power(-3,i));
}

程序说明:

 a、只有自动变量和形参可以被定义为register变量,寄存器变量只能是int、char和指针类型的变量;

 b、 register变量没有地址,不能对它进行求址运算,因为它放在寄存器中而不是内存中;

 c、 register只是对编译程序的一种建议,当没有足够的寄存器空间编译程序将自动按auto处理

3 静态局部变量

在函数体(复合语句)内部,用以下定义格式定义的变量称为静态局部变量:

static 数据类型 变量表

例如:

static int a=8;

关键字static使得变量存储在内存的静态存储区,编译程序为之生成永久存储单元,其生存期为整个程序的一次运行。

静态局部变量的初始化只在编译时进行一次,每次调用它所在的函数时,不再重新赋初值,只是保留上次调用结束时的值。若定义但不初始化,则自动赋以0(数值型)或‘\0’(字符型)

例程:

#include<stdio.h>
main()
{
 int f(void);
 int j;
 for(j=0;j<3;j++)
  printf(“%d\n”,f());
}

int f(void)
{
 static int x=1;
 x++;
 return x;
}

运行结果:

2
3
4

函数f被调用3次,由于x是静态局部变量,编译时分配存储空间,故每次调用函数f时,变量x不再重新初始化,保留加1的值,得到上面的输出结果。

5.6.3 全局变量和静态全局变量

当变量定义在函数体外时,该变量就称为全局变量,全局变量也称为外部变量。

对于全局变量,可用extern和static两种说明符,用static修饰的全局变量称为静态全局变量(静态外部变量)。全局变量和静态全局变量都属于静态存储类。生存期都是程序的一次执行,定义和初始化都是在程序编译时进行的,初始化只有一次。若没有初始化,则自动赋以’0’或’\0’。

  1. 全局变量

全局变量不属于任何一个函数,其作用域:从全局变量的定义位置开始,到本文件结束为止。全局变量可为各函数所共享,所以函数之间数据交流可以使用全局变量,但并不提倡使用。

一个C语言程序可以由一个或多个源程序文件组成,每个源程序文件作为一个编译单位单独进行编译,然后连接成一个可执行文件exe。假如每个文件都定义了一个同名全局变量,则分别编译时将分别给每个变量分配一个存储空间,连接时就会出现同一个变量名“重复定义”的错误。此时可通过外部变量说明实现在其他文件中无需再次定义而直接使用。

外部变量说明的一般形式:

extern 数据类型 全局变量1[全局变量2...]

其作用是声明这些变量是在别处已经定义的全局变量,通知编译程序无需再给它分配存储单元,这时该变量的作用域进行了延伸。若外部变量出现引用它的函数中,则该变量的作用域从extern说明处起,延伸到了该函数末尾。函数外的extern变量延伸到整个文件结束。

例程:

#include<stdio.h>
void try_1(void)
{
 extern int i;          /*先用extern进行说明,说明i是在后面定义的外部变量*/
                        /*i的作用域延伸为从此处到整个文件的结束*/
 i=i+5;
}

int i;
main()
{
 try_1();
 printf(“i=%d\n”,i);
}

运行结果:i=5

如果将全局变量的作用范围扩展至整个源文件,可以将变量说明放在文件头部。

例程:

/*FILE1*/
#include<stdio.h>
int i;
void func();
main()
{
 i=5;
 printf(“FILE1:%d\n”,i);
 func();
}

/*FILE2*/
extern int i;      /*外部变量说明,说明文件FILE2中的变量i是引用File1中定义的外部变量i*/
void func()
{
 printf(“FILE2:%d\n”,i);
}

运行结果:

FILE1:5
FILE2:5

说明:

a当程序中多个函数使用同一数据时,全局变量很有效,可加强函数模块之间的联系,但又使这些函数依赖全局变量,使得独立性降低。在编制大型程序时变量值可能在程序其他地点被改变;

b在同一源文件中,容许全局变量和局部变量同名。此时,在局部变量的作用域内,全局变量将被屏蔽而不起作用。

例程:

#include<stdio.h>
void num()
{
 extern int x,y;    /*外部变量说明,说明num函数中的x,y是后面定义的全局变量
 int a=15,b=10;    /*变量a,b是局部变量,其作用域只在num函数内部*/
 x=a-b;
 y=a+b;
}

int x,y;            /*全局变量定义*/
main()
{
 int a=7,b=5;      /*变量a,b是局部变量,其作用域只在main函数的内部*/
 x=a+b;
 y=a-b;
 num();
 printf(“%d,%d\n”,x,y);
}

运行结果: 5,25

注意:

a、如果extern x,y;不加上extern,则函数内定义了局部变量x,y,其作用范围为函数num内部,与main函数中用的全局变量x,y无关,输出结果为12,2

b、如果程序内extern int x,y;语句不加上extern,并且全局变量定义int x,y;位于程序文件顶部,输出结果仍是12,2,因为此时虽然全局变量x,y的作用域是整个文件,但局部变量的作用域内,同名全局变量将被屏蔽而不起作用。

  1. 静态全局变量
  2. 当用static说明符说明全局变量时,此变量就称为静态全局变量或静态外部全局变量。此时static的作用不是把全局变量改为静态存储,因为全局变量本身就是静态存储类,而是限制了它的作用域只能是本文件内,不能用extern说明符扩展到其他文件中,这有利于管理大型复杂程序,有效消除了副作用。

例如,把上方两个例子中FILE1的外部变量定义int i;改为static int i;,则分别编译两个文件时一切正常,但是把这两个文件连接在一起时将产生FILE2中符号’i’无定义的错误。

5.7 内部函数和外部函数

当一个源程序由多个源文件组成时,C语言根据函数能否被其他源文件中的函数调用,将函数分为内部函数和外部函数。

5.7.1 内部函数

如果一个函数只能被本文件中的函数调用,不能被同一源程序其他文件调用,这种函数称为内部函数(又称为静态函数)。

定义一个内部函数,只需在函数类型前再加一个static关键字即可,定义格式如下:

static 函数类型 函数名(函数参数表)

{......}

例如:

static int fun(int a,int b,int c) {......}

使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数是否会与其他文件中的函数同名。

5.7.2 外部函数

在定义函数时如果没有加关键字static或冠以extern,则表示此函数是外部函数,其定义格式为:

[extern] 函数类型 函数名(函数参数表)

{......}

其中[ ]内为可选项。如:

int fun(int a,int b,int c) {......} 或 extern int fun(int a,int b,int c) {......}

若函数定义在其他文件内,或定义在调用点之前,在调用外部函数时,必须对其进行说明:

[extern] 函数类型 函数名(参数类型表[函数名1[,参数类型表2,...])

例程

a文件mainf.c中定义外部函数示例。

main()
{ extern void input(...),process(...),output(...);   /*说明本文件要用到其他文件中定义的函数*/
 input(...);process(...);output(...);             /*函数调用*/
}

b文件subf1.c中定义外部函数示例
...
extern void input(...)                       /*定义外部函数input*/
{...}

c文件subf2.c中定义外部函数示例
...
extern void process(...)                      /*定义外部函数process*/
...

d文件subf3.c中定义外部函数示例
...
extern void output(...)                       /*定义外部函数output*/
{...}

5.8 编译预处理命令

在C语言中,凡是以字符”#”开头的行都称为:编译预处理”命令行。他们实际上不是C语言的一部分,却扩展了C语言程序设计环境。

所谓”编译预处理”就是在对C源程序进行编译前,由编译预处理程序对这些编译处理行进行处理的过程。

C语言预处理命令有:#define、#undef、#include、#if、#else、#elif、#endif、#ifdef、#indef、#line、#pragma、#error。这些命令均以”#”开头,一行只写一个命令,并且末尾不能加分号,以区别于其他C语句。他们可根据需要出现在程序中的任何一行的开始位置,但通常都写在程序的开始位置。

5.8.1 宏替换

  1. 不带参数的宏定义

不带参数的宏定义形式为:

#define 宏名 替换文本

#define 宏名

后一种形式不包含”替换文本”,仅说明标识符”宏名”被定义。

#define PI 3.14

标识符PI称为”宏名”,是用户定义的标识符,通常大写,不得与程序中的其他名字相同;”3.14”是替换文本,也称”宏体”,编译时,在此命令行之后,预处理程序对源程序中的所有名为PI的标识符用字符串”3.14”来替换,这个替换过程称为”宏替换”。

替换文本可以包含已定义的宏名

#define PI 3.14
#define JAPI (PI+1)
#define JAJAPI (2*JAPI)

说明:

a、宏名一般习惯用大写字母表示,也可以用小写字母

b、使用宏名替换一个字符串,可增加可读性,也便于修改,当发生改变时,可以只改#define命令行,从而做到一改全改;

c、宏定义是用宏名代替一个字符串,简单的置换,不做正确性检查

d、宏定义不是C语句,结尾不能有分号,加了分号,会连分号一起进行置换

#define PI 3.14;

则对程序中的语句

printf(“%f”,PI*10*10);

预处理后悔被替换为:

printf(“%f”,3,14;*10*10);

e对于程序中双括号括起来的字符串内的字符,即使宏名相同,也不进行置换。

#define R 3.0
#define PI 3.14
#define L 2*PI*R

则对程序中的语句:

printf(“L=%f\n”,L);

预处理后只会替换后面的L,前面双括号的L不会替换

f宏定义是一个专门预处理命令的专用名词,只做字符替换,不分配空间;

g宏替换不占运行时间,只占编译时间,宏替换是在编译时进行的,而函数调用是在程序运行时处理的

六、数组

6.1 一维数组

1、一维数组:当数组中每一个元素只有一个下标时,称为一维数组。C语言中,数组必须显示地说明。定义一个一维数组一般形式为:

类型名 数组名[常量表达式];

例如:

int a[5];  //int时类型名,a[5]就是一维数组说明符

(1)方括号中的5规定a[5]含有5个元素,由于C语言固定每个数组第一个月元素下标总为0,所以5个数组元素表示为a[0]、a[1]、a[2]、a[3]、a[4]。此处不能使用a[5]。

(2)类型名int规定了a数组中的每一个元素都是整型,即每个元素只能存放整数。

(3)定义数组类型时可以是int、char、float、double、unsigned等;

(4)数组名后是用方括号括起来的常量表达式,不能用圆括号。常量表达式是数组的长度,即数组中所包含元素的个数。

2、一维数组的引用:C语言规定只能逐个引用数组元素,不能一次引用一个数组。一维数组元素的引用形式如下:

数组名

编程将数字0~4放入一个整数组并输出

#include<stdio.h>
#include<stdlib.h>

main()
{
	int i, x[5];
	for (i = 0; i < 5; i++)
		x[i] = i;
	for (i = 0; i < 5; i++)
		printf("%d\n", x[i]);
	system("pause");
}

(1)一个数组元素实质上是一个变量名,代表内存中一个存储单元;

(2)C语言中,一个数组不能整体引用,如数组x[4]不能用x代表x[0]到x[4]这5个元素。数组名中存放的是一个地址常量,它代表整个数组的首地址;

(3)C语言不检查数组元素下标是否越界。因此数组的两端都有可能越界进而破坏其它存储单元的数据。

3、一维数组的初始化

数组的初始化:定义数组时对数组各元素指定初值。

(1)在定义数组时对数组元素赋初值

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

(2)给部分元素赋初值

int a[5]={5,4};

表明只给前两个元素赋初值,即a[0]=5,a[1]=4,其它元素自动赋0值。

(3)对全部元素赋初值,可以不指定数组长度,系统自动根据数值个数来决定数组长度

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

系统a定义为有5个元素的数组。

2016-11-05 18:27:24 shenziheng1 阅读数 7060

1.为什么也是C语言?

用C 语言来开发单片机系统软件最大的好处是编写代码效率高、软件调试直观、维护升级方便、代码的重复利用率高等,因此C 语言编程在单片机系统设计中越来越广泛的运用。PIC 单片机的软件开发,同样可以用C 语言实现。
Microchip 公司没有自行开发PIC单片机的C 语言编译器,但其他公司有开发众多支持PIC 单片机的C 语言编译器,常见的有Hitech、CCS、IAR、Bytecraft 等公司。其中最常用的是Hitech 公司的PICC 编译器,它稳定可靠,编译生成的代码效率高,在用PIC 单片机开发者中得到广泛认可。
Hitech-PICC 编译器基本上符合ANSI C标准,但是不支持函数的递归调用。其主要原因是因为PIC 单片机特殊的堆栈结构。PIC 单片机的堆栈是硬件实现的,其深度已随芯片固定,无法实现需要大量堆栈操作的递归算法。  成的代码效率高,在用PIC 单片机开发者中得到广泛认可。

2.MpLab中配置PIC C编译环境,并进行项目开发

为便于PICC编译器的编译环境设置,应先在MPLAB IDE集成开发环境下创建一个PICC  C编译器的项目。
1.启动MPLAB IDE7.00集成开发环境窗口。选择集成开发环境中的Project->New菜单项,打开如下所示的新项目对话框,在此对话框中设置项目名和项目路径。

在项目名文本框中输入项目名led,在项目路径文本框中输入项目路径D:\led,也可以通过单击Browse按钮选择项目名的保存路径。
2.器件选择,其操作过程如下所示。首先在MPLAB集成开发环境中打开Configure菜单,然后单击Select Device菜单项,弹出如下所示的器件选择对话框。此处可以选择PICl6F877A作为开发芯片。

3.设置项目
在创建项目和选定器件后,接下来就可以设置工程的编译环境。首先进行语言组件的设置。
在Active Toolsuite下拉列表框中选择HI-TECH PICC Toolsuite作为开发工具组件,然后在Toolsuite Contents列表框中选择PICCCompiler项,如下图所示。  

3.PICC基本编程

3.1 PICC 中的基本变量类型

PICC 支持的基本变量类型见下表:

3.2 PICC 中的高级变量

基于上表的基本变量,除了bit 型位变量外,PICC 完全支持数组、结构和联合等复合型高级变量,这和标准的C 语言所支持的高级变量类型没有什么区别。例如:
数组:
unsigned int data[10];
结构体:
struct commInData {
unsigned char inBuff[8];
unsigned char getPtr, putPtr;
};
联合体:
union int_Byte {
unsigned char c[2];
unsigned int i;
};

3.3 PICC 对数据寄存器bank 的管理

在PIC单片机编程时,单片机数据寄存器的bank是由编程员管理的,因此在定义变量时必须决定这些变量具体放在哪一个bank 中缺省时,所定义的变量将被定位在bank0中,例如下面所定义的这些变量:
unsigned char buffer[32];
bit flag1,flag2;
float val[8];
以上变量都是分布在bank0 中。定义在其它bank 内的变量前面必须加上相应的bank 序号,例如:
bank1 unsigned char buffer[32];  //变量定位在bank1 中
bank2 bit flag1,flag2;  //变量定位在bank2 中
bank3 float val[8];  //变量定位在bank3 中

3.4 volatile 修饰词 

PICC 中还有一个特殊的变量修饰词“volatile”,用来说明一个变量的值是会随机变化的,即使程序没有刻意对它进行任何赋值操作。
在单片机中,作为输入的IO 端口其内容将是随意变化的;很多特殊功能寄存器的值也将随着指令的运行而动态改变。所有这种类型的变量必须将它们明确定义成“volatile”类型,例如:
volatile unsigned char STATUS @ 0x03;
volatile bit commFlag;

3.5 标准库函数

PICC 提供了较完整的C 标准库函数支持,其中包括数学运算函数和字符串操作函数。在程序中使用这些现成的库函数时需要注意的是入口参数必须在bank0 中。
如果需要用到数学函数,则用 “#include <math.h>” 包含头文件;如果要使用字符串操作函数,就需要包含“#include <string.h>”头文件。在这些头文件中提供了函数类型的声明。直接查看这些头文件就可以知道PICC 提供了哪些标准库函数。
C 语言中的格式化输出函数“printf/sprintf”用在单片机的程序中时要特别谨慎。printf/sprintf 是一个非常大的函数,一旦使用,你的程序代码长度就会增加很多。 

4.C和汇编混合编程

用C 语言进行单片机应用程序开发时经常要使用汇编语句。比如,单片机的一些特殊指令操作在标准的C 语言语法中没有直接对应的描述,例如PIC 单片机的清看门狗指令“clrwdt”和休眠指令“sleep”。这样,一个项目中就会出现C 和汇编混合编程的情形,我们在此讨论一些混合编程的基本方法和技巧。
在C 原程序中直接嵌入汇编指令是最直接最容易的方法。如果只需要嵌入少量几条的汇编指令,PICC 提供了一个类似于函数的语句:
asm(“clrwdt”)  ;
双引号中可以编写任何一条PIC 的标准汇编指令。例如:
for (;;) {
asm("clrwdt"); //清看门狗
asm("sleep"); //休眠
asm(“nop”); //空操作延时 
 }
如果需要编写一段连续的汇编指令,PICC 支持另一种语法描述:用“#asm”开始指令段,用“#endasm”结束。
例如下面的一段嵌入汇编指令实现了将0x20~0x7F 间的RAM 全部清零:
#asm
      movlw 0x20
      movwf  _FSR
      clrf  _INDF
      incf _FSR, f
      btfss _FSR,7
      goto  $-3
#endasm
2019-11-18 16:08:45 CodingPs 阅读数 114

单片机为什么还在用C语言编程?答案是:C语言是最适合单片机编程的高级语言。

这个问题的意思应该是:现在有很多很好用的高级语言,如java,python,VC等等,为什么这些语言不能用来编写单片机程序呢?那么这个问题的答案就是:不能不能,而是不合适。

                                  

一、单片机编程的特点

对单片机编程来说,首先要考虑的是单片机的程序空间和数据空间都是有限的,所以要让程序尽量短小精悍,以节省程序占用的存储空间。

第二、单片机编程的一个主要对象是对单片机的端口和内部寄存器的操作和配置,这个需要比较精确的时序控制。

第三、单片机算法运算中,尽量使用加法、减法、移位运算,因为乘法和除法运算会非常费时间,尤其是除法,会耗费很多时间,这对于速度本身就有限制的单片机来说,是一个很大的负担。

                                  

二、高级语言编写单片机程序的缺陷

高级语言可以实现更为优化的算法,更为方便的执行方案,但是,高级语言对程序存储空间的占用要比汇编和C语言多很多。这是最致命的一点,单片机有限的存储空间需要靠精打细算来设计程序,根本经不起高级语言臃肿的代码体积。

高级语言无法实现精确的时序控制。

                                 

三、C语言是一个折中选择

其实用C语言开发单片机也是一个折中方案,因为最适合单片机开发的编程语言实在太过晦涩难懂,并且每一种单片机的汇编指令有很大区别,所以想把一个程序从这种单片机移植到另一种单片机简直是痴心妄想,还不如重新写一遍程序。

而C语言代码执行效率高,也比较精简,更便于移植......所以在现今的单片机编程语言中,C语言才会占据绝对主导地位

作者丨悟空问答:老马识途单片机

“我是一名从事了10年开发的老程序员,最近我花了一些时间整理关于C语言、C++,自己有做的材料的整合,一个完整的学习C语言、C++的路线和工具。如果感觉自学C/C++编程有困难的话可以湫湫扫下方二维码。这里是编程爱好者的聚集地,欢迎初学和进阶中的小伙伴。希望你也能凭自己的努力,成为下一个优秀的程序员。

 

2008-07-20 08:14:00 xyzvalue 阅读数 2101
 以下内容只有回复后才可以浏览

ed2k://|file|[十天学会单片机和C语言编程].Lesson1.rar|449712628|262b8896ad6828cd33ed7189fe94cb2d|h=76MXIF34BFV3VUPLLBN3ASNOVCACHTO3|/
ed2k://|file|[十天学会单片机和C语言编程].lesson10.rar|667224261|ed9eb3658e78db507b7feeb40ec8266e|h=I4VMWODCTZSHMWO7M2CXSV3N3UVV6GQP|/
ed2k://|file|[十天学会单片机和C语言编程].lesson11.rar|681442896|e19147acf6fa169d20129173f521ebf3|h=YRTUBCZZWJJPKWZJUWXNXDBSBKLPIL6L|/
ed2k://|file|[十天学会单片机和C语言编程].lesson12.rar|460469602|921c15b80247fcfc494ab15d2044929b|h=YT6WHJNZBCXAQQ4HQLR3JMZWGHVZBHTH|/
ed2k://|file|[十天学会单片机和C语言编程].lesson13.rar|190113124|e919ce3c566d662080a069dc3c43d0b7|h=U4Z4Q5OJXHLKMD6VTNZHM7N2C2WHPCE3|/
ed2k://|file|[十天学会单片机和C语言编程].Lesson2.rar|345592875|420801534cd254ba3327213b27fcdf4f|h=YRU65TTC2WUL5A365CBHF2DR6M7XC3JC|/
ed2k://|file|[十天学会单片机和C语言编程].Lesson3.rar|386879252|36bf77bdd3903ee6bf482c4612e1357c|h=VZTMPP6TXVWFHGPXI5HVMACGID2SXLU5|/
ed2k://|file|[十天学会单片机和C语言编程].Lesson4.rar|284906926|5ec086a51b3f0187c5f5a538dfe006e0|h=A7LM7FPIJUF5MR6VXZQ2CGMRQPCJWLXD|/
ed2k://|file|[十天学会单片机和C语言编程].Lesson5.rar|350262624|3d72a28200940d87b7cee30e0ac8c4fb|h=CQSG4COAICEDSRNJIX6TJ65GU4CMGLXB|/
ed2k://|file|[十天学会单片机和C语言编程].Lesson6.rar|361522032|280e6a927a80b56be3c3564f2b04f263|h=ZRZIRTQ34NOWJS3AOXLJ5JQI5L3J7VPY|/
ed2k://|file|[十天学会单片机和C语言编程].Lesson7.rar|405452138|82425b53f9b04c035e35bdd92289f66f|h=MXEBCYZZCVRZTH4YYMY5ZNNI6WMSSLUY|/
ed2k://|file|[十天学会单片机和C语言编程].Lesson8.rar|464253442|db2d86462508c46b01d5dc1dd1022d37|h=77PDYPQCS6NXL4CPIGAFLP5IWZ4ATOTC|/
ed2k://|file|[十天学会单片机和C语言编程].lesson9.rar|281473797|fee38d1f01fda17e47e54160429d45cf|h=4AJTWM2746ZNME4NW4MU272PLTQVYUNH|/
ed2k://|file|单片机外围电路设计及C语言编程视频教程内容目录V2.doc|6905856|0417c6bb75d337de2374be1784bb6bd2|h=3ZIFLPTEHNL72A4O6OPEJ2G7FEAJSXBW|/
ed2k://|file|前四课作业.rar|81836|44a355d6bb545f8b0c59f734beb8a1fa|h=E4J2QI7WFI34Q55WQ2WCQN7DOK2ULASR|/
请复制链接用迅雷下载

2019-07-05 00:40:26 liuxianfei0810 阅读数 457

51单片机期末考试复习资料集合,单片机C语言考试资料总结。主要可应付单片机汇编语言期末考试也可应付单片机C语言期末考试。资料在附件里,欢迎下载,若里面有答案错误的地方还请自行修正。资料在附件里!

单片机C语言for循环延时计算。

博文 来自: sczhangheng

PIC 单片机的 C 语言编程

博文 来自: bh_wang

C语言单片机!

阅读数 571

没有更多推荐了,返回首页