C语言chap6(函数与宏定义)

合集下载

详解C语言的宏定义

详解C语言的宏定义

详解C语⾔的宏定义宏定义介绍假设我们有⼀个 C 源⽂件 main.c,那么只需要通过 gcc main.c -o main.exe 即可编译成可执⾏⽂件(如果只写 gcc main.c,那么 Windows 上会默认⽣成 a.exe、Linux 上会默认⽣成 a.out ),但是这⼀步可以拆解成如下步骤:预处理:gcc -E main.c -o main.i,根据 C 源⽂件得到预处理之后的⽂件,这⼀步只是对 main.c 进⾏了预处理:⽐如宏定义展开、头⽂件展开、条件编译等等,同时将代码中的注释删除,注意:这⾥并不会检查语法;编译:gcc -S main.i -o main.s,将预处理后的⽂件进⾏编译、⽣成汇编⽂件,这⼀步会进⾏语法检测、变量的内存分配等等;汇编:gcc -c main.s -o main.o,根据汇编⽂件⽣成⽬标⽂件,当然我们也可以通过 gcc -c main.c -o main.o 直接通过 C 源⽂件得到⽬标⽂件;链接:gcc main.o -o main.exe,程序是需要依赖各种库的,可以是静态库也可以是动态库,因此需要将⽬标⽂件和其引⽤的库链接在⼀起,最终才能构成可执⾏的⼆进制⽂件。

⽽这⾥我们主要来介绍⼀下预处理中的宏定义,相信很多⼈都觉得宏定义⾮常简单,但其实宏定义有很多⾼级⽤法。

我们先来看看简单的宏定义:#include <stdio.h>// 宏定义的⽅式为:#define 标识符常量// 然后会将所有的 PI 替换成 3.14#define PI 3.14int main() {printf("%f\n", PI);}我们⽣成预处理之后的⽂件:gcc -E main.c -o main.i我们看到 PI 被替换成了 3.14,当然除了浮点型之外,也可以是其它的类型:#include <stdio.h>#define NAME "satori"#define AGE 17#define GENDER 'f'int main() {printf("%s %d %c\n", NAME, AGE, GENDER); // satori 17 f}我们再来查看⽣成的预处理⽂件:我们看到确实只是简单替换,除此之外,没有做任何的处理。

二级必过法宝之chap6函数与宏定义

二级必过法宝之chap6函数与宏定义

return result;
} 返回运算结果*/
第14页
表示不返回结果
2.不返回运算结 果的函数定义
void 函数名(参数表) /* 函数首部 */ { /* 函数体 */ 函数实现过程 return; /* 可以省略return */ }
这类函数通常用于屏幕输出等 不能省略 否则 函数类型被默认定义为int
20:18
第4页
程序结构
main( )
函数1
函数2
… …
函数m
函数 1_1
函数 1_2
函数 m_1
… …
函数 m_n
20:18
第5页
• main()也是一个函数,C程序由一个main() 或多个函数构成。 • 程序中一旦调用了某个函数,该函数就会 完成一些特定的工作,然后返回到调用它 的地方。
1、函数经过运算,得到一个明确的运算结果, 并需要回送该结果。例如,函数add()返回两个 数的和。 2、函数完成一系列操作步骤,不需要回送任何 运算结果。
20:18
第10页
函数定义1: int abs_sum(int m, int n) { if (m<0) m=-m; if(n<0) n=-n; return(m+n); }
20:18
函数定义2: int abs_sum(m, n) int m,n { if (m<0) m=-m; if(n<0) n=-n; return(m+n); }
20:18
第23页
4.函数原型声明
只写函数定义中的第1行(函数首部),并以分号结束。
函数类型 函数名(参数表);
double cylinder (double r, double h); void pyramid (int n);

c 函数宏定义格式

c 函数宏定义格式

c 函数宏定义格式C函数宏定义格式C语言作为一种强大而广泛应用的程序设计语言,提供了许多功能和工具来简化代码的编写和重复使用。

其中,函数宏定义(Function Macro Definition)是C语言中的一种重要机制,可以通过宏来定义用户自定义的函数,提高代码的可读性和可维护性。

本文将介绍C函数宏定义的格式以及一些使用示例。

一、函数宏定义的基本格式C语言中的函数宏定义使用#define关键字来定义,其基本格式如下:#define 宏名(参数列表) 替换体其中,宏名是用户自定义的宏名称,用于在代码中进行宏展开替换;参数列表是宏定义时传入的参数,可以为空或包含一个或多个参数;替换体是对应宏名称和参数的替换文本,在代码中进行宏展开时将替换为相应的文本。

下面是一个简单的C函数宏定义示例:#define SQUARE(x) ((x) * (x))上述示例定义了一个名为SQUARE的宏,它接收一个参数x,并将其替换为x的平方。

在实际使用中,当我们调用宏时,如SQUARE(5),宏展开后会替换为((5) * (5)),即25。

二、宏定义的注意事项在使用函数宏定义时需要注意以下几点:1. 参数加括号:在宏定义中,参数通常需要用括号括起来,以避免由于运算符优先级引起的错误。

例如,下面是一个错误的示例:#define MAX(a, b) a > b ? a : b在上述错误示例中,宏定义中的参数a和b没有使用括号括起来,当调用宏MAX传入表达式时可能会出现错误的结果。

正确的示例应该是:#define MAX(a, b) ((a) > (b) ? (a) : (b))2. 避免副作用:由于宏是在编译时展开的,因此在宏的替换体中可能存在副作用的问题。

例如,下面是一个错误的示例:#define INCREMENT(x) x++在上述错误示例中,宏定义中的替换体对参数x进行自增操作,当调用宏INCREMENT时可能会带来预期之外的结果。

C语言的宏定义

C语言的宏定义

C语言中的宏定义SUNNY.MAN1.宏定义格式:#define 标识符字符串其中的标识符就是所谓的符号常量,也称为“宏名”。

预处理(预编译)工作也叫做宏展开,就是把宏名替换为字符串。

2.为什么要使用宏定义我认为主要有两点:1.增强程序的可读性2.增强程序的可移植性int a=16;int *a=(int *)0;如果我们都是把int当32位来处理的,有一天我们的程序需要把int当16位来处理,你怎么办呢?#define int int16//请注意这个int16才是真正的类型(int *)0;也不好看啊。

我们喜欢用NULL,那也定义一个宏好了。

#define NULL (myint *)03.宏定义的作用域这是我写这文的目的。

请看下面的小例子Int sum(int a);Int main(void){Int a=sum(1);Int b=MM;Return 0;}Int sum(int a){#define MM 123Return a+MM;}这个程序在编译的时假会产生一个类似于下面的错误:MM undeclared (first use in this function)。

所以切记宏展开的位置是在文件中的位置,而不是调用它的位置。

运行和编译是两个阶段。

如果1.c文件中#undef MM#define MM 102.c文件中#undef MM#define MM 20那么到底是MM被定义为10呢还是20呢。

请记住宏展开的时机是预处理阶段而不是编译阶段,预处理阶段不检查语法错误。

也就是文件1中的还是10,文件2中的还是20。

4.宏的基本使用1.宏定义末尾不需要像语句一样加分号,但你可以根据需要自己进行添加;2.宏定义不管写在函数的花括号里外边,作用域为其后的程序行,通常在文件的最开头。

3.可以用#undef命令终止宏定义的作用域4.宏定义允许嵌套5.字符串( " " )中不会进行宏替换例如:#define TEST "this is a test"程序行中有"TEST"时不会替换为”this is a test”.6.宏定义的第二个“标识符”必须是合法的C语言的标识符。

c语言 宏函数

c语言 宏函数

C语言宏函数一、什么是宏函数在C语言中,宏函数是一种在代码中被预先定义的简单的文本替换机制。

当代码中出现宏函数的调用时,编译器会将宏函数的名称和参数替换为宏函数定义中所指定的文本,从而实现宏函数的功能。

二、宏函数的定义和使用宏函数的定义使用#define关键字,语法格式如下:#define 宏函数名(参数列表) 替换文本其中,宏函数名是用户自定义的宏函数名称,参数列表包含宏函数的参数,替换文本是宏函数的真正执行内容。

宏函数可以在任何需要的地方使用,它的使用方式和普通的函数调用非常相似。

例如:宏函数名(参数列表)三、宏函数的优缺点3.1 优点•宏函数在编译时会进行简单的文本替换,不需要函数的调用开销,执行效率高。

•宏函数不会增加新的函数调用栈,避免了函数调用的内存开销。

•宏函数可以实现代码的重用,降低代码量,提高可维护性。

3.2 缺点•宏函数的替换是简单的文本替换,没有类型检查,可能导致参数类型不匹配的问题。

•宏函数的替换会增加代码的长度,可能导致可读性下降。

•宏函数的定义一旦出错,会在编译期间就报错,增加了调试的难度。

四、宏函数的应用场景4.1 常量定义宏函数可以用于定义常量,例如:#define PI 3.14159这样,在代码中就可以直接使用宏函数PI来表示圆周率,而不需要重复输入具体的数值。

4.2 算术运算宏函数可以用于简单的算术运算,例如:#define SQUARE(x) ((x) * (x))这样,在代码中就可以使用宏函数SQUARE来计算平方,例如:int result = SQUARE(5); // 结果为254.3 条件编译宏函数可以用于条件编译,例如:#define DEBUG#ifdef DEBUG// 执行调试相关的代码#else// 执行发布版本的代码#endif这样,可以根据是否定义了宏函数DEBUG来选择性地编译不同的代码。

4.4 字符串拼接宏函数可以用于字符串的拼接,例如:#define CONCAT(a, b) a##bchar str[] = CONCAT("Hello", "World"); // 结果为"HelloWorld"五、宏函数的注意事项•宏函数的参数使用时需要加上括号,以防止由于运算符优先级引起的错误。

C语言chap6(函数与宏定义)

C语言chap6(函数与宏定义)
第 6 章 函数与宏定义
6.1 函数概念
在进行程序设计时,程序员总是将复杂的问题进行 分解, 化整为零。编写一段小程序就能解决一个小问题, 然后将这些小程序拼装起来就能解决非常大而复杂的问 题。在 C 中,这些小程序统称为函数。
在 C 中,由系统提供的函数放在函数库中供用户选 用,以减少重复编写程序模块的工作量。
printf(“MS C pragramming”); gets(s); 将被调用的函数写在表达式中。如:
c=2max(a, b); 注意:被调用函数max必须有确定的返回值。 将函数调用作为一个函数的实参。如:
m=max(max(a, b), c);
3.对被调用函数的说明
在一个函数中调用另一个函数时:
不能逆传。 可以在形参表中直接说明形参类型。如:
int max(int x, int y); float fun(int a[10], int n);
2019/5/1
5
2.函数的返回值
函数的返回值是通过return语句获得的。当不需返回 函数值时,可省去return语句。
return语句的后面可以有括号,也可以没有。如:
{ int a, b, c ; a=printstar( ); b=print_message( ); c=printstar( ); printf(“%d,%d,%d\n”,a,b,c);
}
输出的a, b, c的值将是随机值。
为了明确表示不需要函数返回值,可以用“void”定 义函数为“无类型”。此时,不得使用a=printstar( )之 类的语句。
z=x>y ? x : y;
return(z); }
3.“ 空函数 ”

C语言_函数与宏定义_教案

C语言_函数与宏定义_教案

C语言_函数与宏定义_教案教案:C语言_函数与宏定义一、教学目标:1.理解函数的概念和作用;2.学会如何定义和调用函数;3.掌握宏定义的概念和使用方法;4.能够编写复杂的函数和宏定义;5.了解函数和宏定义在编程中的应用。

二、教学内容:1.函数的概念和作用;2.函数的定义和调用;3.函数的参数传递和返回值;4.宏定义的概念和使用方法;5.常用的函数和宏定义的案例。

三、教学步骤:1.导入知识(10分钟)引导学生回顾函数和宏定义的概念,了解它们在编程中的作用和优势。

2.函数的定义和调用(20分钟)-介绍函数的定义和调用的语法;-示例代码演示函数的定义和调用的过程;-学生练习编写简单的函数,并进行调用。

3.函数的参数传递和返回值(20分钟)-介绍函数的参数传递和返回值的概念;-示例代码演示函数的参数传递和返回值的过程;-学生练习编写带参数和返回值的函数。

4.宏定义的概念和使用方法(20分钟)-介绍宏定义的概念和使用方法;-示例代码演示宏定义的过程;-学生练习编写简单的宏定义。

5.常用的函数和宏定义的案例(30分钟)-分析并演示常用的函数和宏定义的应用场景;-以实际案例为例,讲解函数和宏定义在编程中的应用;-学生根据案例练习编写函数和宏定义。

6.总结及作业布置(10分钟)-总结本节课学到的知识点和技能;-布置作业:要求学生编写一个复杂的函数或宏定义,并在下节课进行演示与交流。

四、教学资源:1.讲义和课件;2.代码示例;3. 编程工具(例如Code::Blocks)。

五、教学评估:1.班级练习作业评估;2.随堂讨论、提问和回答问题;3.下节课学生的演示与交流评估。

六、教学反思:通过本节课的教学,学生应该能够理解函数和宏定义的概念,掌握函数的定义和调用的方法,以及函数的参数传递和返回值的使用。

同时,学生还应该了解宏定义的使用方法,并能够编写复杂的函数和宏定义。

为了加深学生的理解和应用能力,本节课引入了常用的函数和宏定义的案例,以实际问题为例,讲解函数和宏定义在编程中的应用。

c语言宏定义

c语言宏定义

c语言宏定义C语言宏定义基本介绍1)#define 叫做宏定义命令它也是C语言预处理命令的一种,所谓宏定义,就是用一个标识符来表示一个字符串。

如果在后面的代码中出现了该标识符,那么就全部替换成指定的字符串。

2)#define N 100 就是宏定义,N为宏名,100是宏的内容(宏所表示的字符串)。

在预处理阶段,对程序中所有出现的“宏名”,预处理器都会用宏定义中的字符串区代换,这称为“宏替换”或“宏展开”。

宏定义是由源程序中的宏定义命令#define完成的,宏替换是由预处理程序完成的。

宏定义的形式#define 宏名字符串1)#表示这是一条预处理命令,所有的预处理命令都以# 开头。

宏名是标识符的一种,命名规则和变量相同。

字符串可以是数字、表达式、if语句、函数等。

2)这里所说的字符串是一般意义上的字符序列,不要和C语言中的字符串等同,它不需要双引号。

3)程序中反复使用的表达式就可以使用宏定义宏定义注意事项和细节0)宏定义实质:只替换,不计算。

1)宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的替换。

字符串中可以包含任何字符,它可以是常数、表达式、if语句、函数等,预处理程序对它不作任何检查,如有错误,只能在编译已被宏展开后的源程序时发现。

2)宏定义不是说明或语句,在行末不必加分号,如果加上分号则连分号一起替换。

3)宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。

如要终止其作用域可使用#undef命令。

4)代码中的宏名如果被引号包围,那么预处理程序不对其作宏代替。

5)宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名,在宏展开时由预处理程序层层代换。

6)习惯上宏名用大写字母表示,以便于与变量区别。

但也允许用小写字母。

7)可用宏定义表示数据类型,使书写方便。

8)宏定义表示数据类型和用typedef定义数据说明符的区别:宏定义只是简单的字符串替换,由预处理器来处理;而typedef 是在编译阶段由编译器处理的,它并不是简单的字符串替换,而给原有的数据类型起一个新的名字,将它作为一种新的数据类型。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

6.5 函数的嵌套调用
C 语言函数的定义都是相互平行、独立的,不能 嵌套定义。但可以嵌套调用函数。所谓函数的嵌套调 用就是在被调用的函数中又调用另外的函数。
6.6 函数的递归调用
在调用一个函数的过程中又出现直接或间接地调 用该函数本身,称为函数的递归调用。
2012-6-12
13
例6.4 有5人排成一队,从最后一人开始,其年龄均比 前面的人大2岁,而最前面的人年龄是10岁,问最后 一人的年龄是多少岁?
age(1)=12
2012-6-12
14
函数的递归调用利用了堆栈技术。在本例中: Age(4–1)+2 Age(3–1)+2 Age(2–1)+2 Age(5–1)+2 Age(5)
Age(2–1)+2
Age(3–1)+2
Age(2–1)+2
Age(3–1)+2
10+2=12
12+2=14
Age(4–1)+2
int max(int x, int y);
float fun(int a[10], int n);
2012-6-12 5
2.函数的返回值 函数的返回值是通过return语句获得的。当不需返回 函数值时,可省去return语句。
return语句的后面可以有括号,也可以没有。如:
return z ; return(z); return(x >y ? x : y); return语句返回值的类型应与该函数的类型一致。否 则以函数类型为准。
2012-6-12 11
例6.3 编程求11~999之间的数m,而m、m2和m3均是回文数(数 位左右对称)。 如:m=11、m2=121、m3=1331,…… 。 #include “stdio.h” main( ) {long int m; for (m=11; m<1000; m++) if (fun(m)&&fun(mm)&&fun(mmm)) printf("m=%ld,\t mm=%ld,\t mmm=%ld\n", m, mm, mmm); } int fun(long n) {long i, k; i= n; k=0; while (i) { k=i%10+k10; i = i /10; } if (k==n) return 1; else return 0; } 2012-6-12 12
全局变量增加了函数间数据联系的渠道。由于同一文件中的所 有函数都能引用全局变量的值,当需要从一个函数中带回多个值 时,就能克服函数调用只能返回一个值的局限性。 如无必要,不要使用全局变量。因为全局变量既降低程序的清 晰性和函数的通用性,且又在程序的全部执行过程中都占用存 储空间。 在文件开头定义的外部变量才可在整个文件范围内使用,若在 定义点之前的函数需引用外部变量,则可用关键字“extern” 作“外部变量说明”。 注意:外部变量定义和外部变量说明并不是同一回事。外部变量 的定义只能有一次,它的位置在所有函数之外。而同一程序中 的外部变量说明可以有多次,它的位置在函数之内(哪个函数 要用就在哪个函数中说明)。系统根据外部变量的定义(而不是 根据外部变量的说明)分配存储单元。对外部变量的初始化只 能在“定义”时进行,“extern”只是申明该变量是一个已在 外部定义过的变量而已。 如果在同一源文件中,外部变量与局部变量同名,则在局部变 量的作用范围内,外部变量不起作用。 2012-6-12 19
2012-6-12 4
注意: 形参变量在被调用前不占用存储单元;在被调用结束 后,形参所占存储单元亦被释放。
实参可以是常量、变量或表达式。
必须指定形参类型,且必须与实参的类型一致。 实参对形参的数据传递是“值传递”。即单向传递, 不能逆传。 可以在形参表中直接说明形参类型。如:
输出结果: 0
2012-6-12
注意:这里是按自右至左 求值的,相当于fun(3,3)。 若按自左至右求值,则相 当于fun(2,3), 则输出为-1。
9
2.函数调用的方式
调用函数,可以有如下三种方式: 将函数调用作为一个语句。如: printf(“MS C pragramming”); gets(s); 将被调用的函数写在表达式中。如: c=2max(a, b); 注意:被调用函数max必须有确定的返回值。 将函数调用作为一个函数的实参。如: m=max(max(a, b), c);
2012-6-12 1
6.2 函数定义的一般形式
1.无参函数的定义形式
无分号!
类型标识符 函数名( ) { 说明部分 ; 语句; } 无参函数一般不需要返回函数值,可以省略类型标识符。 2.有参函数的定义形式 类型标识符 函数名(形式参数表) 形式参数说明; { 说明部分 ; 语句; }2012-6-12
“空函数”什么操作也不做。其作用是在此处留一函 数的位置,以便将来扩充功能之用。函数名也在将来 换取实际的函数名。
2012-6-12 3
6.3 函数参数和函数的值
1.形式参数和实际参数 例6.1 从键盘输入两个数,输出其中较大的一个。 main( ) { int a, b, c ; scanf(“%d,%d”, &a, &b); c=max(a,b); / a, b为实际参数 / printf(“Max is %d”,c); } max(x,y) / x, y为形式参数 / int x, y; { int z; z=x>y ? x : y; return(z); }
结果为:7
汉诺塔问题参考程序(将A座上的N个disks 借助B座移动到C座)
#include "stdio.h" void h(int m,char x,char y,char z); void main() {int n; char a='a';char b='b';char c='c'; printf("input disks:"); scanf("%d",&n); h(n,a,b,c); } void h(int m,char x,char y,char z) {if(m==2){printf("%d%c-->%c\n",m-1,x,y); printf("%d%c-->%c\n",m,x,z); printf("%d%c-->%c\n",m-1,y,z); } else { h(m-1,x,z,y); printf("%d%c-->%c\n",m,x,z); h(m-1,y,x,z); } 2012-6-12 }
无分号!
2
例: int max(x,y) int x, y; / 形式参数说明 / { int z; / 函数体中的说明部分 / z=x>y ? x : y; return(z); 这两行可以写成一行: } int max(int x, int y) 3.“ 空函数 ” 类型说明符 函数名( ) { }
为了明确表示不需要函数返回值,可以用“void”定 义函数为“无类型”。此时,不得使用a=printstar( )之 类的语句。 凡不需要返回值的函数,一般均定义为“void”类型。
2012-6-12 7
6.4 函数的调用
1.函数调用的一般形式 函数名(实参表); 说明: 对于无参函数,尽管没有“实参表”,但也不得省 略括号。 “实参表”中的参数之间用逗号分开。 实参与形参之间的个数及类型必须一一对应。 对实参求值的顺序是自左至右还是自右至左, 视具体 的系统而定。Turbo C 和 MS C 是按自右至左的顺 序求值。
3.对被调用函数的说明
在一个函数中调用另一个函数时: 如果被调函数为库函数,则应在文件开头用“#include”命令 声明相应的“头文件”。如: #include “stdio.h” #include “math.h”
2012-6-12 10
如果被调函数为自定义函数且其定义在主调函数定义之后,则 应在主调函数中声明其类型(称之为”函数声明”)。其语句形式 为: 类型标识符 被调函数名( );
第6章
6.1 函数概念
函数与宏定义
在进行程序设计时,程序员总是将复杂的问题进行 分解, 化整为零。编写一段小程序就能解决一个小问题, 然后将这些小程序拼装起来就能解决非常大而复杂的问 题。在 C 中,这些小程序统称为函数。 在 C 中,由系统提供的函数放在函数库中供用户选 用,以减少重复编写程序模块的工作量。 所有函数都是平行的,相互独立不能嵌套,但可以相 互调用(main函数不能被其它函数调用)。 C 函数分标准函数(库函数)和自定义函数。 C 函数本身分有参函数和无参函数。
Age(5–1)+2 Age(5) 入栈
2012-6-12
Age(4–1)+2
Age(5–1)+2 Age(5) 出栈
14+2=16
16+2=18
18
出栈结果
15
写出下面程序的运行结果: 例6.4 e #include "stdio.h" fun(int x) {int p; if(x==0||x==1) return 3; p=x-fun(x-2); return p; } void main() { printf("%d\n",fun(9)); }
17
6.7 局部变量和全局变量
1.局部变量 在一个函数内部定义的变量,只能在本函数内使用和 有效,称为“局部变量”。 主函数main中定义的变量,也只能在主函数内使用 和有效。 不同函数中可以使用相同名字的变量,且互不干扰。 形式参数也是局部变量,也只能在所在函数内使用和 有效。 可以在一个函数内的复合语句中定义变量,且这些变 量只在本复合语句中有效。 这种复合语句也称为“分程序”或“子模块”。 2.全局变量 在函数(包括main函数)外定义的变量为外部变量, 称为“全局变量”。全局变量的有效范围为从定义变 2012-6-12 18 量的位置开始到本源文件结束。
相关文档
最新文档