文章目录
前言
记录编程语言——c语言的学习过程,基础篇——c语言“组件”:函数
一、函数是什么
自我理解:一段代码(分程序),函数体包含处理问题的过程,调用只需输入参数,输出结果,利于程序模块化设计
二、函数的声明、定义、调用
准则:C语言中的实体(函数、变量等)必须先声明、后定义、再调用
常用格式
1、函数声明放在文件开头(主函数之前),函数定义在主函数之后;
次用格式(不常用)
1、函数声明在主函数内,在调用之前,函数定义在主函数之后;
2、函数定义在主函数之前,在主函数内调用。
鸡肋格式
函数定义在前,声明在后。
错误格式
函数定义在主函数之后,调用前未声明。
(一)函数声明一般格式:
注:合法调用的前提:
- 对库函数,需包含库函数对应的头文件,即 .h 文件;
- 对自定义函数,源程序中需有函数声明。
(二)函数的定义
完成函数体的代码实现
一般格式:
(三)函数的调用
根据给定的实参执行函数体并返回执行结果。
1、一般格式:
注意:
- 函数执行结果可用函数名返回,也可用参数返回;
- 函数调用可以是独立语句,也可以是表达式(以值的形式输出)
- 参数返回,使用方式为:指针或引用(C++)
2、调用方式——传值调用、传地址调用、引用调用(c++)
①传值调用
形参(虚):函数定义首行括号内的参数表。
例(类型1 参数1,类型2 参数2 …类型n 参数n);
实参:调用时赋值给形参。
虚实结合的传值调用过程:
1、调用执行时为形参分配空间;
2、将实参的值 以复制(拷副本)的形式传给形参;
3、使用形参在函数体内进行计算;
4、调用返回时将形参空间释放。
虚实结合传值调用特点:——用时分配,不用释放
形参与实参占用不同内存空间,单向传递,且调用结束时,形参空间被释放,即形参的值发生改变时不会影响到实参。
②传地址(值)调用
主调函数中的实参一定是通过复制实参的值传递到函数形参
传地址调用:传的是实参存储的地址值;
适用于多参数返回值的情形;
指针(地址)型形参(虚):类型为指针(地址)的虚拟参数;
指针(地址)型实参:类型为指针(地址)的实参。
传递过程:
1、执行时为形参分配空间;
2、将地址型值复制到形参空间;
3、函数体内用地址值访问对象实体;
4、返回时释放地址型形参空间。
特点:
- 传递的是实体(变量等)地址
- 函数体内通过形参实际调用外部实体,从而改变实参的值,双向传递
- 返回时,形参空间释放,所指对象的值被保留。
实例:
#include<stdio.h>
void swap(int *p1,int *p2) //形参表
{
int p; //借用中间变量交换过程
p=*p1;
*p1=*p2;
*p2=p;
}
int main(void)
{
int x,y; //实参
scanf("%d,%d",&x,&y);
printf("x=%d,y=%d\n",x,y);
printf("swapped:\n");
swap(&x,&y); //传地址值
printf("x=%d,y=%d\n",x,y);
return 0;
}
③引用调用(c++内容)
引用:被引用对象的别名,能够被编译器逆向引用的常量型指针。
常用于函数参数表、函数返回值的传递,也可独立使用。
基本规则:
1、引用被创建时,必须被初始化为指向一个存在的实体;
2、一旦一个引用被指向一个实体,就不能被改变指向另一个实体;(唯一性)
3、不能有NULL(空)引用
引用型形参:类型为引用(常量型指针)的虚拟参数
实参:实际参数
传递过程:
1、执行时为形参分配空间;
2、实参传递到引用型形参,进行别名(指向实参);
3、函数体内用形参引用实参值;
4、返回时释放引用型形参空间。
实例:别名型引用参数(a,b是实参x,y的别名)
#include<stdio.h>
void swap(int &a,int &b) //别名型形参
{
int t; //借用中间变量交换过程
t=a;
a=b;
b=t;
}
int main(void)
{
int x,y; //实参
scanf("%d,%d",&x,&y);
printf("x=%d,y=%d\n",x,y);
printf("swapped:\n");
swap(x,y); //别名引用方式
printf("x=%d,y=%d\n",x,y);
return 0;
}
三、函数的嵌套与递归
(一)嵌套调用
函数定义时不可嵌套,调用时可以嵌套。
(二)递归调用
自己调用自己,两种方式:直接、间接递归调用
①直接递归
②间接递归
注:对函数递归调用层数没有限制,但递归次数过多,空间浪费很大,程序运行缓慢,且容易引起堆栈溢出。
实例1:递归求n!
#include<stdio.h>
int fact(int num)
{
if(num<=1)
return 1;
else return num*fact(num-1); //直接递归调用
}
int main()
{
int n,nSum; //nSum=n!
printf("please input a number:");
scanf("%d",&n);
if(n>0)
{
nSum=fact(n);
printf("The %d!=%d\n",n,nSum);
}
else
printf("n 必须大于0!\n");
return 0;
}
思考方法:
1)寻找基本项
2)x归纳项
实例2 求解Hanoi塔问题
程序代码:
#include<stdio.h>
#include<stdlib.h>
void dsk_move(int n,char cA,char cB); //将杆A上的盘n移到杆B
void hanoi(int n,char cA,char cC,char cB); //将杆A上n张盘通过杆B移到杆C
int main()
{
int num; //待移动的盘
printf("请输入要移动的盘的张数:");
scanf("%d",&num);
hanoi(num,'A','C','B');
system("pause");
return 0;
}
void dsk_move(int n,char cA,char cB)
{
printf("从%c到%c移动盘%d\n",cA,cB,n);
}
void hanoi(int n,char cA,char cC,char cB)
{
if(n>0)
{
hanoi(n-1,cA,cB,cC); //将杆A上的n-1张盘通过杆C移动到杆B
dsk_move(n,cA,cC); //将杆A上盘n直接移到杆C
hanoi(n-1,cB,cC,cA); //将杆B上的n-1张通过杆A移动到杆C
}
}
运行结果:
总结
文章参考了程序设计基础教程——C语言版(冯山/主编)科学出版社及其视频教程
本文主要为C语言学习笔记,若出现错误,请谅解,欢迎大佬们指正~