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周:程序结构的更多相关文章

  1. 网易云课堂_C语言程序设计进阶_第三周:结构:结构、类型定义、联合

    3.1 枚举 3.2 结构 3.3 类型定义 3.1 枚举 枚举是一种用户定义的数据类型,它用关键字enum以如下语法来表明: enum 枚举类型名字{名字0,...,名字n}; 枚举类型名字通常并不 ...

  2. 网易云课堂_C语言程序设计进阶_第8周:图形交互程序

    8.2函数指针 8.2函数指针 #include <stdio.h> #include <stdlib.h> void f(int i) { printf("void ...

  3. 网易云课堂_C语言程序设计进阶_第七周:文件:文件访问、格式化输入输出、二进制输入输出

    7.1文件 7.2底层操作 7.1文件 格式化的输入输出 printf %[flags][width][.prec][hIL]type Flag 含义 - 左对齐 + 在前面放+或- (space) ...

  4. 网易云课堂_C语言程序设计进阶_第5周:链表_1逆序输出的数列

    1 逆序输出的数列(10分) 题目内容: 你的程序会读入一系列的正整数,预先不知道正整数的数量,一旦读到-1,就表示输入结束.然后,按照和输入相反的顺序输出所读到的数字,不包括最后标识结束的-1. 输 ...

  5. 网易云课堂_C语言程序设计进阶_第5周:链表

    5.1可变数组 5.2链表 5.1可变数组 Resizable Array Think about a set of functions that provide a mechanism of res ...

  6. 网易云课堂_C语言程序设计进阶_期末考试编程题部分

    1 字符串循环右移(5分) 题目内容: 输入一个字符串和一个非负整数N,要求将字符串循环右移N次. 输入格式: 输入在第1行中给出一个字符串,以'#'表示结束,‘#’不是字符串的一部分,字符串的长度未 ...

  7. 网易云课堂_C语言程序设计进阶_第二周:指针:取地址运算和指针、使用指针、指针与数组、指针与函数、指针与const、指针运算、动态内存分配_2信号报告

    2 信号报告(5分) 题目内容: 无线电台的RS制信号报告是由三两个部分组成的: R(Readability) 信号可辨度即清晰度. S(Strength)    信号强度即大小. 其中R位于报告第一 ...

  8. 网易云课堂_C语言程序设计进阶_第一周:数据类型:整数类型、浮点类型、枚举类型_1计算分数精确值

    1 计算分数精确值(10分) 题目内容: 由于计算机内部表达方式的限制,浮点运算都有精度问题,为了得到高精度的计算结果,就需要自己设计实现方法. (0,1)之间的任何浮点数都可以表达为两个正整数的商, ...

  9. 网易云课堂_C语言程序设计进阶_第四周:ACL图形库

    创建ACLLib程序 #include"acllib.h" #include<stdio.h> int Setup1() { initWindow(, );//初始化窗 ...

随机推荐

  1. 初学swift笔记字典、数组(四)

    import Foundation //字典 元素顺序是无序的 //1.字典元素是键值对 (key:value) //key 一定是可哈希的 string\int\bool var dic1=[&qu ...

  2. 一维树状数组(HD1166)

    #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string.h> using namespace st ...

  3. QTcpSocket 及 TCP粘包分析

    ----我的生活,我的点点滴滴!! 这两天用Qt简单的实现一个tcp多线程client,在此记录下知识. 一.长连接与短连接 1.长连接 Client方与Server方先建立通讯连接,连接建立后不断开 ...

  4. instance variables may not be placed in categories

    Avoid Properties in Categories Objective-C分类中是不允许增加成员变量的(Instance variables may not be placed in cat ...

  5. 分布式-在win7上安装linux操作系统

    由于大多数的分布式计算框架.分布式存储系统.分布式平台都支持在unix类似的环境下.所以要做分布式的实验和学习的话,还是推荐装个linux系统.我这里安装的是ubuntu,由于之前装过这个. 一.下载 ...

  6. Secret of Success(成功的秘诀)

    A youngman asked Socrates the secret of Success. Socrates told the youngman to meet him near the riv ...

  7. 重写equal要重写 hashCode的原因

    public class Test { public static void main(String[] args) { Person person1 = new Person(); person1. ...

  8. AngularJs(八) 过滤器filter创建

    大纲 示例 过滤器的使用 创建过滤器 demo 这是整个示例demo 1.filter.js文件 angular.module("exampleApp", []) .constan ...

  9. 常用的sql server规范

    常见的字段类型选择1.字符类型建议采用varchar/nvarchar数据类型2.金额货币建议采用money数据类型3.科学计数建议采用numeric数据类型4. 自增长标识建议采用bigint数据类 ...

  10. 对浏览器css兼容性的学习理解及问题解决汇总

    一.从浏览器内核的角度 来看,浏览器兼容性问题可分为以下三类: 1. 渲染相关:和样式相关的问题,即体现在布局效果上的问题. 2. 脚本相关:和脚本相关的问题,包括JavaScript和DOM.BOM ...