网易云课堂_C语言程序设计进阶_第6周:程序结构
6.1 全局变量
6.2 编译预处理
6.3 大程序结构
6.1 全局变量
全局变量
定义在函数外面的变量是全局变量
全局变量具有全局的生存期和作用域
它们与任何函数都无关
在任何函数内部都可以使用它们
全局变量初始化
没有做初始化的全局变量会得到0值
指针会得到NULL值
只能用编译时刻已知的值来初始化全局变量
它们的初始化发生在main函数之前
被隐藏的全局变量
如果函数内部存在与全局变量同名的变量,则全局变量被隐藏
静态本地变量
在本地变量定义时加上static修饰符就成为静态本地变量
当函数离开的时候,静态本地变量会继续存在并保持其值
静态本地变量的初始化只会在第一次进入这个函数时做,以后进入函数时会保持上次离开时的值
静态本地变量
静态本地变量实际上是特殊的全局变量
它们位于相同的内存区域
静态本地变量具有全局的生存期,函数内的局部作用域
static在这里的意思是局部作用域(本地可访问)
返回指针的函数
返回本地变量的指针式危险的
返回全局变量或静态本地变量的地址是安全的
返回在函数内malloc的内存是安全的,但是容易造成问题
最好的做法是返回传入的指针
tips
不要使用全局变量来在函数间传递参数和结果
尽量避免使用全局变量
使用全局变量和静态本地变量的函数是线程不安全的
6.2 编译预处理
#开头的是编译预处理指令
它们不是C语言的成分,但是C语言程序离不开它们
#define用来定义一个宏
#define
#define<名字><值>
注意没有结尾的分号,因为不是C的语言
名字必须是一个单词,值可以是各种东西
在C语言的编译器开始编译之前,编译预处理程序(cpp)会把程序中的名字换成值
完全的文本替换
gcc--save-temps
宏
如果一个宏的值中有其他的宏的名字,也是会被替换的
如果一个宏的值超过一行,最后一行之前的行末需要加\
宏的值后面出现的注释不会被当作宏的值的一部分
#include <stdio.h>
#include <stdlib.h> #define PI2 2*PI
#define PI 3.14159 void main()
{
printf("%lf\n", PI); printf("%lf\n", PI2); system("pause");
}
没有值的宏
#define _DEBUG
这类宏是用于条件编译的,后面有其他的编译预处理指令来检查这个宏是否已经被定义过了
预定义的宏
__LINE__
在源代码中插入当前源代码行号
__FILE__
在源代码中插入当前源代码文件名
__DATA__
在源代码中插入当前编译日期〔注意和当前系统日期区别开来〕
__TIME__
在源代码中插入当前编译时间〔注意和当前系统时间区别开来〕
__STDC__
当要求程序严格遵循ANSIC标准时该标识符被赋值为1
#include <stdio.h>
#include <stdlib.h> void main()
{
printf("%s:%d\n", __FILE__, __LINE__); printf("%s,%s\n", __DATE__, __TIME__); system("pause");
}
像函数的宏
#define cube(x) ((x)*(x)*(x))
宏可以带参数
错误定义的宏
#define RADTODEG(x) (x*57.29578)
#define RADTODEG(x) (x)*57.29578
#include <stdio.h>
#include <stdlib.h> #define RADTODEG1(x) (x*57.29578) #define RADTODEG2(x) (x)*57.29578 void main()
{
printf("%lf\n", RADTODEG1( + )); printf("%lf\n", RADTODEG2( + )); system("pause");
}
带参数的宏的原则
一切都要括号
整个值要括号
参数出现的每个地方都要括号
#define RADTODEG(x) ((x)*57.29578)
带参数的宏
可以带多个参数
#define MIN(a,b) ((a)>(b)?(b):(a))
也可以组合(嵌套)使用其他宏
分号?
结尾不要加上分号;
带参数的宏
在大型程序的代码中使用非常普遍
可以非常复杂,如“产生”函数
在#和##这两个运算符的帮助下
存在中西方文化差异
部分宏会被inline函数替代
其他编译预处理指令
条件编译
error
6.3 大程序结构
多个.c文件
main()里的代码太长了适合分成几个函数
一个源代码文件太长了适合分成几个文件
两个独立的源代码文件不能编译形成可执行的程序
编译单元
一个.c文件是一个编译单元
编译器每次编译只处理一个编译单元
头文件
把函数原型放到一个头文件(以.h结尾)中,在需要调用这个函数的源代码文件(.c文件)中#include这个头文件,就能让编译器在编译的时候知道函数的原型
#include
#include是一个编译预处理指令。和宏一样,在编译之前就处理了
它把那个文件的全部文本内容原封不动地插入到它所在的地方
所以也不是一定要在.c文件的最前面#include
""还是<>
#include有两种形式来指出要插入的文件
""要求编译器首先在当前目录(.c文件所在的目录)寻找这个文件,如果没有,到编译器指定的目录去找
<>让编译器只在指定的目录去找
编译器自己知道自己的标准库的头文件在哪里
环境变量和编译器命令行参数也可以指定寻找头文件的目录
#include的误区
#include不是用来引入库的
stdio.h里只有printf的原型,printf的代码在另外的地方,某个.lib(Windows)或.a(Unix)中
现在的C语言编译器默认会引入所有的标准库
#include <stdio.h>只是为了让编译器知道printf函数的原型,保证你调用时给的参数值是正确的类型
头文件
在使用和定义这个函数的地方都应该#include这个头文件
一般的做法就是任何.c都有对应的同名.h,把所有的对外公开的函数原型和全局变量的声明都放进去
不对外公开的函数
在函数前面加上static就使得它成为只能在所在的编译单元中被使用的函数
在全局变量前面加上static就使得它成为只能在所在的编译单元中被使用的全局变量
变量的声明
int i;是变量的定义
extern int i;是变量的声明
声明和定义
声明是不产生代码的东西
函数原型
变量声明
结构声明
宏声明
枚举声明
类型声明
inline声明
定义是产生代码的东西
头文件
只有声明可以被放在头文件中
是规则不是法律
否则会造成一个项目中多个编译单元里有重名的实体
某些编译器允许几个编译单元中存在同名的函数,或者用weak修饰符来强调这种存在
重复声明
同一个编译单元里,同名的结构不能被重复声明
如果你的头文件里有结构的声明,很难这个头文件不会在一个编译单元里被#include多次
所以需要“标准头文件结构”
标准头文件结构
#ifndef __LIST_HEAD__
#define __LIST_HEAD__ #include "node.h" typedef struct _list
{
Node *head;
Node *tail;
}List; #endif // !
运用条件编译和宏,保证这个头文件在一个编译单元中只会被#include一次
#pragma once也能起到相同的作用,但是不是所有的编译器都支持
网易云课堂_C语言程序设计进阶_第6周:程序结构的更多相关文章
- 网易云课堂_C语言程序设计进阶_第三周:结构:结构、类型定义、联合
3.1 枚举 3.2 结构 3.3 类型定义 3.1 枚举 枚举是一种用户定义的数据类型,它用关键字enum以如下语法来表明: enum 枚举类型名字{名字0,...,名字n}; 枚举类型名字通常并不 ...
- 网易云课堂_C语言程序设计进阶_第8周:图形交互程序
8.2函数指针 8.2函数指针 #include <stdio.h> #include <stdlib.h> void f(int i) { printf("void ...
- 网易云课堂_C语言程序设计进阶_第七周:文件:文件访问、格式化输入输出、二进制输入输出
7.1文件 7.2底层操作 7.1文件 格式化的输入输出 printf %[flags][width][.prec][hIL]type Flag 含义 - 左对齐 + 在前面放+或- (space) ...
- 网易云课堂_C语言程序设计进阶_第5周:链表_1逆序输出的数列
1 逆序输出的数列(10分) 题目内容: 你的程序会读入一系列的正整数,预先不知道正整数的数量,一旦读到-1,就表示输入结束.然后,按照和输入相反的顺序输出所读到的数字,不包括最后标识结束的-1. 输 ...
- 网易云课堂_C语言程序设计进阶_第5周:链表
5.1可变数组 5.2链表 5.1可变数组 Resizable Array Think about a set of functions that provide a mechanism of res ...
- 网易云课堂_C语言程序设计进阶_期末考试编程题部分
1 字符串循环右移(5分) 题目内容: 输入一个字符串和一个非负整数N,要求将字符串循环右移N次. 输入格式: 输入在第1行中给出一个字符串,以'#'表示结束,‘#’不是字符串的一部分,字符串的长度未 ...
- 网易云课堂_C语言程序设计进阶_第二周:指针:取地址运算和指针、使用指针、指针与数组、指针与函数、指针与const、指针运算、动态内存分配_2信号报告
2 信号报告(5分) 题目内容: 无线电台的RS制信号报告是由三两个部分组成的: R(Readability) 信号可辨度即清晰度. S(Strength) 信号强度即大小. 其中R位于报告第一 ...
- 网易云课堂_C语言程序设计进阶_第一周:数据类型:整数类型、浮点类型、枚举类型_1计算分数精确值
1 计算分数精确值(10分) 题目内容: 由于计算机内部表达方式的限制,浮点运算都有精度问题,为了得到高精度的计算结果,就需要自己设计实现方法. (0,1)之间的任何浮点数都可以表达为两个正整数的商, ...
- 网易云课堂_C语言程序设计进阶_第四周:ACL图形库
创建ACLLib程序 #include"acllib.h" #include<stdio.h> int Setup1() { initWindow(, );//初始化窗 ...
随机推荐
- 手机开机提示SD卡受损
手机开机提示SD卡受损,手机不显示内存卡,有人会选择换新卡或者格式化内存卡,如果刚好木有备份,内存卡上的珍藏丢失了多心痛啊.其实,我们可以通过电脑救活提示受损的内存卡,前后不超过5分钟... 方法:1 ...
- 用正则表达式抓取网页中的ul 和 li标签中最终的值!
获取你要抓取的页面 const string URL = "http://www.hn3ddf.gov.cn/price/GetList.html?pageno=1& ...
- MYSQL 二进制还原
解决方法: mysqlbinlog bin_log_file_path_and_name | mysql -uroot -p 如: mysqlbinlog E:\DB\mysql_log\mysql_ ...
- Android源码下载
Android源码下载 1.安装git 2.安装repo 从这里 https://dl-ssl.google.com/dl/googlesource/git-repo/repo 下载repo文件 3. ...
- 第52周四ApplicationContext
ApplicationContext的中文意思是"应用前后关系"应用上下文即容器,它继承自BeanFactory接口,除了包含BeanFactory的所有功能之外,在国际化支持.资 ...
- Build A Micro Team
最近这两周一直在忙,忙到忘记回QQ和微信的程度,甚至有两天下班回来直接躺平,虽说忙碌但是也收获了不少. Start 说起来有趣,最近在忙的这个项目最初是公司设立的用于工程师在业余时间开发的projec ...
- WMware VMX格式转换成OVF
1.关于VMX格式 vmx文件是vmware虚拟机系统的配置文件,注意:刚刚安装好VMware Workstation以后是找不到这个文件的,当你在VMware Workstation中建立了一个虚拟 ...
- description方法介绍及重写
- bootstrap注意事项(二)
1.内联子标题 在标题内还可以包含 <small> 标签或赋予 .small 类的元素,可以用来标记副标题. <!DOCTYPE html> <html> < ...
- 说说数据库架构,ORM缓存和路由
为什么在ORM层做缓存,而不是DB层 ORM能有效地提高程序员的开发效率,程序员更喜欢操作对象而不是数据库,他们不关心也不想手写一堆SQL语句,毕竟一个公司里普通程序员要占多数,他们并不是非常熟悉数据 ...