第十二周:程序结构

简介: 你已经快坚持到了最后,很棒!

12.1-1全局变量:定义在函数之外的变量,全局的生存期和作用域

全局变量

  1. 定义在函数外面的变量是全局变量
  2. 全局变量具有全局的生存期和作用域
  1. 他们和任何函数无关
  2. 在任何函数内部都可以使用他们

#include

intf(void);

intgAll=12;//全局变量

intmain(intargc,charconst*argv[])

{

   printf("in %s gAll=%d\n",__func__,gAll);

   f();

   printf("agn in %s gAll = %d\n",__func__,gAll);

   return0;

}

//_func_是一个字符串,表达的是当前函数的名字,也就是main的名字

intf(void)

{

   printf("in %s gAll=%d\n",__func__,gAll);

   gAll+=2;

   printf("agn in %s gAll=%d\n",__func__,gAll);

   returngAll;

}

全局变量初始化

  1. 没有做初始化的全局变量会得到0值
  1. 指针会得到NULL值
  1. 只能用编译时刻已知的值来初始化全局变量
  2. 它们的初始化发生在main函数之前

被隐藏的全局变量

  1. 如果函数内部存在与全局变量同名的变量,则全局变量被隐藏(局部的优先度会更高噢,会覆盖掉外面的变量)

12.1-2静态本地变量:能在函数结束后继续保有原值的本地变量

静态本地变量

  1. 在本地变量定义时加上static修饰符就成为静态本地变量
  2. 当函数离开的时候,静态本地变量会继续存在并保持其值
  3. 静态本地变量的初始化只会在第一次进入这个函数时做,以后进入函数时会保持上次离开时的值

#include

intf(void);

intgAll=12;//全局变量

intmain(intargc,charconst*argv[])

{

   f();

   f();

   f();

   return0;

}

//_func_是一个字符串,表达的是当前函数的名字,也就是main的名字

intf(void)

{

   staticintall=1;

   printf("in %s gAll=%d\n",_func_,gAll);

   gAll+=2;

   printf("agn in %s gAll=%d\n",_func_,gAll);

   returngAll;

}

  1. 静态本地变量实际上是特殊的全局变量
  2. 它们(静态本地变量和全局变量)位于相同的内存区域
  3. 静态本地变量具有全局的生存期,函数内的局部作用域
  4. static 在这里的意思是局部作用域(本地可访问)

12.1-3后记:返回指针的函数,使用全局变量的贴士

*返回指针的函数

  1. 返回本地变量的地址是危险的
  2. 返回全局变量或静态本地变量的地址是安全的
  3. 返回在函数内malloc的内存是安全的,但是容易造成问题
  4. 最好的做法是返回传入的指针

tips(贴士)

  1. 不要使用全局变量来在函数间传递参数和结果
  2. 尽量避免使用全局变量
  1. 丰田汽车的案子(ks)  这里给出传送门(想知道的可以看看):https://www.sohu.com/a/133455549_464086
  1. *使用全局变量和静态本地变量的函数是线程不安全的

12.2-1宏定义

编译预处理指令

  1. #开头的是编译预处理指令
  2. 它们不是c语言的成分,但是C语言程序离不开它们
  3. #define用来定义一个宏 ,其实只是一个原始的文本替换

#define

  1. #define<名字><值>
  2. 注意没有结尾的分号,因为不是c的语句
  3. 名字必须是一个单词,值可以是各种东西
  4. 在C语言的编译器开始编译之前,编译预处理程序(cpp)会把程序中的名字换成值
  1. 完全的文本替换
  1. gcc——save-temps

  1. 如果一个宏的值中有其他宏的名字,也是会被替换的
  2. 如果一个宏的值超过来一行,最后一行之前的行末需要加\
  3. 宏的值后面出现的注释不会被当作宏的值的一部分

没有值的宏

  1. #define_DEBUG
  2. 这里宏是用于条件编译的,后面有其他的编译预处理指令来检查这个宏是否已经被定义过了

预定义的宏

  1. LINE表达代码所在的行号
  2. FILE表达代码所在的文件名
  3. DATE编译时候的日期
  4. TIME编译时候的时间
  5. STDC

12.2-2带参数的宏

像函数的宏

  1. #define cube(x)((x)(x)(x))
  2. 宏可以带参数

#include

#define cube(x)((x)*(x)*(x))

intmain(intargc,charconst*argv[])

{

   printf("%d\n",cube(5));

   //cube(5)会被替换成cube((5)*(5)*(5));

   

   return0;

}

错误定义的宏

  1. #define RADTODEG(x)(x*57.29578)
  2. #define RADTODEG(x)(x)*57.29578

带参数的宏的原则

  1. 一切都要括号
  1. 整个值要括号
  2. 参数出现的每个地方都要括号
  1. #define RADTODEG(x)((x)*57.29578)

带参数的宏

  1. 可以带多个参数
  1. #define MIN(a,b)((a)>(b)?(b):(a))
  1. 也可以组合(嵌套)使用其他宏
  2. 定义宏的时候后面千万不要加分号
  3. 在大型程序的代码中使用非常普遍
  4. 可以非常复杂,如"产生"函数
  1. 在#和##这两个运算符的帮助下
  1. 存在中西方文化差异
  2. 部分宏会被inline函数替代

宏的缺陷

没有可以去检查宏有没有问题的机制

其他预编译

  1. 条件编译
  2. error
  3. ...

12.3-1多个源代码文件

多个.c文件

  1. main()里的代码太长了适合分成几个函数
  2. 一个源代码文件太长了适合分成几个文件
  3. 两个独立的源代码文件不能编译形成可执行的程序

项目

因为看的是翁恺老师2014年的版本(比后来的课程内容多不少,后来的课程缩水了),所以这部分已经有更好的就进行省略了

编译单元

  1. 一个.c文件是一个编译单元
  2. 编译器每次编译只处理一个编译单元

12.3-2头文件

  1. 把函数原型放到一个头文件(以.h结尾)中,在需要调用这个函数的源代码文件(c文件)中#include这个头文件,就能让编译器在编译的时候知道函数的原型

#include

  1. #include是一个编译预处理指令,和宏一样,在编译之前就处理了
  2. 它把那个文件的全部文本内容原封不动地插入到它所在的地方
  3. 所以也不是一定要在.c文件的最前面#include

“”还是<>

  1. #include有两种形式来指出要插入的文件
  1. “”要求编译器首先在当前目录(.c文件所在的目录)寻找这个文件,如果没有,到编译器指定的目录去找,例如“MAX.h”啥的自己设定的那些
  2. <>让编译器只在指定的目录去找,例如
  1. 编译器自己知道自己的标准库的头文件在哪里
  2. 环境变量和编译器命令行参数也可以指定寻找头文件的目录

#include的误区

  1. #include不是用来引入库的
  2. stdio.h里只有printf的原型,printf的代码在另外的地方,某个.lib(Windows)或.a(Unix)中
  3. 现在的C语言编译器默认会引入所有的标准库
  4. #include只是为了让编译器指定printf函数的原型,保证年调用时给出的参数值是正确的类型

头文件

  1. 在使用和定义这个函数的地方都应该%include这个头文件
  2. 一般的做法就是任何.c都有对应的同名的.h,把所有对外公开的函数的原型和全局变量的声明都放进去
  3. 全局变量是可以在多个.c之间共享的

不对外公开的函数

  1. 在函数前面加上static就使得它成为只能在所在的编译单元中被使用的函数
  2. 在全局变量前面加上static就使得它成为只能在所在的编译单元中被使用的全局变量了

12.3-3声明

变量的声明

  1. int i;是变量的定义
  2. extern int i;是变量的声明

声明和定义

  1. 声明是不产生代码的东西
  1. 函数原型
  2. 变量声明
  3. 结构声明
  4. 宏声明
  5. 枚举声明
  6. 类型声明
  7. inline函数
  1. 定义是产生代码的东西

头文件

  1. 只有声明可以被放在头文件中
  1. 是规则不是法律
  1. 否则会造成一个项目中多个编译单元里有重名的实体
  1. *某些编译器允许几个编译单元中存在同名的函数,或者用week修饰符来强调这种存在

重复声明

  1. 同一个编译单元里,同名的结构不能被重复声明
  2. 如果你的头文件里有结构的声明,很难这个头文件不会在一个编译单元里被#include多次所以需要"标准头文件"

标准头文件结构

  1. 运用条件编译和宏,保证这个头文件在一个编译单元中只会被#include一次
  2. #pragma once也能起到相同的作用,但是不是所有的编译器都支持

#ifndef __LIST_HEAD__

#define __LIST_HEAD__

#include"node.h"

typedefstruct_list{

   Node*head;

   Node*tail;

}List;

#endif

目录
相关文章
|
6月前
【中级软件设计师】—(针对上午题)输入输出控制方式(二十)
【中级软件设计师】—(针对上午题)输入输出控制方式(二十)
蓝桥杯之单片机学习(二十一)——自动售水机(附题目和完整代码)
蓝桥杯之单片机学习(二十一)——自动售水机(附题目和完整代码)
368 0
蓝桥杯之单片机学习(二十一)——自动售水机(附题目和完整代码)
[软考考点解析]软件设计师--流水方式指令执行时间
1. 题目 将一条指令的执行过程分解为取指、分析、执行三步,按照流水方式执行,若取指时间为4t,分析时间为2t,执行时间3t,则执行100条指令需要的时间为____t。 A 200 B 300 C 400 D 405
232 0
|
机器学习/深度学习 人工智能 C++
C++第6周项目2 - 程序填空
课程首页地址:http://blog.csdn.net/sxhelijian/article/details/7910565,本周题目链接:http://blog.csdn.net/sxhelijian/article/details/8748730 【题目】程序填空:按要求将缺少的代码填进去,经调试确认符合要求 a. 用指针访问对象 class A { private: int a
940 1
2013C++第10周项目——循环结构程序设计
课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759【项目1:利用循环求和】求1000以内所有偶数的和要求:请编出3个程序来,分别用三种循环语句完成,注意体会各种循环语句的执行过程及语法特点。 【项目2-分数的累加】编程序,输出1/3-3/5+5/7-7/9…+19/21的结果提示:如果直接解决上面的问题有困难,可以设计一
1089 0
2013C++第9周项目——多分支结构程序设计
课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759 【项目1分段函数求值】从键盘输入x的值(整型),根据公式1计算并输出x和y的值。  要求用switch语句构造多分支结构完成求解,利用BB平台上“第9周练习源代码及博文模板.txt”中给出了博文模板发布报告。 提示: 解法1:类似例3.9的思路,各分段的标准都
1420 0
|
存储 自然语言处理 C++
C02-程序设计基础提高班(C++)第14周上机任务-文件操作
第14周:阅读教材第13章(p417-458),主要内容是输入输出,重点是文件的操作,完成第14周上机任务; (回到C02-程序设计基础提高班(C++)学习安排) 【任务1】涨工资从文件salary.txt中读入500名工人的工资,全部增加100元后进行排序,将排序后的结果在屏幕上输出,并保存到文件ordered_salary.txt中。[ 参考:涨工资了 - http://blog.cs
1508 0
|
程序员 C++
C++第12周项目1——重温星号图
课程首页地址:http://blog.csdn.net/sxhelijian/article/details/7910565 【项目1-调用函数输出星号图】   这一组的练习意在通过调用函数输出星号图,体会与理解函数的工作过程,并为其后编制自定义函数实现特定功能,打下基础。  任务1:补充完下面的程序,使程序输出上面的两个星号图,要求在main()函数中调用自定义函数printstars(
1414 0
|
C++
C02-程序设计基础提高班(C++)第11周上机任务-运算符重载
第11周:阅读教材第10章(p314-346),掌握用运算符重载解决问题,完成第11周上机任务; (回到C02-程序设计基础提高班(C++)学习安排) 【任务1】实现复数类中的运算符重载定义一个复数类重载运算符+、-、*、/,使之能用于复数的加减乘除。(1)方案一:请用类的成员函数完成运算符的重载; class Complex { public: Complex(){real=0;imag
1336 0
|
网络架构 C++ 安全
C02-程序设计基础提高班(C++)第12周上机任务-类的继承
第12周:阅读教材第11章(p347-394),主要内容是类的继承,完成第12周上机任务; (回到C02-程序设计基础提高班(C++)学习安排) 【任务1】定义一个名为CPerson的类,有以下私有成员:姓名、身份证号、性别和年龄,成员函数:构造函数、析构函数、输出信息的函数。并在此基础上派生出CEmployee类,派生类CEmployee增加了两个新的数据成员,分别用于表示部门和薪水。要
1223 0