一、函数基础
1.函数定义
/函数定义/
/*[存储类] <返回值类型> <函数名>(形参列表) */
int add(int a, int b)//函数头
{//函数体
int s = a + b;
//return语句后面跟的值必须在类型上与函数返回值类型保持一致
return s;
}
2.函数声明
/函数声明/
int add(int a, float b);//函数声明是一条语句,要以分号结束
// int add(int, int);//函数声明语句,可以不加形参名
// int add(a, b);//错误:声明语句必须指明参数类型
// int add(float b, int a);//错误:形参的顺序必须和定义保持一致
// int add(int x, float y);//正确
// int add(int, int, int);//错误
函数声明语句,返回值类型必须和函数定义的时候保持一致,参数列表在类型、顺序和个数上必须和函数定义保持一致(形参名可以有,可以没有,也可以和函数定义的时候形参名不一样)
3.函数调用
int n = add(10, 20.0);
函数调用的时候,实参在个数、类型、顺序上必须和函数声明与函数定义保持一致,实参可以是常量、变量、表达式、函数调用,实参的名字和形参的名字没有联系。对于函数的返回值而言,我们可以不管。
练习1:
编写一个函数,接受一个字符,和两个整型作为其参数。第一个整型参数说明了在每行中该字符输出的个数,而第二个整型参数指的是需要输出的行数,比如要打印一个3行5列的星号,可以这么调用:f(‘*’, 5, 3)。编写一个调用该函数的程序。
练习2:输入两个整型数据,设计一个函数,通过调用这个函数,实现两个数值的交换,调用完成后打印出交换的结果。
a = 10 , b = 20
f()
prinft a 20, b 10
#include <stdio.h>
void swap(int *a, int *b);
int main(int argc, char const *argv[])
{
int a, b;
scanf("%d%d", &a, &b);
printf(“交换前: a = %d, b = %d\n”, a, b);
swap(&a, &b);
printf(“交换后: a = %d, b = %d\n”, a, b);
c = 100;
int c;
return 0;
}
void swap(int *x, int *y)
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
printf(“swap内: *x = %d, *y = %d\n”, *x, *y);
}
二、函数调用的内存逻辑
三、函数的形参和实参
1.形参只在函数调用的时候,才会被分配内存,函数退出,形参会被释放掉。形参只在函数体内有效。
2.实参可以是常量、变量、表达式、函数调用,在调用的时候,必须确定
3.形参和实参在函数调用过程中,值的传递是单向的
在函数调用的开始,实参要给形参做初始化;但是函数退出的时候,这个形参的值不会反过来给实参重新赋值。
4.实参和形参在名字上没有任何关联。因为两者在内存中不同作用域的位置,互不冲突。
四、变量作用域
1.作用域:就是变量在哪个范围内有效(从变量的定义位置开始)
2.局部变量:函数体内定义的变量,它的作用域就在函数内部,在函数外不能使用。
(形参也是一种局部变量)
3.全局变量:在当前代码文件中,所有函数以外定义的变量,它的作用域就是整个文件
4.代码块:符号{}括起来的部分就是一个代码块。
代码块作用域:在代码块里面定义的变量,它的作用域就在代码块里面,在当前代码块外面不能使用。
【在代码中某个位置访问某个变量,优先从当前代码块或作用域去访问,如果当前代码块或作用域找不到这个变量,扩大范围再寻找】
五、递归思想和递归函数
1.递归思想:一个过程或者函数在定义或声明中有自己调用自己的一种方法。
【函数是可以嵌套调用】
2.递归的条件
(1)子问题与原问题要处理的事情是一样的,并且越简单
(2)问题是有穷的,不能无限制重复调用本身
3.怎么设计一个递归算法?
(1)确定问题变量
(2)确定递归公式(怎么用代码实现大问题化简为小问题)
(3)确定边界条件
练习:汉诺塔问题
有三个柱子A, B, C表示,输入n值,表示圆盘的数量,这些圆盘原来放在A柱子上并且从下到上由大到小摆放。设计一个代码:实现将所有圆盘从A柱子上移动到B柱子上,要求每次只能移动一个盘子,并且圆盘的摆放必须满足从下到上由大到小摆放。打印出总的移动次数和每一次移动的过程
n=1 1次: A -> B
n=2 3次: A -> C
A -> B
C -> B
#include <stdio.h>
int i = 0;
void hanoi(int n, char from, char to, char tmp)
{
if (n == 1)
{
printf(“第%d次移动:%c -> %c\n”, ++i, from, to);
return;
}
hanoi(n-1, from, tmp, to);
printf(“第%d次移动:%c -> %c\n”, ++i, from, to);
hanoi(n-1, tmp, to, from);
return;
}
int main(int argc, char const *argv[])
{
int n;
scanf("%d", &n);
if (n < 1)
{
printf(“输入错误,请输入一个大于0的整数\n”);
return -1;
}
hanoi(n, 'A', 'B', 'C');
printf("总共移动%d次\n", i);
return 0;
}
六、回调函数
回调的机制就是通过函数指针来找到回调函数执行的位置的
七、变参函数
double sumup(const char *format, …);
八、内联函数
要求:
(1)函数代码简短
(2)函数被频繁调用
九、printf函数的使用
(1)格式控制符
https://www.cnblogs.com/HackHarry/p/8320825.html
(2)printf打印属性
http://blog.chinaunix.net/uid-28458801-id-4581042.html