C语言入门学习(第二十二天——函数)
作者:互联网
镇楼图
Pixiv:よはく
============
〇、引入函数的原因
当程序规模不断扩大时,主函数会变得冗杂、复杂、难阅读、关联度过高、难修改等问题,这时候引入【函数】来分解程序,提高可读性、效率是非常有必要的。
其他程序员在使用你的函数时只需要了解作用、参数、返回即可。
============
一、函数
①声明函数
编译会从上往下编译,而如果你调用的语句在上面定义函数在下面,则会报错。于是你需要提前声明函数防止报错,告诉编译器“确实有这个函数,只是你还没看到。”
一般声明语句会写在最上面
<类型名> <函数名>(参数列表)
//若不存在返回值,参数最好写void
//声明函数可以只写类型
void test();
int main(){
test();
}
void test(){
printf("HelloWorld");
}
②定义函数
<类型名> <函数名>(参数列表){
<函数体>
}
③调用函数
根据你写的函数按照定义来调用
//声明函数
void print_C();
//定义函数
void print_C(){
printf(" ###### \n");
printf("## ##\n");
printf("## \n");
printf("## \n");
printf("## \n");
printf("## ##\n");
printf(" ###### \n");
}
int main()
{
//调用函数
print_C();
return 0;
}
============
二、extern关键字
extern关键字用于声明全局变量
和声明函数类似,防止报错
int main(){
extern int a;
printf("%d\n\a",a);
}
int a = 3;
============
三、作用域
变量被定义到不同位置时,所作用的范围称为作用域。
①代码块作用域block scope
一个代码块{}中定义的变量只能在这代码块中使用
作用域不同的变量允许名字一致
作用域在调用同名变量时会优先考虑这个代码块所在的变量
比如
/*
for、if、switch、函数中定义的变量
也不可在这些代码块以外使用
*/
int main(){
int a = 2;
{
{
int a = 52;
printf("%d\n",a);
}
printf("%d\n",a);
int a = 3;
{
int a=1;
printf("%d\n",a);
}
printf("%d\n",a);
}
printf("%d\n",a);
}
②文件作用域
在代码块之外的变量、数组、函数等能在这整个文件中使用,则称为具有文件作用域
具有文件作用域的称为全局变量
注:应尽量避免使用全局变量以节省内存、防止污染命名空间、降低程序耦合性。一个好的程序应该要高内聚、低耦合
③原型作用域
声明函数中对于声明的参数的作用域仅限这一行代码。
所以声明时可以不写参数名,参数名也可以不同于原型的参数名
【没什么用】
void f(int,int diff);
void f(int a,int b){
//...
}
④函数作用域
函数在调用时会产生的作用域,goto语句的标签会被限制在函数内,当函数调用完成后会销毁这个作用域
============
四、定义与声明
定义:
定义是指为某一个对象分配存储空间
声明:
声明是指向编译器表明存在这个变量
定义也可以当作是声明
相同名字只能定义一次,而可以声明多次
============
五、指针参数
函数由参数、返回值、函数体构成
以交换变量的函数为例
void swap(int,int);
void swap(int x,int y){
int t;
printf("In swap,互换前:x = %d,y = %d\n",x,y);
t = x;
x = y;
y = t;
printf("In swap,互换后:x = %d,y = %d\n",x,y);
}
int main(){
int x = 3,y = 5;
printf("In main,互换后:x = %d,y = %d\n",x,y);
swap(x,y);
printf("In main,互换后:x = %d,y = %d\n",x,y);
}
由上面的结果来看,是不符合我们的预期的。
原因在于我们函数内的变量是局部变量无法改变值,需要引入指针或全局变量来达到预期目的
现在再来改一下代码
void swap(int*,int*);
void swap(int *x,int *y){
int t;
printf("In swap,互换前:x = %d,y = %d\n",*x,*y);
t = *x;
*x = *y;
*y = t;
printf("In swap,互换后:x = %d,y = %d\n",*x,*y);
}
int main(){
int x = 3,y = 5;
printf("In main,互换后:x = %d,y = %d\n",x,y);
swap(&x,&y);
printf("In main,互换后:x = %d,y = %d\n",x,y);
}
============
六、传递数组
数组在函数中传递的是首元素的指针,所以即使在函数内改变数组的值,也会改变main中数组的值
数组只有第一维可以省略数量
void get_array(int a[5]);
void get_array(int a[]){
int i;
a[3] = 520;
for (i = 0;i<10;i++){
printf("a[%d] = %d\n",i,a[i]);
}
}
int main(){
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int i;
get_array(a);
printf("\n=========\n");
for (i = 0;i<10;i++){
printf("a[%d] = %d\n",i,a[i]);
}
return 0;
}
===========
七、指针函数
函数返回类型为指针的函数称为指针函数
char *cstrcat(char*,const char*);
char *cstrcat(char* a,const char* b){
char* r = strcat(a,b);
return r;
}
int main(){
char a[30] = "123456",b[] = "abcdef";
cstrcat(a,b);
printf("%s",a);
return 0;
}
和之前的知识多少有些重复,比较简单,但需要注意一个点!
不要返回局部变量的指针
根据作用域我们可以得知,定义指针的变量是一个在函数作用域内的变量。
当你返回指针后这个变量也同时被销毁,而返回到的指针因为原本指向的内容也被销毁自然会有八嘎(bug)
以下这段代码明显会出错
(编译器只会警告,不确定你是要这个指针的返回值还是所指向的内容)
char *cstrcat(void);
char *cstrcat(void){
char str[10] = "ABCDEFG";
return str;
}
int main(){
printf("%s",cstrcat());
return 0;
}
============
八、函数指针
int (*p)(int,int)
这是不是感觉和数组指针很像呢?本质上就是优先级的不同而导致的不同的结果。
那么函数指针有什么作用呢?
函数在定义后会存在一个地址,这个地址称为【入口地址】,而这个地址的值就是函数名。
现在你多了一种方式去调用函数
int square(int);
int square(int num){
return num*num;
}
int main(){
int num;
scanf("%d",&num);
int (*p)(int) = square;
printf("%d",(*p)(num));
}
============
九、return
return关键字用来返回函数的值并结束本次函数的调用
只能返回一个值
============
总结
现在可以使用函数去简化main函数,参数可以用变量、指针、数组,返回值可以是变量、常量、指针,调用方式也可以使用指针来调用.
另外可以看看stdarg.h
还可以看看如何用函数传递函数
这个模块能较弱地实现一个函数带可变数量的参数
参考资料
https://fishc.com.cn
http://www.cplusplus.com/reference
https://www.icourse163.org/course/ZJU-200001
http://c.biancheng.net/
标签:第二十二,函数,int,void,C语言,作用域,printf,main,入门 来源: https://www.cnblogs.com/AlienfronNova/p/14454208.html