一、存储方案
1)自动存储持续性:在函数定义中声明(包括函数参数)的存储持续性为自动的。在开始执行所属函数或代码块时被创建,执行完时被释放。
2)静态存储持续性:在函数定义外的变量和使用关键字static定义的变量。他们在整个运行过程中都存在。
3)线程存储持续性。
4)动态存储持续性:使用new或malloc分配的内存,又被称为自由存储(free store)或堆(heap)。
二、作用域和链接性
作用域:描述了名称在文件(翻译单元)的多大范围可见。
连接性:描述名称如何在不同单元间共享。
三、自动存储持续性
作用域为局部,没有链接性。
int main()
{
int i = 5; //main函数中可见
{
cout<< "hello\n";
int j = -9; //只在代码块中可见
int i = 7; //输出i等于7,隐藏了以前的定义
cout<< j << " " << i <<endl;
}
cout<< i <<endl; //i等于5
......
}
寄存器变量
关键字register:提高访问变量的速度。
在C++11中显示地指出变量时自动的,只能作用于原来就是自动的变量。
四、静态持续变量
1)外部链接性:可在其它文件中访问,必须带代码块外面声明。
2)内部连接性:只能在当前文件中访问,必须在代码块外面声明,并使用static限定符。
3)无连接性:只能在当前函数或代码块中访问,必须在代码块内声明,并使用static限定符。
以上三种都在整个程序执行期间存在。
...
int global = 100; //外部链接性
static int one_file = 200; //内部连接性
int main()
{
...
}
void funct(int n)
{
static int count = 123; //无链接性
int i = 0;
}
void funct2(int m)
{
...
}
静态变量的初始化:零初始化和常量初始化(意味着编译器处理文件时初始化变量,动态初始化意味着变量在编译后初始化)
int main()
{
int x; //零初始化
int y = 15; //常量初始化
long z = 13 * 13; //常量初始化
const double pi = 4.0 * atan(1.0); //动态初始化
}
//首先x、y、z、pi被零初始化。然后,编译器计算常量表达式,将y和z被初
//始化为5和169,但要初始化pi,必须调用函数atan(),需要等到该函数被
//链接且程序执行时。
五、静态持续性、外部链接性
外部变量(全局变量):连接性为外部的变量,作用于整个文件。
单定义规则(ODR):变量只能定义一次。C++提供两种变量声明。一种是定义声明简称“定义”,给变量分配存储空间,另外一种引用声明简称“声明”,不给变量分配存储空间,引用已有的变量。
引用声明使用关键字extern,且不进行初始化;否则,声明为定义,导致分配存储空间。
作用域解析运算符(::)。放在变量名前面时,表示该变量用的是全局版本。
六、静态持续性、内部链接性
将static限定符用于作用域为整个文件的变量时,该变量的连接性将为内部的。
//file1
int i = 20;
...
-------------------------------
//file2
static i = 30;
void froobish()
{
cout<< i <<endl; //uses i defined in file2
...
}
七静态存储持续性、无链接性
该变量值在定义的代码块中可用,但它在该代码块不处于活动状态时仍然存在。两次调用函数之间,静态局部变量的值保持不变。(静态变量适用于再生——将瑞士银行密码账号传递到下一个要去的地方)
#include<iostream>
using namespace std;
const int ArSize = 10;
void strcount(const char * str);
int main()
{
char input[ArSize];
char next;
cout<< "Enter a line:\n" ;
//一直读取,直到到达行尾或读取了ArSize-1个字符,把换行符留在队列中
cin.get(input, ArSize);
while(cin)
{
//读取输入后的字符,如果为换行符说明cin.get(input, ArSize)
//读取了整行,否则说明没有读取完
cin.get(next);
while(next != '\n') //丢弃余下的字符
cin.get(next);
strcount(input);
cout<< "Enter next line (empt line to quit):\n";
cin.get(input, ArSize);
}
cout<< "Bye\n";
return 0;
}
void strcount(const char * str)
{
static int total = 0; //静态变量(第一次调用时置为0,以后调用时为上次调用后保存的值)
int count = 0; //自动变量(每次被调用时都重新置为0)
cout<< "\"" << str <<"\" contains";
while(*str++)
count++;
total += count;
cout<< count << "characters\n";
cout<< total << " characters total\n";
}
八、函数和链接性
C/C++不允许在一个函数中定义另一个函数,因此所有函数的存储持续性都自动为静态的。默认情况下,函数的连接性为外部的,可以在文件间共享。实际上,函数原型可以使用关键字extern指出函数是在另一个文件中定义的。也可以使用关键字static将函数的连接性设置为内部的,只在一个文件中使用,必须原型和函数定义中使用该关键字:
static int private(double x);
...
...
...
static int private(double x)
{
...
}
九、存储方案和动态分配呢
动态内存:C++运算符new或C函数malloc()分配的内存
1)使用new运算符初始化:
int *pi = new int (6); //*pi set to 6
double *pi = new double (99.99); //*pi set to 99.99
//C++11
struct where {
double x;
double y;
double z;
};
where *pi = new where {12.23, 23.34, 34.45};
int * ar = new int [4] {2, 3, 4, 5};
int * pin = new int {6};
2)new失败时 :
引发异常std::bad_alloc.(以前为返回空指针)。
3)new:运算符、函数和替换函数
运算符new和new[]分别调用如下函数:
//分配函数
void * operator new(std::size_t);
void * operator delete(std::size_t);
void * operator new [] (std::size_t);
void * operator delete [] (std::size_t);
//std::size_t是一个typedef,对应合适的整形。
4)定位new运算符
指定要使用的位置。需要包含头文件#include.
#include<iostream>
#include<new>
using namespace std;
const int BUF = 512;
const int N = 5;
char buffer[BUF];
int main()
{
double *p1, *p2;
int i;
cout<< "Calling new and placement new:\n" <<endl;
p1 = new double[N]; //use heap
p2 = new (buffer) double[N]; //use buffer array
for(i = 0; i < N; i++)
p2[i] = p1[i] = 1000 + 20 * i;
cout<< "Memory addresses:\n" <<" heap: " << p1
<< " static: " << &buffer <<endl;
cout<< "Memory contents:\n";
for(i = 0; i < N; i++)
{
cout<< p1[i] << " at " << &p1[i] << "; ";
cout<< p2[i] << " at " << &p2[i] << endl;
}
cout<< "\nCalling new and placement new a second time:\n";
double *p3, *p4;
p3 = new double[N];
p4 = new (buffer) double[N];
for(i = 0; i < N; i++)
p4[i] = p3[i] = 1000 + 40 * i;
cout<< "Memory contents:\n";
for(i = 0; i < N; i++)
{
cout<< p3[i] << " at " << &p3[i] << "; ";
cout<< p4[i] << " at " << &p4[i] << " --- "
<< p2[i] << " at " << &p2[i] <<endl;
}
cout<< "\nCalling new and placement new a thrid time:\n";
delete [] p1;
//delete [] p2;
p1 = new double[N];
//从数组buffer开头算起的偏移量
p2 = new (buffer + N * sizeof(double)) double[N];
for(i = 0; i < N; i++)
p2[i] = p1[i] = 1000 + 60 * i;
cout<< "Memory contents:\n";
for(i = 0; i < N; i++)
{
cout<< p1[i] << " at " << &p1[i] << "; ";
cout<< p2[i] << " at " << &p2[i] << endl;
}
delete [] p1;
delete [] p3;
return 0;
}