跳过正文
  1. 文章/
  2. C/
  3. C语言基础/

7、函数和作用域

·3232 字·7 分钟· loading · loading · ·
C C语言基础
GradyYoung
作者
GradyYoung
C语言基础 - 点击查看当前系列文章
§ 7、函数和作用域 「 当前文章 」

函数
#

函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。

您可以把代码划分到不同的函数中。如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根据每个函数执行一个特定的任务来进行的。

函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。

C 标准库提供了大量的程序可以调用的内置函数。例如,函数 strcat() 用来连接两个字符串,函数 memcpy() 用来复制内存到另一个位置。

函数还有很多叫法,比如方法、子例程或程序,等等。

库函数和自定义函数
#

C语言在发布时已经为我们封装好了很多函数,它们被分门别类地放到了不同的头文件中(暂时先这样认为),使用函数时引入对应的头文件即可。这些函数都是专家编写的,执行效率极高,并且考虑到了各种边界情况。

C语言自带的函数称为库函数(Library Function)。库(Library)是编程中的一个基本概念,可以简单地认为它是一系列函数的集合,在磁盘上往往是一个文件夹。C语言自带的库称为标准库(Sdandard Library),其他公司或个人开发的库称为第三方库(Third-Party Library)。

库函数
#

标准C语言(ANSI C)共定义了15 个头文件,称为“C标准库”,所有的编译器都必须支持,如何正确并熟练的使用这些标准库,可以反映出一个程序员的水平。

可根据需要查阅C语言函数手册,网址是http://www.cplusplus.com/reference/clibrary/

  • 合格程序员:<stdio.h>、<ctype.h>、<stdlib.h>、<string.h>
  • 熟练程序员:<assert.h>、<limits.h>、<stddef.h>、<time.h>
  • 优秀程序员:<float.h>、<math.h>、<error.h>、<locale.h>、<setjmp.h>、<signal.h>、<stdarg.h>

main函数
#

C 语言有两种可能的运行环境中,它们之间有一定差别:

  • 独立环境(freestanding):在独立环境中,C 程序的运行没有操作系统的支持,因此,只具有最小部分的标准库能力。
    • 在独立环境中,程序开始时所调用的第一个函数,其类型和名称是由正在运行的 C 语言实现版本所决定的。除非是在嵌入式系统上进行 C 程序开发,否则程序一般都运行在宿主环境中。
  • 宿主环境(hosted):在宿主环境中,C 程序会在操作系统的控制和支持下运行。可得到完整的标准库能力。
    • 在宿主环境中编译的 C 程序必须定义一个名为 main 的函数,这是程序开始时调用的第一个函数。

main函数一般有三种定义方式

//这两种定义方式都符合 C 语言标准
int main( void ) { /* … */ }
int main( int argc, char *argv[ ] ) { /* … */ }
//除此之外,许多 C 的实现版本还支持第三种、非标准语法的定义方式
int main( int argc, char *argv[ ], char *envp[ ] ) { /* … */ }

返回值
#

main()函数都会把最终的执行状态以整数的方式传递给操作系统。返回值如果是 0EXIT_SUCCESS,就表示程序执行过程一切顺利;任何非 0 的返回值,尤其是 EXIT_FAILURE,则表示程序执行时出现了某种问题。

头文件 stdlib.h 中定义了上述的两个常量 EXIT_SUCCESSEXIT_FAILUREmain()函数不一定要有 return 语句。如果程序运行到 main()函数块的右括号(}),那么就会自动向执行环境返回状态值 0。

main()函数结束等效于调用标准库函数 exit()main()的返回值作为 exit()的参数。

参数
#

  • argc(全称为 argument count)的值为 0 或者为命令行中启动该程序的字符串的数量。程序本身的名称也算作该字符串,也要计算进去。
  • argv(全称为 arguments vector)是一个 char 指针数组,每个指针都独立的指向命令行中每个字符串: 数组中元素的个数,比 argc 的值多 1;最后一个元素 argv[argc] 是空指针。 如果 argc 大于 0,那么第一个字符串,argv[0],就是程序本身的名称。如果运行环境不支持程序名称,那么 argv[0] 为空。 如果 argc 大于 1,从字符串 argv[1]argv[argc-1] 包含该程序命令行参数。
  • envp(全称为 environment pointer)在非标准的、有 3 个参数的 main()函数版本中,是一个指针数组,每个指针都指向组成程序环境的一个字符串。通常,这个字符串的格式是名称=值。在标准 C 语言中,可以利用函数 getenv()获取得这些环境变量。

函数的定义
#

return_type function_name( parameter list ){
   body of the function
}
  • 返回类型:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void
  • 函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
  • 参数:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
  • 函数主体:函数主体包含一组定义函数执行任务的语句。
  • c语言的函数不可以嵌套定义

函数的声明
#

所谓声明(Declaration),就是告诉编译器我要使用这个函数,你现在没有找到它的定义不要紧,请不要报错,稍后我会把定义补上

return_type function_name( parameter list );
//因为函数的参数名不是必须的,所以下面两种声明方式都可以
void max(int a,int b);
void max(int,int);

函数声明给出了函数名、返回值类型、参数列表(重点是参数类型)等与该函数有关的信息,称为函数原型(Function Prototype)。函数原型的作用是告诉编译器与该函数有关的信息,让编译器知道函数的存在,以及存在的形式,即使函数暂时没有定义,编译器也知道如何使用它。

有了函数声明,函数定义就可以出现在任何地方了,甚至是其他文件、静态链接库、动态链接库等。

#include<stdio.h>
//函数的声明
int max(int,int);

int main(){
   int num1 = 10;
   int num2 = 20;
   //调用函数
   printf("num1、num2最大值为:%d",max(num1,num2));
}
//函数的定义
int max(int a,int b){
   return a > b? a : b;
}

作用域规则
#

任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量:

  1. 在函数或块内部的局部变量
  2. 在所有函数外部的全局变量
  3. 在形式参数的函数参数定义中

局部变量
#

在某个函数或块的内部声明的变量称为局部变量。它们只能被该函数或该代码块内部的语句使用。局部变量在函数外部是不可知的。

#include<stdio.h>

int main(){
   //局部变量a和b,只可以在main函数中使用
   int a = 10,b = 20;
   printf("a:%d,b:%d\n",a,b);

   return 0;
}

全局变量
#

全局变量是定义在函数外部,通常是在程序的顶部。全局变量在整个程序生命周期内都是有效的,作用域在整个程序,也就是所有的代码文件,包括源文件(.c文件)和头文件(.h文件),任意的函数内部能访问全局变量。

#include<stdio.h>
//局部变量a和b,作用域是整个程序
int a = 10,b = 20;

int main(){
   
   printf("a:%d,b:%d\n",a,b);

   return 0;
}

形参
#

函数的参数,形式参数,被当作该函数内的局部变量,它们会优先覆盖全局变量。

#include<stdio.h>

int a = 10;

void test(int a){
   printf("%d",a);
}

int main(){
   test(50);
   //50
   return 0;
}

同名参数调用规则
#

C语言规定,在同一个作用域中不能出现两个名字相同的变量,否则会产生命名冲突;但是在不同的作用域中,允许出现名字相同的变量,它们的作用范围不同,彼此之间不会产生冲突。

  • 不同函数内部可以出现同名的变量,不同函数是不同的局部作用域;
  • 函数内部和外部可以出现同名的变量,函数内部是局部作用域,函数外部是全局作用域。
  • 函数调用参数遵循就近原则,也就是形参>全局参数局部参数>全局参数

参数默认值
#

局部变量被定义时,系统不会对其初始化,必须自行对其初始化

定义全局变量时,系统会自动对其初始化

正确地初始化变量是一个良好的编程习惯,否则有时候程序可能会产生意想不到的结果,因为未初始化的变量会导致一些在内存位置中已经可用的垃圾值。

全局参数默认值:

数据类型 初始化默认值
int 0
char ''
float 0
double 0
pointer NULL
C语言基础 - 点击查看当前系列文章
§ 7、函数和作用域 「 当前文章 」