笔记_C语言_函数与程序结构

函数的基本知识

函数的定义形式如下:

返回值类型 函数明(参数声明表)
{
	声明和语句
}

函数定义中的各构成部分都可以省略。最简单的函数如下所示:
dummy() {}
该函数不执行任何操作也不返回任何值。这种不执行任何操作的函数有时很有用,它可以在 程序开发期间用以保留位置(留待以后填充代码)。如果函数定义中省略了返回值类型,则默 认为 int 类型。
C 语言不允许在一个函数中定义其它函数

返回非整型值的函数

函数的声明与定义必须一致,否则结果会失去意义(数据类型会不一致会造成数据丢失)

外部变量

C语言程序可以看成由一系列的外部对象构成,这些外部对象可能是变量或函数。
默认情况下,外部变量与函数具有下列性质:通过同一个名字对 外部变量的所有引用(即使这种引用来自于单独编译的不同函数)实际上都是引用同一个对 象(标准中把这一性质称为外部链接)
如果函数之间要共享大量的变量,使用外部变量比使用很长的参数列表要高效方便的多。
缺点:对程序结构造成不良影响、导致程序中各个函数之间具有太多的数据联系。

外部变量的用途还表现在它们与内部变量相比具有更大的作用域和更长的生存期。自动变量只能在函数内部使用,从其所在的函数被调用时变量开始存在,在函数退出时变量也将 消失。而外部变量是永久存在的,它们的值在一次函数调用到下一次函数调用之间保持不变。 因此,如果两个函数必须共享某些数据,而这两个函数互不调用对方,这种情况下最方便的 方式便是把这些共享数据定义为外部变量,而不是作为函数参数传递。

作用域规则

名字的作用域指的是可以使用改名字的部分。
在一个源程序的所有源文件中,一个外部变量只能在某个文件中定义一次,而其它文件 可以通过 extern 声明来访问它(定义外部变量的源文件中也可以包含对该外部变量的 extern 声明)。外部变量的定义中必须指定数组的长度,但 extern 声明则不一定要指定数 组的长度。
extern(外部的)
外部变量的初始化只能出现在其定义中。

头文件

一方面是我们期望每个文件只能访问它完成任务所需 的信息;另一方面是现实中维护较多的头文件比较困难。我们可以得出这样一个结论:对于 某些中等规模的程序,最好只用一个头文件存放程序中各部分共享的对象。较大的程序需要 使用更多的头文件,我们需要精心地组织它们。
主要还是看项目的大小,适当的选择建立怎样的头文件,但是这些都只是为了 写代码和后期维护方便一些,编译器编译的结果可能不变

静态变量(static)

用 static 声明限定外部变量与函数,可以将其后声明的对象的作用域限定为被编译源文件的剩余部分。
如果把函数声明为 static 类型,则该函数名除了对该函数声明所在的文件可见外,其它文件都无法访问。
static 类型的内部变量同自动变量一样,是某个特定 函数的局部变量,只能在该函数中使用,但它与自动变量不同的是,不管其所在函数是否被 调用,它一直存在,而不像自动变量那样,随着所在函数的被调用和退出而存在和消失。换 句话说,static 类型的内部变量是一种只能在某个特定函数中使用但一直占据存储空间的变量。

寄存器变量(register)

register 声明告诉编译器,它所声明的变量在程序中使用频率较高。其思想是,将 register 变量放在机器的寄存器中,这样可以使程序更小、执行速度更快。但编译器可以 忽略此选项。

程序块结构

C 语言并不是 Pascal 等语言意义上的程序块结构的语言,它不允许在函数中定义函数。但 是,在函数中可以以程序块结构的形式定义变量。变量的声明(包括初始化)除了可以紧跟 在函数开始的花括号之后,还可以紧跟在任何其它标识复合语句开始的左花括号之后。以这 种方式声明的变量可以隐藏程序块外与之同名的变量,它们之间没有任何关系,并在与左花 括号匹配的右花括号出现之前一直存在
没怎么明白什么意思,就随便试了一下,就是不停的输出i的值,观察i值的变化

#include<stdio.h>
#include<stdlib.h>
void main() {
 int i = 1;
 if (i > 0) {
  int i = 2;
  for (; i < 4; i++) {
   printf("%d\n", i);
  }
 }
 else {
  printf("%d\n", i);
 }
 printf("%d\n", i);
 system("pause");
}

初始化

在不进行显式初始化的情况下,外部变量和静态变量都将被初始化为 0,而自动变量和寄 存器变量的初值则没有定义(即初值为无用的信息) 。
数组的初始化可以在声明的后面紧跟一个初始化表达式列表,初始化表达式列表用花括 号括起来,各初始化表达式之间通过逗号分隔。
字符数组的初始化比较特殊:可以用一个字符串来代替用花括号括起来并用逗号分隔的 初始化表达式序列。

递归

C 语言中的函数可以递归调用,即函数可以直接或间接调用自身。
虽然就一句话但是是一个非常好用的东西

C预处理器

文件包含

文件包含指令(即#include 指令)使得处理大量的#define 指令以及声明更加方便。 在源文件中,任何形如:
#include “文件名”

#include <文件名>
的行都将被替换为由文件名指定的文件的内容。如果文件名用引号引起来,则在源文件所在 位置查找该文件;如果在该位置没有找到文件,或者如果文件名是用尖括号<与>括起来的, 则将根据相应的规则查找该文件,这个规则同具体的实现有关。被包含的文件本身也可包含 #include 指令。

宏定义

替换只对记号进行,对括在引号中的字符串不起作用。例如,如果 YES 是一个通过#define 指令定义过的名字,则在 printf(“YES”)或 YESMAN 中将不执行替换
可以通过#undef 指令取消名字的宏定义,这样做可以保证后续的调用是函数调用,而不 是宏调用:

#undef getchar
int getchar(void) { ... } 

形式参数不能用带引号的字符串替换。但是,如果在替换文本中,参数名以#作为前缀则 结果将被扩展为由实际参数替换该参数的带引号的字符串(如果下面的例子看不懂就仔细阅读这段话)。例如,可以将它与字符串连接运 算结合起来编写一个调试打印宏:
#define dprint(expr) printf(#expr " = %g\n", expr)
使用语句
dprint(x/y)
调用该宏时,该宏将被扩展为:
printf("x/y" " = &g\n", x/y);
其中的字符串被连接起来了,这样,该宏调用的效果等价于
printf("x/y = &g\n", x/y);
在实际参数中,每个双引号"将被替换为",反斜杠\将被替换为\,因此替换后的字符串是 合法的字符串常量。

预处理器运算符##为宏扩展提供了一种连接实际参数的手段。如果替换文本中的参数与 ##相邻,则该参数将被实际参数替换,##与前后的空白符将被删除,并对替换后的结果重新 扫描。例如,下面定义的宏 paste 用于连接两个参数

#define  paste(front, back)
front ## back 

因此,宏调用 paste(name, 1)的结果将建立记号 name1。

条件包含

#if 语句对其中的常量整型表达式(其中不能包含 sizeof、类型转换运算符或 enum 常 量)进行求值,若该表达式的值不等于 0,则包含其后的各行,直到遇到#endif、#elif 或 #else 语句为止(预处理器语句#elif 类似于 else if)。在#if 语句中可以使用表达式 defined(名字),该表达式的值遵循下列规则:当名字已经定义时,其值为 1;否则,其值 为 0。
这个真没太看懂就不把例子放在这了

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值