一、函数
1、函数初识
- 例:打印一段话
# include <stdio.h> void hello(); //函数声明 void hello() //函数定义 { printf("你好哇,nice to meet you"); } int main(){ hello(); //函数调用 return 0; }
输出结果为:
你好哇,nice to meet you
①、函数声明
有时候,函数声明也可以省略(子函数放在主函数前面的时候)
但在初学阶段,为了养成良好的习惯,建议写上函数声明。
②、函数定义
- 基本框架如下:
类型名 函数名(参数列表) //参数列表可以空,但是()不能省 { 函数体 }
2、函数的参数和输出值
- 例:编写一个函数sum,由用户输入参数n
,计算1+2+…+(n-1)+n的结果并返回
。
# include <stdio.h> int sum(int n); //函数声明 int sum(int n) //函数定义 { int result = 0; for(;n>0;n--) //经典的用一个循环进行求和 { result += n; } return result; } int main(){ int n,result; printf("请输入您想输入的数字:"); scanf("%d", &n); result = sum(n); //函数调用 printf("求和结果为:%d", result); return 0; }
输出为:
请输入您想输入的数字:10 求和结果为:55
值得一提的是:函数遇到return 就会立即返回值。
比如说,利用if条件语句的时候,有两个return,是有两个返回值吗?不是的,只有一个!
- 例:编写一个函数max,接受两个
整型参数
,并返回
它们中较大的值。
# include <stdio.h> int max(int x, int y); //函数声明 int max(int x, int y) //函数定义 { if (x > y) //条件语句比较大小 { return x; } else { return y; } } int main(){ int a, b, c; printf("请输入你想比较的两个数:"); scanf("%d %d", &a, &b); c = max(a, b); printf("这两个数中较大的那个是:%d", c); return 0; }
子函数(max函数)和主函数(main函数)中的参数名是不冲突的,可以一样,也可以不一样。
3、指针函数
函数也可以返回指针类型的数据
- 例:根据输入的字母返回不同的值
# include <stdio.h> char *getword(char); char *getword(char c) { if (c == 'A'){ //这里的if语句也可以写成switch语句 return "Apple"; } else if (c == 'D'){ return "Dog"; } else{ return "None"; } } int main(){ char input; printf("请输入一个字母:"); scanf("%c", &input); printf("输出结果为:%s\n", getword(input)); return 0; }
值得注意的是:不要返回局部变量的指针
- 例:将上述例子加以修改
# include <stdio.h> char *getword(char); char *getword(char c) { char str1[] = "Apple"; char str2[] = "Dog"; if (c == 'A'){ return str1; //返回局部变量 } else if (c == 'D'){ return str2; } else{ return "None"; } } int main(){ char input; printf("请输入一个字母:"); scanf("%c", &input); printf("输出结果为:%s\n", getword(input)); return 0; }
编译会报warring:
[Warning] function returns address of local variable [-Wreturn-local-addr]
运行结果如下:
请输入一个字母:A 输出结果为:P
因此,返回局部变量的指针是不可取的
4、函数指针
像数组指针一样,它是一个指针。
# include <stdio.h> int sum(int); int sum(int num){ return num + num; } int main(){ int num; int (*fs)(int); //函数指针 printf("请输入一个数字:"); scanf("%d", &num); fs = sum; //函数名就是函数的地址 printf("%d + %d = %d\n", num, num, (*fs)(num)); return 0; }
二、全局变量和局部变量
1、局部变量
在函数里边定义的变量
2、全局变量
在函数外边定义的变量
Q:哪些情况下,会使用全局变量呢?
A:当一个程序中,多个函数都需要使用一个变量,那么就会用到全局变量
全局变量的一些特点:
- ①、如果不对全局变量进行初始化,那么它会初始化为0。
- ②、如果在函数的内部存在一个与全局变量同名的局部变量,那么在这个函数中,全局变量不起作用。
- 例:
# include <stdio.h> void func(); int a, b = 110; // 定义全局变量a,b 其中a=0,b=110 void func() { int b; //定义局部变量b a = 119; b = 120; //对a,b进行赋值 printf("在func中的值,a = %d, b = %d\n", a, b) ; } int main(){ printf("在main中的值,a = %d, b = %d\n", a, b); func(); printf("func函数处理后,在main中的值,a = %d, b = %d\n", a, b); return 0; }
运行结果:
在main中的值,a = 0, b = 110 在func中的值,a = 119, b = 120 func函数处理后,在main中的值,a = 119, b = 110
简单分析一下:
首先,定义了全局变量a=0,b=110,所以在第一次打印的时候,结果是不变的;第二次打印,是作用在func函数中,此时定义了一个局部变量b,并对a=119,b=120进行分开赋值,打印结果应该是赋值后的值;第三次打印,是在main函数中,由于a是全局变量,func对其影响是有的,所以a=119继续保持,而b在func中变成了局部变量,赋值仅仅作用在func函数中,到了main函数,又变回110。
全局变量不建议大量使用,原因:
- ①、使用全局比那辆会使程序占用更多的内存
- ②、污染命名空间,降低程序可读性
- ③、提高了程序的耦合性,当代码体比较长了之后,时间再久一点,自己会忘记全局变量受到哪些函数的影响了。
三、作用域
- 当变量被定义在程序的不同位置时,它的作用范围时不一样的,这个作用范围就是作用域。
- C语言编译器可以确认的4种不同的作用域
①、代码块作用域
②、文件作用域
③、原型作用域
④、函数作用域
四、链接属性
- external(外部的)
多个文件中声明的同名标识符表示同一个实体
- internal(内部的)
单个文件中声明的同名标志符表示同一个实体
- none(无)
声明的同名标识符被当作独立不同的实体
- 注意:
只有具备文件作用域的标识符才能拥有external或internal的链接属性,其他作用域的标识符都是none属性。
默认情况下,具备文件作用域的标识符拥有external属性。也就是说该标识符允许跨文件访问。对于external属性的标识符,无论在不同文件中声明多少次,表示的都是同一个实体。
默认情况下,具备文件作用域的标识符拥有external属性。也就是说该标识符允许跨文件访问。对于external属性的标识符,无论在不同文件中声明多少次,表示的都是同一个实体。
使用static关键字可以使得原先拥有external属性
的标识符变为internal属性
。有两点需要注意:
①、使用static关键字修改链接属性,支队具有文件作用域的标识符生效(对于拥有其他作用域的标识符时另一种功能)
②、链接属性只能修改一次,也就是说一旦将标识符的链接属性变为internal,就无法变为external。
五、生存期
C语言的变量拥有两种生存期:
- 静态存储期
具有文件作用域的变量属于静态存储期,函数也属于静态存储期。属于静态存储期的变量在程序执行期间将一致占据存储空间,知道程序关闭才释放。
- 自动存储期
具有代码块作用域的变量一般情况下属于自动存储期。属于自动存储期的变量在代码块结束时将自动释放存储空间。
六、存储类型
C语言提供了五种不同的存储类型。
- 自动变量(auto)
在代码块中声明的变量默认的存储类型就是自动变量,使用关键字auto来描述。
- 寄存器变量(register)
将一个变量声明为寄存器变量,那么该变量就有可能被存放于寄存器中。
寄存器变量和自动变量在很多方面是一样的,它们都拥有代码块作用域,自动存储期和空连接属性。
将变量声明为寄存器变量,那么就没办法通过取址运算符获得该变量的地址。
- 静态局部变量(static)
使用static来声明局部变量,那么就可以将局部变量指定为静态局部变量。
static的局部变量具有静态存储期,所以它的生存期与全局变量一样,直到程序结束才释放。
- 外部变量(extern)
extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。
也就是说,extern关键字是用于告诉编译器这个变量或函数在别的地方已经定义过了,不要急着报错
- typedef