将程序分成适度的自包含单元是开发任一程序的基本方式
C语言中的一个重要观念是,每个程序都应该切割成许多小的函数
8.1 程序的结构
- C程序是由许多函数组成,其中最重要的就是函数main(),它是执行的起点。
- 程序中的每个函数都是一个执行特定操作的自包含单元
- 调用一个函数时,就执行该函数体内的代码,这个函数执行结束后,控制权就回到调用该函数的地方
8.1.1 变量的作用域和生存期
变量只存在与定义变量的块中,变量在声明时创建,在遇到下一个闭括号时就不存在了。
在外部块的起始处声明的变量也存在于内部块
自动变量:
- 变量在一个块内声明时创建,在这个块结束时销毁,这种变量称为自动变量。自动变量是自动创建和销毁的。
变量的作用域:
- 给定变量可以在某个程序代码块中访问和引用,这个程序代码块称为变量的作用域。
- 变量在它的作用域之外不存在
- 外部块变量可以访问内部块的变量,内部块变量不可以访问外部块变量
变量的生存周期:
- 变量存在的时间称为变量的生存期。
8.1.2变量的作用域和函数
如何创建函数?
每个函数体都是一个块,在一个函数内声明的自动变量是这个函数的本地变量,在其他地方不存在。
不同的函数内使用相同的变量名称
8.2 函数
如何通过函数名称后括号内的参数给函数传递信息?????
有两种方法接收函数返回的信息
(1)使用函数的一个参数
(2)通过返回值接收函数传回的信息。
8.2.1 定义函数
1、什么是函数定义?
2、什么是函数头?
函数头定义了函数的名称、函数参数、和函数返回值的类型
3、什么是函数体?
- 函数的一般形式:
返回值的类型 函数名称(参数列表)
{
//执行代码块?
}
Return_type Function_name(Parameters - Separated by commas)
{
//Statements....
}
- 调用函数的一般形式
Function_name(List of Arguments - sepaated by commas)
函数名称(参数列表)
1、函数的命名
数字、字母、下划线、
函数名最好能说明函数的作用
- 在函数名称中用下划线字符分开每个单词。
- 将每个单词的第一个字母大写
- 将除第一个单词之外的每个单词的第一个字母大写。
注意:
不要使用与任何标准库函数相同的名称、以避免混淆。
2、函数的参数
- 函数的参数在函数头中定义
- 是调用函数时必须指定的变元的占位符。
- 函数的参数是一列变量名称和变量的类型。
- 整个参数列表放在函数名称后的括号中。
- 调用函数时给参数指定的值称为变元
- 要把数组作为变元传递给函数,必须传递一个额外的变元,指定数组的大小。,没有这个额外的参数,函数就不知道数组有多少个元素
- -
3、指定返回值的类型
Return_type Function_name(List of parameters - separated by commas)
{
//Statements ....
}
Return_type 指定了函数的返回值类型,如果在表达式中使用函数,或者在赋值语句的右侧使用,则函数的返回值会取代该函数。
返回类型也可以是void*。表示指向void指针,此时,返回值是一个地址值,但是没有指定类型。
8.2.2 return 语句
return语句允许退出函数
return ;
这个形式的return语句用于返回值类型声明为void的函数,它不返回任何值
一个函数中可以能有多条return语句,但每条return语句都必须提供一个可以转换为函数头中返回值指定的类型的值
8.3 按值传递机制
- 给函数传送变元时,变元值不会直接传递给函数,而是先制作变元值的副本,存储在栈上,再使这个副本可用于函数,而不是使用初始值。
double value 1 = 4.0;
double value 2 = 6.0;
double result =Average(value1,value2);
double Average(double x,double y)
{
return (x+y)/2.0;
}
- Average()函数不能访问调用该函数时传递为变元的变量value1和value2,只能访问这两个变元值的副本。这表示函数不能修改存储在value1或者value2中的值。
- 这个机制是C语言中的所有变元值传递给函数的方式。称为按值传递机制(pass-by-value mechanism)
8,4 函数原型
函数的声明也称为函数的原型,是一个定义函数基本特性的语句,它定义了函数的名称,返回值的类型和每个参数的类型
函数原型需要在函数头后面加上分号
函数原型能使编译器在使用这个函数的地方创建适当的指令,检查是否正确地使用。
函数原型一般放在源文件的开头处,而且在所有函数的定义和头文件之前
在源文件中,函数原型在所有函数的外部,函数的作用域是从其声明处开始一直到源文件的结尾。
因此无论函数的定义放在什么地方,源文件中的任意函数都可以调用该文件中的其他函数。
注意参数类型double*等价于函数定义中的参数类型double[].
在函数原型中
无论在什么地方调用,最好总是把函数的声明放在程序的源文件中,
main()函数不需要函数原型,因为在程序开始执行时,这个函数会由主机环境调用
8.5 指针用作参数和返回值
把数组作为变元,通过指针参数传递给函数时,只传递了该数组的地址副本,而没有传递数组
第一种方式:定义一个额外的参数,即数组的元素个数
对于带有指针参数P和元素个数n的函数,数组元素可以通过其地址来访问,它们的地址p到p+n-1《=== 》 等价于传递了两个指针,一个是p,指向数组的第一个元素;另一个是p+n指向最后一个元素后面的地址第二种方式:在函数可以访问的最后一个数组元素中存储一个特别的唯一值
8.5.1 常量参数
用const关键字修饰函数的参数,这表示函数将传递给参数的变元看做是一个常量
指针参数:指定函数不能修改变元指向的值
函数不修改指针指向的数据
bool SendMessage(const char* pmessage)
{
//code to send the message
return true;
指向指针的指针:把指针指向的指针定义为const ,防止修改指针指向的内容
指针的指针参数
void sort(const char** str,size_t n);
void replace(char *const *str,size_t n);
char *const *str::指向char的常量指针的指针
size_t max_lenth(const char* const* str,size_t n)
const char* const* str:指向const char的常量指针的指针类型