作用域 :代码块、文件作用域;
连 接 :外部连接(extern)、内部连接(static)、空连接;
存储时期:静态存储时期、自动存储时期;
注:static表面的是连接类型,并非存储时期;文件作用域变量,不管何种连接,都是静态存储时期;
5种存储类型
存储类 | 存储时期 | 作用域 | 连接 | 声明方式 | 初始化 |
---|---|---|---|---|---|
自动 | 自动 | 代码块、函数头部 | 空 | 代码块内,关键字auto | 需要初始化 |
寄存器 | 自动 | 代码块 | 空 | 代码块内,关键字register | |
外部连接静态 | 静态 | 文件 | 外部 | 所有函数之外 | 自动赋初值0 |
内部连接静态 | 静态 | 文件 | 内部 | 所有函数之外,关键字static | 自动赋初值0 |
空连接静态 | 静态 | 代码块 | 空 | 代码块内,关键字static,作用域结束后不清空 |
存储类型说明符auto、static、register、extern、typedef:
auto:有意覆盖外部函数定义,或表明不能改变为其他存储类;只能在代码块作用域中使用;
static:对函数参数不能使用;例如:int move (static int flu); extern :
register:属于请求,而非命令;只能用于代码块作用域变量,但不能获取变量地址;
extern:变量在其他文件中定义,必须使用extern来声明变量;除了显示外部文件变量,还表明该函数或变量在其他地方已经定义过了;
外部变量定义和声明:
- 不同于自动变量,只能用常量表达式来初始化文件作用域变量;
- 一个外部变量只能进行一次初始化,而且必须是变量被定义时进行;
- 可以用extern 来再次声明任何文件作用域的变量,并不改变连接类型;
int avr1 = 1;
static int avr2 = 1;
int main()
{
extern int avr1; // 使用全局变量,可以被其他文件使用;
extern int avr2; // 使用全局变量,但仍属于内部连接;
....
}
分配内存:malloc()和free()
- malloc()可接收一个变量参数,匿名分配内存;可返回数组指针、结构指针等内存块的第一个字节地址;
- 若malloc()找不到所需空间,返回空指针;
double* ptr = (double*)malloc(30 * sizeof(double));
// ptr指向一个double类型值的指针;
// 跟new有什么区别?
free(ptr);
// 除了malloc()和calloc(),不能用free来释放其他方式分配的内存;
calloc()函数:
double* ptr = (double*)calloc(30, sizeof(double));
//第一个参数,内存单元数量;第二个参数,内存单元字节大小;
//与malloc()不同,它将块中全部位均置为0;
类型限定词:
const:
不能通过赋值、增量、加减运算来修改const变量值;
const float* pf; // pf指向常量浮点值;指向的值不能修改;
float* const pt; // pt是常量指针;指向地址不能变,但值能变;
float const* pt; // 同第一句,主要看const位于*的左边还是右边;
*Bjarne在他的The C++ Programming Language里面给出过一个助记的方法:
把一个声明从右向左读。
char * const cp; ( * 读成 pointer to )
cp is a const pointer to char
const char * p;
p is a pointer to const char;
volatile:
表明数据除了可被程序修改,还可通过其他方式修改;
restrict:
限定指针所指向的数据块只能有唯一访问途径;
课后习题
第2题:使用static文件作用域变量;
//main文件
int main()
{
int mode; // s_mode为static内部连接,所以同一变量尽量定为不同名称的;
// pe12-2a.cpp文件中,再将mian文件中的参数赋值给s_mode;
printf("Enter 0 for metric mode,1 for us mode:");
scanf("%d", &mode);
while (mode >= 0)
{
set_mode(mode);
get_info();
show_info();
printf("Enter 0 for metric mode,1 for US mode");
printf("(-1 to quit):");
scanf("%d", &mode);
}
printf("Done.\n");
return 0;
}
//pe12-2a.cpp文件
#include "stdafx.h"
#include "pe12-2a.h"
static int s_mode; // static类型参数命名时注意使用s_;
static double s_distance;
static double s_fuelamount;
// 判断计算模式;
void set_mode(int mode)
{
s_mode = mode;
if (s_mode == 0)
printf("you choose for metric mode.\n");
else if (s_mode == 1)
printf("you choose for US mode.\n");
else
printf("Invalid mode specified.Mode 1(US) used.\n");
}
// 获取参与计算的distance 、fuelamount;
void get_info()
{
if (s_mode == 0)
{
printf("Enter distance traveled in kilometers:");
get_double(&s_distance);
printf("Enter fuel consumed in liters:");
get_double(&s_fuelamount);
}
else
{
printf("Enter distance traveled in miles:");
get_double(&s_distance);
printf("Enter fuel consumed in gallon:");
get_double(&s_fuelamount);
}
}
// 显示计算结果
void show_info()
{
if (s_mode == 0)
{
printf("Fuel consumption is %.1lf liters per 100km.\n",
s_fuelamount / (s_distance /100));
}
else
{
printf("Fuel consumption is %.1lf miles per gallon.\n",
s_distance / s_fuelamount);
}
}
// 获取一个double类型值,注意使用double* 做参数;
void get_double(double* x)
{
while (scanf("%lf", x) != 1)
{
while (getchar() != '\n')
;
printf("please input the right number:\n");
}
}
第5题:产生100个1-10范围随机数;
// 产生随机数;
int* random_number(int count, int range)
{
srand((unsigned int) time(0)); // 以系统时间为种子,初始化rand();
int* ptr = (int*) malloc(count * sizeof(int)); // 注意free(ptr);
for (int i = 0; i < count; i++)
{
*ptr = rand() % range + 1;
//*ptr = 1 + (int)(10.0 * rand() / (range + 1.0));
printf("%d ", ptr[i]);
}
printf("\n");
return ptr;
}
// 降序排列数组内的元素
void sort_number(int *number_ptr, int num)
{
int top, seek, temp;
for (top = 0; top < num-1; top++)
{
for (seek = top + 1; seek < num; seek++)
{
if (number_ptr[top] - number_ptr[seek] < 0)
{
temp = number_ptr[top];
number_ptr[top] = number_ptr[seek];
number_ptr[seek] = temp;
}
}
}
}