目录

  • 1 第一章 C语言简介
    • 1.1 C语言前世今生
    • 1.2 主流开发环境介绍
    • 1.3 第一个小程序解析
    • 1.4 常见编译错误
    • 1.5 章节知识点小结
  • 2 算法基础
    • 2.1 算法-程序的灵魂
    • 2.2 算法的描述-流程图
  • 3 数据类型与运算符
    • 3.1 数据描述
    • 3.2 运算符和表达式1
    • 3.3 运算符和表达式2
    • 3.4 章节知识点小结
  • 4 顺序结构程序设计
    • 4.1 输入和输出
    • 4.2 顺序结构程序设计
    • 4.3 章节知识点小结
  • 5 选择结构程序设计
    • 5.1 关系运算符和关系表达式
    • 5.2 逻辑运算符和逻辑表达式
    • 5.3 if语句
    • 5.4 条件运算符
    • 5.5 switch语句
    • 5.6 章节知识点小结
  • 6 循环结构程序设计
    • 6.1 while循环结构
    • 6.2 do_while循环结构
    • 6.3 for循环结构
    • 6.4 循环的嵌套
    • 6.5 break语句和continue语句
    • 6.6 章节知识点小结
  • 7 数组
    • 7.1 一维数组
    • 7.2 二维数组
    • 7.3 字符数组
    • 7.4 章节知识点小结
  • 8 函数
    • 8.1 子程序设计
    • 8.2 函数定义
    • 8.3 函数的调用
    • 8.4 局部变量和全局变量
    • 8.5 参数传递
    • 8.6 函数递归调用
    • 8.7 章节知识点小结
  • 9 指针
    • 9.1 指针的基本概念
    • 9.2 指针变量的定义及引用
    • 9.3 通过指针引用数组元素
    • 9.4 指向多维数组的指针和指针变量
    • 9.5 用指向数组的指针作函数参数
    • 9.6 指针与字符串
    • 9.7 函数指针和指针函数
    • 9.8 章节知识点小结
  • 10 用户自己建立数据类型
    • 10.1 定义和使用结构体变量
    • 10.2 使用结构体数组
    • 10.3 结构体指针
    • 10.4 章节知识点小结
  • 11 编译预处理
    • 11.1 宏定义预处理
    • 11.2 文件包含预处理
    • 11.3 条件编译预处理
    • 11.4 章节知识点小结
  • 12 文件
    • 12.1 文件的基本知识
    • 12.2 文件的基本操作
    • 12.3 章节知识点小结
函数的调用





主函数是程序的入口,若主函数中调用了其它函数,将进入其它函数执行其功能,执行完毕之后再继续执行主函数中内容。程序执行流程如下图所示

函数调用的一般形式

格式: 

函数名(实参表列)

说明:

(1) 如果调用无参函数,则实参列表没有,但是括号不可省略。

(2) 形参和实参之间为一一对应,故它们之间个数必须一致、类型一致或兼容,且实参之间以“,”隔开。

8.3.1】函数调用示例。

#include <stdio.h>

int f(int a,int b)

{

 int c;

 printf("a=%d,b=%d\n",a,b);

 if(a>b) c=1;

 else  if(a==b)  c=0;

     else  c=-1;

 return(c);

}

void main( )

{

 int i=2,p;

 p=f(i,++i);

 printf("%d\n",p);

 return;

}

函数调用方式

函数调用的三种方式:

(1) 函数语句:将函数调用作为一条语句,函数不带返回值,只完成某项功能操作。

如第一节中提到的函数,执行时可以只有:printstar();其功能只是打印一系列号。

(2) 函数表达式:函数出现在一个表达式中,函数带回一个确定值以参加表达式的运算。

c2*max (a,b);

(3) 函数参数:函数调用作为一个函数的实参。如:

m=max (a,max (b,c));

  printf(" %d",max(a,b));


对被调用函数的声明

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

(1) 被调用函数必须是已存在的函数;

(2) 如使用库函数,一般应在本文件开头用#include命令,如:#include "stdio.h"

(3) 如使用用户自己定义的函数,且该函数与调用它的函数在同一个文件中。但如果被调用函数的位置出现在主调用函数的后面,一般还应在主函数中对被调用函数作声明(说明)。声明的作用是把函数名、函数参数的个数和参数类型这些信息通知编译系统,以便对被调用函数据的编译检查。的返回值类型加以说明,例如:类型标识符、被调函数的函数名;

(4) 对第3条,以下几种情况可以不在调用函数中加类型说明,

如函数的值是整型或字符型(系统按整型对待);

如被调用函数的定义出现在主调函数之前,可以不加说明;

如已在所有函数定义之前,在文件开头、函数的外部已说明了函数类型。

请看下面两个例子。

例8.3.2】输入二个实数,求其和。

#include <stdio.h>

void main( )

{

float a,b,c;

scanf(" %f,%f ",&a,&b);

c=add(a,b);

printf(" sum is %f ",c);

 return 0;

}

float add(float x, float y)

{

float z;

z=x+y;

return(z);

}

 

该程序在编译过程会报错,原因是程序进行编译时是从上到下逐行进行的,当编译到第5行时,编译系统不能确定add是否为函数名,因为具体的函数定义还在下面。

有二种方法可以避免这种情况发生。一是将add()函数定义放在主调用函数main()之前;二是在主调用函数main()内函数调用语句之前对被调用函数add()作声明。第二种情况程序调整如下:

#include <stdio.h>

void main( )

{

 float a,b,c;

 float add(float x, float y);   //对被调用函数add()作声明

 scanf("%f,%f",&a,&b);

 c=add(a,b);

 printf("sum is %f\n",c);

 return ;

}

float add(float x, float y)     //该行称为函数原型

{

 float z;

 z=x+y;

 return(z);

}

运行结果:

可能发现,函数的声明就是函数定义的第一行后面加一个分号。我们把函数定义的首行称为函数原型。因为函数的形参名称只是一种形式名称,用哪一个名称都可以,所以对被调用函数的声明语句中,形参名还可省略。如上面的声明语句可以写为:

float add(float, float );

如果在文件的开头即所有函数之前,已对本文件中所调用的函数进行了声明,则在各函数中不必对其所调用的函数再作声明。

例8.3.3】设计一个简单算术运算的演示程序,求两个整数的加、减和乘运算的结果。

    解题思路:

    分别设计三个函数用来实现求两个数的加、减和乘运算的结果,以及一个菜单功能函数void menu(),并将它们放在主函数的下面,在主函数上面增加对上述四个函数的原型声明(虽然前三个函数返回值都是整型,可以省略声明,但建议养成这样的习惯),在主函数设计循环语句实现完成对算术运算函数的调用,直到输入0退出并结束程序。

    程序代码:

#include<stdio.h>

int add(intx,int y);        //以下3行在所有函数之前,且在函数外部

int sub(intx,int y);

int mul(int x,int y);

void menu();

void main( )                 //main函数中要调用下面的三个函数不必再对它们进行声明

{

  int i,a,b;

  menu();

  printf("please choiceoperataion:");

   scanf("%d",&i);

   do

   {

    switch(i)

       {

              case 1:

                       printf("pleaseinput two integer:");

                                   scanf("%d,%d",&a,&b);

                                   printf("%d+%d=%d\n",a,b,add(a,b));

                             break;

          case 2:

                       printf("pleaseinput two int:");

                                   scanf("%d,%d",&a,&b);

                                   printf("%d-%d=%d\n",a,b,sub(a,b));

                      break;

         case 3:

                       printf("pleaseinput two int:");

                                   scanf("%d,%d",&a,&b);

                                   printf("%d*%d=%d\n",a,b,mul(a,b));

                      break;

       }

   menu();

   printf("please choiceoperataion:");

   scanf("%d",&i);

   }while(i!=0);

   return ;

}

void menu()

{

   printf("1.add    2.sub   3.multply    0.quit\n");

}

int add(int x,int y)

    int z;

    z=x+y;

    return(z);

}

int sub(int x,int y)

    int  z;

    z=x-y;

    return(z);

}

int mul(int x,int y)

   int  z;

   z=x*y;

   return(z);

}

运行结果:



嵌套调用

在调用一个函数的过程中,又调用另一个函数,这种现象称为函数的嵌套调用。

 嵌套调用的形式

可以用下图来描述嵌套的调用。



在上图中,main函数调用了函数a,而函数a又调用了函数b,所以main函数相当于间接调用了b函数,这样就出现了函数的嵌套调用。在上图中,括号中的数字顺序也就是程序的执行流程顺序。


下面用例8.4.1来解释函数的嵌套调用。

例8.4.1】用弦截法求方程的根。x3-5x2+16x-80=0


解题思路:

根据上图所示,按以下步骤进行:

(1) 先取两点x1,x2,计算f(x1)f(x2),如f(x1)*f(x2)<0,则此两点间必有根,否则重新选取,直至满足此要求为止;

(2) 计算(x1,f(x1))(x2,f(x2))连线与X轴交点x,计算f(x)

(3) f(x)*f(x1)<0,则根在x1x之间,此时令x2=x,计算f(x2),返回上步(2;否则根在xx2之间,令x1=x,计算f(x1),返回上步(2);

(4) 重复23,直至|f(x)|<10-6为止,至此可认为此时的x为所求。

程序代码:

#include <stdio.h>

#include  "math.h"

float f(float x)

{

 float y;

 y=((x-5.0)*x+16.0)*x-80.0;

 return(y);

}

float xpoint(float x1,float x2)

{

   float y;

   y=(x1*f(x2)-x2*f(x1))/(f(x2)-f(x1));

   return(y);

}

float root(float x1,float x2)

{

  float x,y,y1;

  y1=f(x1);

  do

  {

       x=xpoint(x1,x2);

       y=f(x);

       if(y*y1>0)

       {

              y1=y;

              x1=x;

       }

       else  x2=x;

  }while(fabs(y)>=0.0001);

 return(x);

}

void main()

{

 float x1,x2,f1,f2,x;

 do

  {

     printf(" input x1,x2:\n ");

     scanf("%f,%f",&x1,&x2);

    f1=f(x1);f2=f(x2);

 }while(f1*f2>=0);

 x=root(x1,x2);

 printf(" A root of equation is %8.4f\n " ,x);

 return ;

}


本例中除main函数外又定义了f( )xpoint( )root( )三个函数,其功能分别是求函数值、弦与x轴的交点、求根的迭代过程。这里main( )函数调用root函数,而root函数调用xpoint函数,xpoint函数又调用f函数。

关于函数嵌套调用的几点说明:

(1) 各函数是相互独立的,并不相互从属。

(2) 程序从main( )函数开始执行。

(3) 如自定义函数定义在main( )之前,则在main( )中不必对这些函数作进行声明。


*EASYX图形编程.用函数来实现高效率的绘图

实际中有许多类似的图案,如果一一单独绘制,太麻烦。于是,我们需要一个公用的绘制过程,就是函数。

例如,我们需要画5个三角形,位于不同的位置。我们可以将绘制单个三角形的过程写成函数,函数内是一个独立的程序段,这个绘制过程很简单。
然后,在需要绘制的时候,调用这个函数即可。可以通过参数来解决细微差异(图案的坐标、颜色等),例如:

#include<graphics.h>
#include <conio.h>

// 在坐标 (x,y) 处,用颜色 c 绘制三角形
void sanjiaoxing(int x, int y, int c)
{
    //
设置画线颜色
    setcolor(c);

    // 画三角形的三条边
    line(x, y, x+50, y);
    line(x, y, x, y+50);
    line(x+50, y, x, y+50);
}

void main()
{
    initgraph(640, 480); //
初始化图形窗口

   sanjiaoxing(100, 100, RED);
    sanjiaoxing(120, 160, BLUE);
    sanjiaoxing(140, 220, GREEN);
    sanjiaoxing(160, 120, BLUE);
    sanjiaoxing(160, 160, GREEN);
    sanjiaoxing(220, 140, GREEN);

   getch(); // 按任意键继续
    closegraph(); //
关闭图形窗口
}

再结合循环等控制条件,就能绘制更复杂漂亮的图案了。试试运行下面程序,理解一下函数的用处:

#include<graphics.h>
#include <conio.h>

void sanjiaoxing(intx, int y, int color)
{
     //
设置画线颜色
     setcolor(color);

    // 画三角形的三条边
     line(x, y, x+10, y);
     line(x, y, x, y+10);
     line(x+10, y, x, y+10);
}

void main()
{
    initgraph(640, 480); //
初始化图形窗口

   for(int x=0; x<640; x+=10)
        for(int y=0; y<480; y+= 10)
           sanjiaoxing(x, y, RGB(x*255/640, y*255/480, 0));

   getch(); // 按任意键继续
    closegraph(); //
关闭图形窗口
}