将程序分为三部分:
(1)头文件:包含结构声明和使用这些结构的函数的原型。
(2)源代码文件:包含与结构有关的函数的代码。
(3)源代码文件:包含调用与结构相关的函数的代码。
头文件应该包含的内容:
(1)函数原型
(2)使用#define或const定义的符号常量
(3)结构声明
(4)类声明
(5)模板声明
(6)内联函数
包含头文件应使用“”而非<>
防止定义define多次的方法#ifndef xxx #endif
作用域和链接
作用域:名称在文件的多大范围内可见。
链接性:名称如何在不同单元间共享。
存储性
自动存储持续性
如果在代码块中定义了变量,则该变量的存在时间和作用域将被限制在该代码块内。
自动变量和栈
新数据往栈顶放,栈顶指针指向下一个可用的内存单元。当函数调用结束,指针重新指向以前的位置,新数据也不会被删除。
关键字register用来建议编译器使用CPU寄存器来存储自动变量:
register int cont;
旨在提高访问变量的速度
静态持续变量
编译器将分配固定的内存块来存储所有的静态变量
如果没有显示地初始化静态变量,编译器将他设为0
代码片段示例:
....int global = 1000;
static int one_file = 50;
int main(){}
void func1(int n)
{static int count = 0;int llama = 0;..}
void func2(int q){}
count作用域为局部,没有链接性(static声明的)只能在func1中使用他,和自动变量llama一样,与llama不同的是,即使不使用func1,count也会被留在内存中。
global和one_file的作用域都为整个文件,one_file只能在使用过main(),func1(),func2()的文件中使用他,global的链接性为外部,可以在其他文件使用
5种变量
存储描述 持续性 作用域 链接性 如何声明
自动 自动 代码块 无 在代码块中
寄存器 自动 代码块 无 在代码块中使用register
静态,无链接性 静态 代码块 无 在代码块中使用static
静态,外部链接性 静态 文件 外部 不在任何函数内
静态,内部链接性 静态 文件 内部 不在任何函数内使用static
静态初始化和动态初始化
静态初始化:零初始化和常量表达式初始化。
动态初始化:如果没有足够信息,变量将被动态初始化。(变量刚开始不初始化)
静态持续性和外部链接性
声明:定义声明和引用声明
引用声明使用关键字exern且不能进行初始化,否则声明为定义导致分配存储空间
double up;
extern int blem;
extern char gr = 'z';//初始化了算作定义声明
如果要在多个文件使用外部变量,只需在一个文件包含该变量的定义,但在使用该变量的其他文件中应使用extern声明他
定义与全局变量同名时,局部变量将隐藏全局变量。
作用域解析符"::"放在变量前面使用变量的全局版本。
静态持续性和内部链接性
//file1
int errors = 20;
//file2
static int errors = 5;
这种做法是允许的,因为static指出标识符errors的链接性为内部
静态存储持续性和无链接性
将static限定符用于在代码块中定义的变量,只能在代码块中使用,但是代码块不活跃时仍然存在。两次调用函数之间,静态局部变量的值不变。
只在程序启动时初始化一次
说明符和限定符
存储说明符:auto/register/static/extern/thread_local/mutable
auto:指出变量为自动变量。
thread_local:指出变量的持续性与其所属线程的持续性相同。
cv-限定符:const/volatile
volatile:即使程序代码没有对内存单元进行修改,其值也有可能发生变化。
mutable:即使为const也能修改。
const和extern const
如果在头文件声明const int x = 1那预处理器会让所有源文件包含此语句,是为内部链接性
如果是在头文件声明extern const int x = 1则在其他文件要使用x必须extern const x并且不能初始化
函数和链接性
和变量一样,静态函数只在本文件可用,其他文件可有同名函数,且覆盖外部定义,优先调用静态函数。
语言链接性
extern "C" void spiiff(int);//使用C语言链接性extern "C++" void spiff(int);//使用C++语言链接性
extern void spoff(int);//使用C++语言链接性
存储方案和动态分配
使用new运算符初始化
int *pi = new int (6);
double *pd = new double (99.99);
struct where {double x;double y;double z;}
where * one = new where {2.5,5.3,7.2};
int * ar = new int[4]{2,4,6,7};
int * pin = new int {6};
new失败时返回空指针
定位new运算符
new负责在堆中找到一个足以能够满足要求的内存块。
struct chaff
{
cbar dross[20];
int slag;
};
char buffer1[50];
char buffer2[500];
int main()
{
char *p1,*p2;
int *p3,*p4;
p1 = new chaff;
p3 = new int[20];
p2 = new (buffer1) chaff;
p4 = new (buffer2) int[20];
名称空间
传统的名称空间包括声明区和作用域
新的名称空间可以自己创建命名
namespace Jack{
double pail;
void fetch();
struct well{..};
}
名称空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中。
通过作用域解析运算符::访问名称空间的名称
Jack::pail = 12.4;
using声明和using编译指令
char fetch;
int main()
{
using Jack::fetch;
cin >> fetch;//读Jack的fetch
cin >> ::fetch//读global的fetch
}
using声明将名称添加到局部声明区域中
using Jack::fetch
int main()
{
cin >> fetch;//读Jack的fetch
}
using编译指令
using namespace Jack
int main()
{
cin >> fetch;
}
using编译指令和using声明比较
如果使用using编译指令导入一个已经在函数中声明的名称,则局部名称将隐藏名称空间名,就像隐藏同名的全局变量一样。
name space Jack{double fetch;}
char fetch;//global fetch
int main()
{
using namespace Jack;
dobule fetch;
cin >> fetch;//读的是main里刚声明的fetch
cin >> ::fetch;//读的是global fetch
cin >> Jack::fetch//读的是Jack的fetch
}
int foom()
{
Jack::Hill crest;//不合法
}
虽然函数中的using编译指令将名称空间的名称视为在函数之外声明的,但其他函数不能使用。
使用using声明导入名称如果和局部名称发生冲突,编译器将发出指示。使用using编译指令导入所有名称,如果发生冲突,局部名称将覆盖名称空间版本而编译器不会发出警告。
少用using namespace std;
多用 std::cin/std::cout/using std::cin
也可以在名称空间内使用using编译指令和using声明
namespace myth
{
using Jack::fetch;
using namespace elements;
}
如果要访问Jack::fetch可以std::cin >> myth::fetch;
当然也能std::cout << Jack::fetch;
创建别名:
namespace mvft = myth;
名称空间及其前途
(1)使用在已命名的名称空间中声明的变量,而不是使用外部全局变量。
(2)使用在已命名的名称空间中声明的变量,而不是静态全局变量。
(3)如果开发了一个函数库或类库,将其放在一个名称空间中。
(4)仅将编译指令using作为一种将旧代码转换为使用名称空间的权宜之计。
(5)不要在头文件中使用using编译指令。非要使用应将他放在所有预处理器编译指令#include之后。
(6)导入名称时,首选使用作为作用域解析运算符或using声明的方法。
(7)对于using声明,首选将其作用域设置为局部而不是全局。