目录
main函数和库函数;
在C语言中,main函数是必不可少的,程序在运行的时候,会执行main函数的主体部分,在main函数中使用的printf,scanf,puts函数在C语言中被称为库函数。
什么是函数;
我们先创建一个简单的函数:
创建一个函数,接收两个整数的参数,返回较大值的整数!
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int max(int a, int b)
{
if (a > b)
{
return a;
}
else
{
return b;
}
}
int main(void)
{
int a = 0;
int b = 0;
printf("请输入两个整数:\n");
printf("整数1:"); scanf("%d", &a);
printf("整数2:"); scanf("%d", &b);
max(a, b);
printf("两个整数最大值是%d", max(a, b));
return 0;
}
我们可以用一张图片来解答刚才创建函数的流程!
函数这一名词,来源于数学术语函数(function)。意思是“功能”“作用”“职责”的意思 。
函数定义与调用;
函数的创建---函数定义
函数的使用---函数调用
函数定义(创建):
函数是由两个大部分组成的,分别是函数头,函数体。而函数头又包括(返回类型,函数名称,形参声明)。
函数头:该部分表示函数的名称和格式。
返回类型:函数返回的值的类型,可以是double也可以是void(不返回值)。
函数名:函数的名称,我们在使用函数的时候,就可以直接使用函数名。
形参声明:小括号括起来的部分,是用于接收辅助性提示变量--形式参数的声明。
函数体:函数体是复合语句,仅在某个函数中使用的变量,原则上应该在函数中声明和使用。但要注意不能声明和形参同名的变量,否则会变量名冲突的错误。
函数调用(使用):
创建一个函数,求出两个整数相加的和!
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int num(int i, int m)
{
int z = 0;
z = i + m;
return z;
}
int main(void)
{
int a, b = 0;
printf("请输入两个整数:\n");
printf("整数1:"); scanf("%d", &a);
printf("整数2:"); scanf("%d", &b);
printf("两个整数相加的和是%d。", num(a, b));
return 0;
}
在这个程序中,定义了两个函数,一个是主函数(main)一个是求和函数(num)。虽然求和函数定义在main函数的前面,但是却没有先执行求和函数,而是执行了main函数,因为main函数是一个程序的主体,在所有函数中,都会第一时间从main函数执行。
而求和函数的执行流程解析:
函数调用的形式就是在函数名后面加上小括号。这个小括号就叫做(函数调用运算符)而函数表达式就叫做函数调用表达式,函数调用运算符中的括起来的就是实参,当实参不止一个的时候,就需要用逗号隔开。
进行函数调用以后,程序的流程会转到被调用的函数处,这时,传递过来的实参会被赋值给函数接受的形参!
形参的初始化结束以后,将执行函数体。程序遇到return语句的时候,或者执行到函数体最后的大括号的时候,就会从该函数转到调用函数。
写一个函数,求出三个整数中最大的一个数。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int max3(int i, int m, int e)
{
int max = i;
if (m > max)
{
max = m;
}
if (e >max)
{
max = e;
}
return max;
}
int main(void)
{
int a, b, c = 0;
printf("请输入三个整数:\n");
printf("整数1:"); scanf("%d", &a);
printf("整数2:"); scanf("%d", &b);
printf("整数3:"); scanf("%d", &c);
printf("最大的数是%d。", max3(a, b, c));
return 0;
}
将函数的返回值作为参数传递给函数;
输入两个整数,计算出他们的平方差并显示。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int pf(int a)
{
return a * a;
}
int ret(int i, int m)
{
return(i > m ? i - m : m - i);
}
int main(void)
{
int x = 0;
int y = 0; //我输入的两个整数
printf("请输入两个整数:\n");
printf("整数1:"); scanf("%d", &x);
printf("整数2:"); scanf("%d", &y);
pf(x); //计算平方的函数
pf(y);
ret(pf(x), pf(y));
printf("平方差是%d", ret(pf(x), pf(y)));
return 0;
}
分析:
分析之前,我们再回顾一下‘ ? :’ 条件操作符(三目操作符),其表达形式如下:
表达式1为真时,执行表达式2,否则执行表达式3。
这个代码我们定义了两个函数,分别是pf函数(计算平方的函数)和ret函数(比较两个整数的函数)。首先定义的第一个函数(pf函数)因为我们需要返回一个整形的值,所以返回类型一定是int,接着就是接收整形就平方,因为输入的整数,也是用int类型接收,最后直接返回就行了。第二个就是ret函数,这个函数比较奇怪的地方是它return后面的那个表达式,但是我们前面介绍过了这个操作符,但这个操作符放在ret函数里面的意义就是“较大的值减去较小的值”。这个就是平方差的方法!定义完成后,直接调用。
值传递;
创建一个计算幂的函数,如果n是整数,就计算出x是n的几次幂。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
double power(double x, int n)
{
int i = 1;
double tmp = 1.0;
for (i = 1; i <= n; i++)
{
tmp *= x;
}
return tmp;
}
int main(void)
{
double a = 0;
int b = 0;
printf("求出a的b次幂:\n");
printf("实数a:");
scanf("%lf", &a); //输入double类型的变量的时候,就不是%d了
printf("整数b:");
scanf("%d", &b);
//power(a, b); //创建一个求次幂的函数
printf("%.2f的%d次幂是%.2f.\n", a, b, power(a, b));
return 0;
}
如上述代码,形参x的值被赋值了实参a的值,形参n的值被赋值了实参b的值,像这样值来通过进行参数的机制称为值传递。
没有返回值的函数;
显示出一个直角在左下方的等腰直角三角形(函数)。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void put_staris(int n)
{
while (n-- > 0)
{
printf("*");
}
}
int main(void)
{
int i = 0;
int len = 0;
printf("生成一个直角三角形在左下方:\n");
printf("几边:");
scanf("%d", &len);
put_staris(i);
for (i = 1; i <= 5; i++)
{
put_staris(i);
putchar('\n');
}
return 0;
}
因为我们写的这个函数不需要返回结果,只需要显示,这个时候我们就可以使用void。
void就是“空”的意思,意思是没有。在c语言中,不论有没有返回值都同样作为函数,在其他的编程语言中。没有返回值会定义其他非函数的概念,例如子程序或者过程。
不含形参的整数;
输入一个正整数,并显示其倒转的值
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int scan_zfhanshu(void) //判断正负的函数 不需要接收,输入void
{
int tmp;
do
{
printf("请输入一个正整数:");
scanf("%d", &tmp);
if (tmp <= 0)
{
printf("请不要输入非正整数的数字。\n");
}
} while (tmp <= 0);
return tmp;
}
int ret_daozhuan(int num) //进行倒转的函数
{
int tmp = 0;
if (num > 0)
{
do
{
tmp = tmp * 10 + num % 10;
num /= 10;
} while (num > 0);
}
return tmp;
}
int main(void)
{
int i = scan_zfhanshu();
printf("该整倒转后的值是多少:%d", ret_daozhuan(i));
return 0;
}
分析:
因为在函数中就可以读取到键盘输入的整数并返回,所以就不需要接收形参了,因此在小括号中输入void。
在main函数中声明的i变量,其实是在scan—zfhanshu中输入的整数(程序执行时从键盘上输入非负的整数)。
作用域;
在这两个创建的函数中,都有一个相同标识符(名称)的变量tmp。但是他们两个却是各自独立的变量。
也就是说在函数scan_zfhanshu中的tmp变量是scan_zfhanshu中独有的一个变量。
在函数ret_daozhuan中的tmp变量是ret_daozhuan独有的一个变量,相互是不干预的。
赋给变量的标识符,它的名称都有一个通用的范围,称为作用域。
在程序块(复合语句)中声明的变量的名称,只在该程序块中调用,在其他区域无效,也就是说,变量的名称从变量声明的位置开始,到包含该声明的变量的程序块最后的大括号}为止这一区域都有用,这样的作用域称为块作用域。(参考下面图片)
文件作用域;
输入5名同学的分数,并求出最高分。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define number 5 //定义number为5
int tensu[number]; //定义一个数组为五个人 (创建数组的实体声明,定义)
int top(void); //定义一个判断最高分的函数
int main(void)
{
int i = 0;
extern int tensu[number]; //声明这个数组,并不是定义
printf("请输入这%d学生的分数:\n", number);
for (i = 0; i < number; i++)
{
printf("%d:", i + 1);
scanf("%d", &tensu[i]);
}
printf("最高分是:%d", top());
return 0;
}
int top(void)
{
extern int tensu[number];
int i = 0;
int max = tensu[0];
for (i = 1; i < number; i++)
{
if (tensu[i] > max)
{
max = tensu[i];
}
}
return max;
}
在函数的程序块中声明的变量等标识符是该程序块特有的部分。而想数组tensu这样,在函数外面声明的变量标识符,其名称的开始到程序的结尾都是通用的。
这样的作用域称为文件作用域。
声明和定义:
该程序中,创建了一个元素为5的数组。想这样创建的变量实体的声明称称为定义。
函数原型声明:
编译器在读取数据的时候,也是按照从头到尾的顺序依次解读的。因为上述程序中,top函数定义在main函数后面的,所以想要在main函数中调用top函数我们就一定要声明!
像:
明确了记述了函数的返回类型,以及形参的类型和个数的声明称为函数原型声明。
需要注意的是,这种声明需要分号结尾。
函数原型定义只是声明了函数的返回值和形参等相关信息,并没有定义函数的实体。函数定义和函数原型声明不同之处如下所示:
如果函数top函数的需求发生了改变,那么定义函数和函数原型声明两部分都必须进行修改。但是如果top函数定义放在了main函数前面,就不用特意使用函数原型声明了。
数组的传递;
写一个程序,计算出英语和数学的最高分数
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define NUMBER 5
int max_js(int v[], int n) //
{
int i = 0;
int max = v[i];
for (i = 1; i < n; i++)
{
if (v[i] > max)\
{
max = v[i];
}
}
return max;
}
int main(void)
{
int i = 0;
int mat[NUMBER] = { 0 }; //数学分数
int eng[NUMBER] = { 0 }; //英语分数
int max_m = 0; //数学最高分
int max_e = 0; //英语最高分
printf("输入%d同学的分数:\n",NUMBER);
for (i = 0; i < NUMBER; i++)
{
printf("[%d]英语:", i + 1);
scanf("%d", &eng[i]);
printf(" 数学:");
scanf("%d", &mat[i]);
}
int max_js(); //创建一个计算最高分的函数
max_e = max_js(eng, NUMBER); //英语最高分
max_m = max_js(mat, NUMBER); //数学最高分
printf("英语最高分数=%d\n", max_e);
printf("数学最高分数=%d\n", max_m);
return 0;
}
创建的max_js的作用就是:找出包含任意个元素的int类型数组中的最大值,然后返回该值。
该数组接收的形参的声明就是“类型名 参数名[ ]” ,这样的n就是接收元素的个数。
函数的传递和const类型修饰符;
就数组全部设置为0
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void print_arr(const int v[], int n)
{
int i = 0;
printf("{");
for (i = 0; i < n; i++)
{
printf("%d ", v[i]);
}
printf("}");
}
void print_zero(int v[], int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
v[i] = 0;
}
}
int main(void)
{
int arr1[] = { 1, 2, 3, 4, 5 };
int arr2[] = { 3, 2, 1 };
printf("arr1="); print_arr(arr1, 5);
putchar('\n');
printf("arr2="); print_arr(arr2, 3);
putchar('\n');
print_zero(arr1, 5);
print_zero(arr2, 3);
printf("把0赋值给所有元素。\n");
printf("arr1="); print_arr(arr1, 5);
putchar('\n');
printf("arr2="); print_arr(arr2, 3);
putchar('\n');
return 0;
}
const:当我们希望变量不被改变的时候,我们就可以在前面使用const的类型修饰符,简而言之就是在变量面前加上const这个值就不会被修改。、
由于我们在printf_arr这个函数中使用了const类型修饰符,因此在函数中就不能在修改数组v的元素值了。
注意:
如果只是引用所接受的数组元素值,而不改写的话,在声明接受数组的形参时候就应该加上const。这样函数调用就可以安心的调用函数了。
线性查找;
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define NUMBER 5 //定义数组元素个数
#define FAILEAD -1 //查找失败
int search(const int v[], int key, int n) //分别代表的是:输入元素的值不能改变,查找的元素,接收元素的个数
{
int i = 0;
while (1)
{
if (i == n)
{
return FAILEAD;
}
if (v[i] == key)
{
return i;
}
i++;
}
}
int main(void)
{
int i = 0;
int ky = 0; //我要查找的值
int idx = 0;
int vx[NUMBER] = { 0 };
for (i = 0; i < NUMBER; i++)
{
printf("vx[%d]", i + 1);
scanf("%d", &vx[i]);
}
printf("要查找的值:");
scanf("%d", &ky);
idx = search(vx, ky, NUMBER); //分别代表的是元素的值。要查找元素的值,和数组元素的个数
if (idx == FAILEAD)
{
puts("查找失败。");
}
else
{
printf("%d是数组的第%d元素。\n", ky, idx + 1);
}
return 0;
}
函数search是从元素个数为5的int 类型数组v中依次查找与key相同的值,而这个key就是我们输入的ky的值。如果有相同的值,则返回数组元素的下标,如果没有则返回FAILERA,也就是-1。
函数search中的while语句表达式中的“1”,因此只有在执行return语句中才能跳出循环,否则将永远执行下去。
像这样,从数组开头顺次搜索,找出与目标相同的元素一系列操作,称为线性查找或者叫顺序查找。
总结;
1.函数体是复合语句(程序块)。如果仅有函数中使用变量,原则上应该在函数中声明和使用。
2.函数调用的形式是在函数名后面加上小括号。这个小括号称为函数调用运算符。如果没有实参,则小括号中为空。有多个实参的情况下,用逗号隔开。
3.创建变量或者函数实体的声明称为定义声明,否则为非定义声明。
4.在函数中执行return语句的时候,或函数执行结束的时候,程序流就会返回到原来进行调用的地方。如果函数放返回类型不是void类型,则返回到原来调用的地方时,会返回到单一的值。
5.在函数外定义的变量,拥有文件作用域;在函数内定义的变量拥有块作用域;
6.对函数调用表达式进行判断,会得到函数返回的值。
到此函数的内容就已经结束了!