C语言学习(五)函数,预处理命令

来源:互联网 发布:中国的gis数据交换中心 编辑:程序博客网 时间:2024/04/30 15:43

第八章 函数

8.1概述

1.一个C程序可以由一个主函数和若干个其他函数构成。


2.一个C程序由一个或多个源程序文件组成。对较大的程序,一般希望将所有内容分别放在若干个源文件中。这样便于分别编写,分别编译,提高调试效率。一个源文件可以为多个C程序公用。


3.一个源程序文件由一个或多个函数以及其他有关内容(如命令行,数据定义等)组成。一个源程序文件是一个编译单位,在程序编译时是以源程序文件为单位进行编译的,而不是以函数为单位。


4.函数不能嵌套定义。函数可以相互调用,但是不能调用main()函数。main()函数由系统调用。


5.从用户角度看函数有2

1)标准函数,系统提供.

2)自定义


6.从函数形式看,分为2

1)无参函数

2)有参函数


8.2函数定义的一般形式

1.无参函数定义

类型标识符函数名() {

声明部分

语句部分

}


例如:


voidtest() {

inta = 1;

a= a + 1

}


2.有参函数定义

类型标识符函数名(形参列表) {

声明部分

语句部分

}


例如:


inttest(int num) {

int a = 1;

intb = a + num;

returnb;

}


如果在定义函数时,不指定函数返回类型,系统会默认返回int类型,因此上面test()函数的int返回类型可以不用声明。


3.空函数

在程序设计时有可能会用到空函数,一般形式为:


类型标识符函数名() {

}


例如:

intrun() {

}


在程序设计中可以在将来准备扩充功能的地方写上一个空函数,以后用一个编好的函数代替它。这样做以后在扩展新功能时方便,对程序结构影响不大。


8.3函数参数和函数值


1.函数被调用前,形参不占内存,只有当被调用了,形参才被分配内存,调用结束后所占内存也被释放。


2.实参可以是常量,变量或表达式,要求它们有确定的值,在调用时将实参的值赋给形参。


3.在定义函数时,必须指定形参类型。


4.实参与形参类型应该相同或赋值兼容。


5.C语言中,实参向形参的数据传递是“值传递”,单项传递,在调用函数时,给形参分配存储单元,并将实参数值传递给形参,结束后,形参内存被释放,实参但愿仍然保留并维持原值。

因此,在执行一个函数时,形参的值改变并不会改变主调函数的实参的值。


6.函数原型的一般形式有2种:

1)返回值 函数名(参数类型1,参数类型2...,参数类型n);例如:

intsum(int,int);


2)返回值函数名(参数类型1,参数名1,参数类型2,参数名2...,参数类型n,参数名n);例如:

intsum(int num1,int num2);


说明:a)如果被调用函数在主调函数之前,可以不必加以声明。


b)如果已经在文件的开头(在所有函数之前),对所调用的函数进行了声明,则在各函数中不必对其所调用的函数再作声明。

8.8局部变量和全局变量

1.为了便于区别全局变量和局部变量,在C程序设计人员中一般将全局变量名的第一个字母大写。


2.建议不在必要时,不要使用全局变量:

a)全局变量在程序的全部执行过程中都占内存,而不是仅在需要时开辟内存空间.


b)它使函数的通用性降低了,因为函数在执行时要依赖于其所在的外部变量。如果将一个函数移到另一个文件中,还要将有关的外部变量和它的值一起。如果这个外部变量与其他文件中的变量同名时,就会出现问题。

c)在划分模块时要求模块的“内聚性”强,“耦合性”弱。也就是要模块的功能单一,与其他模块的互相影响要尽量小,而全局变量不符合这个原则。


d)一般要求把C程序中的函数做成一个封闭体,除了可以通过”实参——形参”方式与外界发生联系外,没有其他渠道。这样的程序移植性好,可读性强。


3.如果在同一个源文件中,局部变量和全局变量同名,则在局部变量的作用范围内,全局变量无效。



8.9变量存储类别

1.静态存储方式指在程序运行期间由系统分配固定的存储空间。动态存储方式指在程序运行期间系统根据需要分配存储空间,不固定。


2.内存中提供用户使用的存储空间分为三部分:程序区,静态存储区,动态存储区。数据分别存放在静态存储区和动态存储区中。


3.静态存储区。

a)全局变量全部存放在静态存储区中

b)在程序开始执行时给全局变量分配存储空间,程序执行完毕释放。

c)在程序执行过程中全局变量占据固定的存储单元,而不是动态进行分配和释放。


4.动态存储区。

以下数据存放在动态存储区中:

1)函数形参

2)未加static生命的局部变量

3)函数调用时的现场保护和返回地址等

对于这些数据,函数在调用开始时分配动态存储空间,函数结束时释放这些空间。在程序执行过程中,这种分配和释放是动态的。


5.C语言中,每一个变量和函数都有两个属性:数据类型和存储类别。数据类型就是整形,字符行。存储类型指的是数据在内存着中的存储方式。


6.数据在内存中的存储方式分为:静态存储类和动态存储类。具体包含4种:自动的(auto),静态的(static),寄存器(register)和 外部的(extern).根据变量的存储类别,可以知道变量的作用域和生存期。

a)auto变量

函数中的局部变量,如果不专门声明为static存储类别,都是动态分配存储空间的,数据存储在动态存储区中。


关键字”auto”可以省略。


b)static变量

1)静态局部变量属于静态存储类型,在静态存储区内分配存储单元。在整个程序运行期间都不释放。

2)静态变量在编译时进行初始化。

3)如果不对不静态局部变量赋初值,编译时,系统会自动赋初值,0(数值型变量)或空字符(字符变量)。


4)静态局部变量在函数调用后仍然存在,但是其他函数不能引用它。


c)register变量

一般情况下,变量的值是存储在内存中的。C语言允许将局部变量的值放到CPU中的寄存器中,需要时,直接从寄存器取出参与运算,不必再到内存中去存取。

由于对寄存器的存取速度远高于对内存的存取速度,因此这样做可以提高执行效率。


说明: 1)只有局部自动变量和形式参数可以作为寄存器变量,其他(如全局变量)不行。


d)extern变量

外部变量的作用域从变量的定义处开始,到本程序文件的末尾。编译时将外部变量分配在静态存储区。用extern来声明外部变量,以扩展外部变量的作用域。


1)在一个文件内声明外部变量

如果外部变量不在文件开始处定义,则它的有效范围是从定义处到文件末尾。

如果在定义点之前的函数想引用该外部变量,则应该在引用之前加上extern,表示该变量是一个已经定义的外部变量。例如:

#include<stdio.h>


voidmain() {

intmax(int,int);

externA , B;


printf("%d\n",max(A,B));

}


intA = 13; B = 0;


intmax(int a,int b) {

intz;

z= a > b ? a : b;

returnz;

}

输出:13


外部变量就是用extern关键字引用的全局变量,它的作用就是扩展全局变量的作用域。例如引用函数下面定义的全局变量,如上例,或者引用另外一个文件中的全局变量。


全局变量加上static关键字修饰之后,就只能被本文件引用,而不能被其他文件引用。


外部变量以静态存储方式存放,在编译时分配内存。


8.10内部函数和外部函数


1.内部函数(static)

内部函数只能被本文件中其他函数所调用。


2.外部函数(extern)

如果在定义函数时省略extern,则默认为该函数是外部函数。


第九章 预处理命令

预处理命令不是C语言本身的组成部分,不能直接对它们进行编译。必须在对程序进行通常的编译前跟据预处理命令对程序作相应的处理。(例如在程序中用#define命令定义了一个符号常量A,则在预处理时将程序中所有的A都置换为制定字符。)

经过预处理后的程序不再包括预处理命令了,最后再由编译程序对预处理后的源程序进行通常的编译处理,得到可供执行的目标代码。

C提供的预处理功能主要有3种:

宏定义
文件包含
条件编译


9.1宏定义


1.定义符号常量:#define标识符 字符串例如:

#definePI 3.1415


说明: a)宏名一般用大写字母表示

b)宏定义不是C语句,不需要加分号,如果加了则会将分号一起置换

c)#define命令出现在程序中函数的外面,宏名的有效范围在定义命令之后到本源文件结束。通常                           将#define命令写在文件开头,函数之前,作为文件一部分在此文件范围内有效。


e)可以用#undef命令终止宏定义的作用域。


f)在进行宏定义时,可以引用已定义的宏名。例如:

#include<stdio.h>


#defineR 3.0

#definePI 3.1415

#defineL 2*PI*R

#defineS PI*R*R

g) 宏定义不分配内存


2.带参数的宏定义:#define宏名(参数表) 字符串例如:

#defineS(a,b) a*b

.

.

.

area=S(3,2);

赋值语句展开为:area= 3 * 2;


#include<stdio.h>


#definePI 3.1415

#defineS(r) PI*r*r


voidmain() {

floata,area;

a= 3.6;

area= S(a);

printf("area= %f\n",area);


}


输出:area= 40.713837



说明: a)对带参数的宏的展开只是将表达式中实参字符串代替#difine命令行中的形参。

b)在宏定义时,在宏名与带参数的括号之间不应该加空格,否则就会将空格后面的内容作为替换内容。例如:

#defineS (r) PI * r * r

则认为S是符号常量,它代表字符串”(r)PI * r * r”, 如果程序中出现area= S(a),则被展开为area= (r) PI * r * r(a);


9.2文件包含处理

1.指一个源文件可以将另外一个源文件的全部内容包含进来。C语言提供了#include命令来实现“文件包含的操作”。

#include“文件名” 或者#include<文件名>


2.在编译时不是将源文件和被包含的文件分别进行编译,而是在经过编译预处理后将头文件包含到主文件中,得到一个新的源程序,然后再对这个文件进行编译,得到一个目标文件。

3.被包含文件修改后,凡是包含这个文件的主文件都要重新编译。


4.头文件除了可以包括函数原型宏定义外,也可以包括结构题类型定义全局变量定义


5.注意:

a)一个#include命令只能制定一个包含文件。


b)如果文件1包含文件2,而文件2用到文件3的内容,则可以在文件1中用两个include命令分别包含文件2和文件3,而且文件3应该出现在文件2之前,这样,file1file2都可以用到file3的内容。在file2中不必再用到#include“file3.h”了。


c)文件包含可以嵌套。


9.3条件编译

一般情况下,源程序中所有内容都参加编译。但是有时希望程序中的一部分内容只在满足一定条件下才进行编译,也就是对一部分内容制定编译的条件,这就是”条件编译“。


条件编译有以下几种形式:


1)#ifdef标识符

程序段1

#else

程序段2


#endif


作用是如果标识符已经被#fefine命令定义过,则在程序编译阶段编译程序段1;否则编译程序段2.其中#else部分可以没有。


#ifdef标识符

程序段1


#endif


2#ifndef标识符

程序段1

#else

程序段2


#endif



与第一种方式相反。



3)#if表达式

程序段1

#else

程序段2


#endif


作用是当指定的表达式值为真(非零)时编译程序段1,否则编译程序段2.

文章链接:http://blog.csdn.net/murongshusheng/article/details/8626529



原创粉丝点击