C语言函数

在C语言中,函数是执行特定任务的功能模块。我们需要函数是为了解决复杂问题,将其拆成小问题,对应到一个功能模块上,并且增加代码的复用性,提高开发效率。

一  函数:

1.语法:

类型标识符 函数名(形式参数列表)
{
   函数体; //实现具体功能 对应代码 
}

(1)类型标识符  --- 数据类型

(2)函数名      --- 名字,标识符

(3)形式参数    --- 变量的定义,主要用来接收 实际的数据

(4)函数体      --- 实现具体功能 对应代码

2.返回值类型

返回结果对应的数据类型 函数名(数据入口)
{
   函数体; //实现具体功能 对应代码  ---处理数据
   
   return 表达式; //--带出结果 
}
3.函数调用:函数名(实际参数):如add(1,2);,c = c + add(1,2);

4.函数的返回值:

(1)返回值类型:如函数不需要带出结果使用void 类型

(2)返回值类型也可以与返回结果类型 不一致,此时,以规定的返回值类型为准

(3)返回值也可以不写类型,默认是 int型

5.函数的声明:函数定义在main函数之后,在main函数中使用前,需要声明函数定义的位置:函数头+分号

6.局部变量和全局变量:处于 {} 范围内的都叫局部变量 ,{} 这个范围叫做局部变量的作用域

二  数组作为函数参数:

1.传数组名作为实参过去形参写成:void printArray(int a[10]),形式上,说明准备接收一个数组

void printArray(int *a),本质上,指针类型的变量,用来接收数组的名字 (数组名代表的是数组首元素的地址)
{              在函数内部可以访问到数组元素 ---(指针再说)
}

2.整型二维数组做函数参数:

形参:数组形式   行数;int A(int(*a)[n],int row)

实参:数组名     行数 ;A(a,row)

3.字符型一维数组做函数参数:

形参:数组形式;char A(char a)

实参:数组名(不需要传数组长度 ---- 字符串本身有结束标志 );A(a)

4.字符型二维数组:与整型 二维数组作函数参数 书写方式相同

形参:数组形式 行数

实参:数组名   函数 

三 函数的嵌套调用:

1.在了解嵌套调用前,先了解一些数据结构的一些基本知识

(1)栈 --- 函数调用过程中的数据 以及 局部变量

特点:自动申请自动释放(局部变量)    

(2)堆 --- 特点:空间大,但需要程序员手动申请手动释放

(3)全局区(静态区):全局的数据

(4)字符串常量区:如char s[] = "hello";

(5)代码区:程序 = 数据 + 代码 

2.特殊的嵌套调用:递归,即自己调用自己

(1)递归本质上还是一种循环 

(2)与for while do-while 循环有区别:栈的空间有限,一定会结束 

(3)在效率上递归并不高效

(4)递归解决问题的思路:问题n,解决依赖,问题n-1,的解决

递归的代码结构:

int sum(int n)
{
   什么情况下 要递推下去
   什么情况下 要结束 
   if (n==1)
   {
        return 1;
   }else
   {
       return sum(n-1) + n;    
   }
}

四 标识符的作用域 和 可见性问题

1.作用域:即变量的作用范围,分为局部作用域和全局作用域

2.可见性: 从程序的角度看,在运行到某句代码时,哪些标识符,可以被用

标识符的可见性的规则:

(1)先定义,后使用

(2)同一作用域中,不能有同名标识符

(3)在不同的作用域,同名标识符,相互之间没有影响

(4)如果是不同的作用域,但是作用域之间存在嵌套关系,则内层的作用域的同名标识符,会屏蔽外层的作用域的同名标识符。(就近原则)

3.变量的生命周期:

(1)局部变量的生命期:从定义处开始,到作用域结束

(2)静态变量(全局变量)的生命周期:从程序运行开始,到程序结束

修饰的关键字:static,静态修饰局部变量,表示将局部变量,放到静态区
      (1)static 修饰的变量不能用变量初始化 ,需要用常量

      (2) static 修饰的局部变量值, 只需要初始化一次,具有继承性;static 修饰全局变量,限定该变量只能被本文件使用(限定了它的作用域 static 修饰的全局变量 ,不能再用extern)

                          auto int a:局部变量 默认就是auto 存储类别的关键,一般都省略不写

                          register int a:寄存器,建议性的关键字,register  修饰的变量,不能 & (取地址)
                
                          extern int a:表示这个a不在本文件中,而是在外部的文件中定义的,需要到外部的文件中寻找,extern 扩展了变量的作用域

五  gcc编译代码的流程:

预处理:预编译 ---- 为编译阶段做准备---- 将.c代码中预处理命令执行---- 得到全是c代码的文件

eg:gcc -E hello.c -o hello.i  

编译阶段:将c代码的文件,编译成汇编代码 
   
eg: gcc -S hello.c -o hello.s

         gcc -S hello.i -o hello.s 

汇编阶段:将.s文件编译成机器指令 
eg:gcc -c hello.s -o hello.o

链接:需要将用到的别的函数的代码实现链接到最终的可执行程序中

eg:gcc hello.o -o hello

预处理需要注意的点:

(1)预处理本身不是c语言的一部分

(2)预处理命令都是#开头

(3)预处理阶段要做的事:执行预处理的命令,完成文本原样替换

五 宏定义:#define

1.宏定义语法:#define 标识符 字符串;#define 宏名  宏值

eg.define N  10    宏定义在预处理阶段 ,用宏值将出现宏名的统统原样替换

2.带参宏: #define 宏名(参数) 宏值;define SUM(a,b) a+b,又叫宏函数,但它不是函数,只是形式上有些相似。区别:函数形式参数带类型,函数往往有返回值,函数返回值往往有类型

(1)带参宏:预处理阶段发挥作用

(2)函数:程序运行时发挥作用

(3)但是宏替换可能导致代码体积偏大,而函数在代码中只保留一份

3.宏的副作用:完完全全的文本替换,涉及运算符优先级时,能加括号都加括号;宏的定义要求必须写在同一行(续航符: \ 符号后面不能空格)

4.宏作用域:从宏定义处开始到本文件结束,但是可以使用#undef强制结束宏作用域

六 文件包含:在预处理阶段,表示将文件中的内容,展开在这个位置(文本替换) 

(1)#include <文件名>:系统的默认(头文件)路径下寻找文件 --- 系统下,一般都用<>

(2)#include "文件名":首先,先在当前位置下寻找,如果没找到再到系统默认路径下寻找 

六 条件编译:

#if 0

#endif 

形式1:
#ifdef 表达式
   程序段1
#else
    程序段2
#endif

形式2:
#ifndef 表达式
   程序段1
#else
    程序段2
#endif

Linux编译时,gcc -D宏名可以快捷定义宏

条件编译的用途:debug版本 --- 调试版本,release版 --- 去除掉调试信息;实现头文件,可以避免,因重复包含,带来重复定义的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值