单独编译
大工程不可能只有一个.c文件。
原来程序可以分成三个部分-分成的几部分拼接成翻译单元进行编译。
- 头文件,包含结构声明和使用这些结构的函数原型
函数原型、使用define定义或者是const定义的符号常量、结构声明、类声明、模板声明、内联函数。声明不会产生变量开辟内存,所以可以放在头文件,且内联函数不声明函数,此外,头文件不可以出现定义,因为在调用过程中不确定头文件内容,但又在main函数中重新定义则出现错误,不可以在..cpp文件中包含.cpp.因为可能出现大量重复定义。
函数的定义除了内联函数外都不要放在头文件中。
- 源代码文件:包含与结构相关的函数的代码
- 源代码文件:包含调用与结构相关的函数的代码。
预处理器编译器指令
#ifndef
#define
#endif
示例代码
#include<iostream>
#include<cmath>
using namespace std;
struct polar
{
double distance;
double angle;
};
struct rect
{
double x;
double y;
};
polar rect_to_polar(rect xypos);
void show_polar(polar dapos);
int main()
{
rect rplace;
polar pplace;
cout << "enter the x and y values";
while (cin >> rplace.x >> rplace.y)
{
pplace = rect_to_polar(rplace);
show_polar(pplace);
cout << "next two numbers(q to quit)";
}
cout << "done";
system("pause");
return 0;
}
polar rect_to_polar(rect xypos)
{
polar answer;
answer.distance = sqrt(xypos.x * xypos.x + xypos.y * xypos.y);
answer.angle = atan2(xypos.y, xypos.x);
return answer;
}void show_polar(polar dapos)
{
const double rad_to_deg = 57.29577951;
cout << "distance=" << dapos.distance;
cout << ",angle=" << dapos.angle * rad_to_deg;
cout << "degrees\n";
}
存储持续性、作用域、连接性
变量在不同的空间作用域不同且存活的时间不同,c++中使用三种方案来保存数据,这些方案的区别是数据保留的时间。
作用域:在什么范围能看到这种变量。生命周期
代码在内存空间中作用的长短
- 自动存储持续性
在函数定义中声明的变量(自动变量),存储持续性为自动的,它们在程序开始执行代码块或者其所属的函数时被创建,在执行完内存被释放,自身操作不需要程序员控制。
- 静态存储持续性
全局变量和使用static定义的变量,变量在整个程序运行都存在。
- 线程存储持续性(c++11)
- 动态存储持续性
用new分配的的内存一直存在,直到使用delete运算符将其释放给或程序结束为止。
作用域:无论是什么生命周期的变量,它都可以叫做作用域。编译器将三个文件组成翻译单元。
链接性:变量链接是外部链接时,则别的翻译单元也可以调用这个函数。自动变量的名称没有链接性,因为它们不能共享,它们只作用于当前的局部变量,连翻译单元的其他部分都无法调用。
注:函数原型作用域只能在函数的参数列表可用。
自动变量和栈
自动变量都是在栈,栈和堆都是内存开辟出来的,栈运行的速率比堆高,栈只需要一条cpu指令1就可完成工作。
栈:自动变量的数目随函数的开始和结束而递减的因此程序必须在运行中对自动变量进行管理,常用的方法是留一段内存,并且将其视为栈。(栈后进先出)使用两个指针跟踪栈,一个顶一个底。类似堆书。
当函数被调用时,自动变量被加入到栈中,栈顶指针指向变量后面的下一个可用单元,函数结束时栈顶指针被重置为被调用前的值。但是不会处理掉内存中的值,变量是直接往上覆盖。
栈并不是连续的内存空间,因为要防止溢出。
注:不可以将指针和引用作为局部变量。
#include<iostream>
using namespace std;
int* func()
{
int a = 20;
int* p = &a;
cout << p << endl;
return p;
}
int main()//说明指针和引用尽量不要使用局部作用。
{
int* b = func();
cout << b << endl;
cout << *b << endl;//因为是指针移动,但是栈中的内容是没有被删除的,所以*b返回的不一定是a,地址一直存在但是值是不确定的
system("pause");
return 0;
}