概念
将实现某些功能的代码封装成代码块,想使用这个功能的时候,通过代码块的名字就可以调用,就无须写重复的代码了。这个代码块就叫做函数,代码块的名字就叫做函数名。
函数的定义,调用,声明等
2.1函数的定义
定义函数的格式:返回值类型 函数名(函数的参数列表){
函数体; //也就是要实现功能的代码块
}
函数名:也是一个标识符,要符合标识符的命名规范。
例:
int print_menu(void){
函数体;
return 0;
}
(1)int 是函数的返回值类型,如果没有返回值,可以写成 void 但是不能不写;
(2)print_menu 是函数名是一个标识符,要符合命名规范;
(3)() 里面是函数的参数列表,如果没有可以空着,或者写void 括号必须写;
(4){} 里面是函数体,也就是用来实现功能的代码块;
(5)return 表示返回函数运行的结果,如果没有返回值,可以不写,或者写 return;如果有返回值 return后面既可以是常量,也可以是变量,也可以是表达式但是要注意,类型必须和函数名前面的类型保持一致;
(6)函数一旦定义好之后,就可以在其他函数中调用了;
(7)函数如果不被调用,里面的代码是不会执行的。
2.2函数的调用
通过函数名即可调用函数 ()里面是要给函数串的参数,如果没有参数,可以不写,但是()必须写,当程序执行到调用函数的语句时,就会跳转到函数内部执行,执行完之后回到调用位置继续向下执行,下次再使用函数的功能时,直接通过函数名再次调用即可。
2.3 函数的声明
如果把所有函数都定义在main函数的前面,在main函数中调用是没有问题的,但是函数之间相互调用,就可能出现不认识的情况,这时候,就需要用到函数的声明了。
2.4 函数的参数
在函数实现功能的过程中,有些值,函数里面没有,这时,就需要调用者,在调用函数的时候,以参数的形式将这些值传递给函数。
(1)有参数的函数调用,调用函数的时候 ()里面的叫做函数的实际参数,简称:实参;
要注意,实参的个数和类型,要和形参保持一致
(2)定义函数时 ()里面的叫做函数的形式参数,简称:形参;
(3)形参只是告诉调用者,调用这个函数的时候,需要几个什么类型的函数;
(4)在调用函数的时候,操作系统会给形参分配空间,然后用实参来初始化形参,相当于隐藏了几句定义的代码;
(5)形参只能在函数里面使用,在函数调用结束的时候,形参占用的内存空间就被操作系统回收了。
2.5 函数的返回值
函数执行的结果,有时需要供后面使用,而不是直接输出到终端,这时就需要函数返回执行的结果了;如果需要返回值,就写,如果不需要,可以不写。
例:计算两个整数的和并返回计算的结果
int my_add(int x, int y){
int sum = x+y;
return sum;//注意类型要和函数名前面的类型一致
printf("hello world\n");//函数中遇到return之后后面的代码就都不执行了
}
int main(int argc, const char *argv[])
{
int a = 10;
int b = 20;
int ret = 0;//定义一个变量来接收函数执行的结果
ret = my_add(a, b);
printf("ret = %d\n", ret);//30
//有返回值的函数也不是接收返回值
//函数也会被调用 只不过没有现象了
my_add(100, 200);
return 0;
}
全局和局部变量
分类标准
作用域:在哪个范围内可以访问;
生命周期:何时被创建,何时被回收;
全局变量:
没有被任何 {} 扩住的变量 就叫做全局变量;
作用域: 整个文件;
生命周期: 在main函数执行之前就已经被分配好了,直到整个程序结束,才被回收;
局部变量:
被任何{} 扩住的变量 都叫做局部变量;
作用域:最近的{};
生命周期:定义时被创建 最近的{}结束时,被回收;
全局变量和局部变量重名时,访问采用局部优先原则。
函数的传参方式
4.1全局传参
不常用,了解即可。
4.2复制传参(值传递)
是将实参的值复制了一份,传给了形参,在函数内部,不管如何修改形参,实参都不会发生变化,因为实参和形参不在同一块内存空间上。即使形参和实参重名了 也没问题 因为不在同一个作用域,不管对形参如何修改实参都不会变化。
4.3地址传参(地址传递)
实现不了将 a+b 的值放在c中的功能
int my_add_1(int x, int y, int z){
z = x+y;
printf("z = %d\n", z); //30
}
//x和y的传参方式是值传递,z的传参方式是地址传递
//当函数中需要修改实参的值时,就应该把实参的地址传过来
例:
int my_add_2(int x, int y, int *z){
*z = x+y;
}
int main(int argc, const char *argv[])
{
int a = 10;
int b = 20;
int c = 0;
my_add_1(a, b, c);
printf("1111:c = %d\n", c); //0
my_add_2(a, b, &c);
printf("2222:c = %d\n", c); //30
return 0;
}
形参是一级指针,也不一定是地址传递,也有可能是一级指针的值传递。
my_chage_1(p);//指针的值传递
my_chage_2(&p);//指针的地址传递
一维数组的传参方式
5.1 字符串的传参方式
字符串传参:只传首地址即可,因为每个字符串结尾都有'\0'作为标识。
5.2 整型数组传参方式
整型数组传参时:既要传数组的首地址,还要传数组的长度,因为整型数组是没有 '\0' 作为结束标志的。
最常用的写法: void print_arr(int *p, int len)
也可以用下面的两种写法,下面的两种写法叫做 代码的自注释。这两种写法 p 的本质也是指针:
void print_arr(int p[100], int len)
void print_arr(int p[], int len)
5.3二维数组的传参方式
二维数组传参时:要用数组指针作为形参.
例:
void print_arr(int (*p)[4], int row, int column)
int s[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
print_arr(s, 3, 4);
main函数的参数