进程内存分布
-
text 代码段:
存储的是二进制指令、常量(字符串字面值),该内存段的权限为只读,一旦强行修改就会产生段错误。
-
data 全局数据段:
里面存储着初始化过的全局变量、静态变量。
-
bss 静态数据段:
里面存储着末初始化过的全局变量、静态变量,该内存段在程序执行前会被初始化为0。
-
heap 堆:
由于程序员手动管理,该内存无法与标识符建立映射关系(无法取名字),必须与指针配合使用。
- 优点:够大,分配和释放可控。
- 缺点:使用麻烦,容易产生内存泄漏、内存碎片。
-
stack 栈:
由系统自动管理,随着函数被调用,会自动分配内存,函数执行结束后自动释放内存。
- 优点:使用方便,采用栈结构方式管理安全,不会产生内存泄漏、内存碎片。
- 缺点:大小有限,一次使用过多可能会产生段错误,分配和释放不可控不适合长期保存数据。
示例 ps:stack作用见后页
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
int data_glocal = 2333; //初始化的全局变量,存储于data中;
int bss_glocal; //未初始化的全局变量,存储于bss中,默认会被初始化为0;
static void func(void); //用于限制函数func的作用范围:只在本文件中使用。
//可防止函数、全局变量重名、防止被人调用。
void main(void)
{
static int data_local = 2333; //初始化的静态局部变量,存储于data中;
static int bss_local; //未初始化的静态局部变量,存储于bss中,默认会被初始化为0;
int stack_local_0 = 2333; //初始化的局部变量,储存于stack中
int stack_local_1; //未初始化的局部变量,储存于stack中,数值随机。
int n = 9; //随便设定一个值
int *heap_arr_n = malloc(sizeof(int)*n);//向系统申请n个int字节的内存空间,存放于heap中。
printf("----全局变量-----\n");
printf("定义数值: data_glocal = %d\n",data_glocal);
printf("未定义数值: bss_g1ocal = %d\n",bss_glocal);
printf("----局部变量-----\n");
printf("定义数值的静态: data_local = %d\n",data_local);
printf("未定义数值的静态: bss_local = %d\n",bss_local);
printf("定义数值的变量: stack_local_0 = %d\n",stack_local_0);
printf("未定义数值的变量: stack_local_1 = %d\n",stack_local_1);
}
类型限定符
-
auto
用于定义自动申请、自动释放的变量(局部变量),不加代表了加。
- 不能用于修饰全局变量
-
const (常数)
显示地"保护"变量不被修改
但是,如果要强制修改还是可以修改的(通过指针,对变量修改)
如果对初始化过的全局变量,用const修饰后,存储位置从data变成了text -
extern (外部的)
声明外部的全局变量,声明的变量已在别处定义过,请放心使用
但是只能临时通过编译,如果没有定义,链接时依然会报错
只是声明变量,不能赋值 -
static (静态的)
被static修饰过的变量称为静态局部变量,局部全局变量
改变存储位置:
改变局部变量的存储位置,由stack改data或者bss(由是否初始化决定)
延长生命周期:
延长局部变量的生命周期
限制作用范围:
限制全局变量、函数只能在本文件内使用
可以防止函数、全局变量重名、防止被别人调用 -
register (寄存器)
申请把变量的存储介质由内存转移到寄存器存储,如果能成功,数据的读取速度会大幅提升,寄存器数量有限,申请可能失败- 存储介质:
硬盘->内存->高速缓存->寄存器->CPU
- 存储介质:
-
volatile (不稳定的)
-
编译器每次读取 volatile 定义的变量时,都从内存地址处重新取值。
编译器的取值优化:
变量的值没有发生改变时,后续的取值会进行优化,不再去内存中读取,而是使用第一次读取的结果,可以节约时间
示例
#include <stdio.h>
/******************
extern Ex_global; //声明外部的全局变量,声明的变量已在别处文件定义过,避免报错。
*****************/
/**************************************************
测试const功能函数
**************************************************/
const int Num_text = 0; //如果对初始化过的全局变量,用const修饰后,存储位置从data变成了text
int *Num_text_p = &Num_text; //声明对象为num_text的指针,对num_text进行测试
void func_const(void)
{
const int num_0 = 0;
int* num_0_p = &num_0; //声明对象为const num_0的指针,测试可否改变其值;
int num = 0;
const int *num_p1 = # //声明对象为num的指针。const保护其值不能改变
int* const num_p2 = # //声明对象为num的指针。const保护其指向地址不能改变
const int* const num_p3 = # //声明对象为num的指针。const保护其值与指向地址不能改变。
/***********编辑想改变的变量或者指针,进行测试。**********/
/**示例**/
printf("num_0 = %d\n",num_0);
// num_0++; //不能修改
(*num_0_p)++; //可以修改num_0的值
printf("num_0 = %d\n",num_0);
printf("num_text = %d\n",Num_text);
// Num_text++;
(*Num_text_p)++; //出现段错误:修改只读空间text的值
printf("num_text = %d\n",Num_text);
}
/**********************************
测试static功能函数
**********************************/
void func_static(void)
{
for(int i=1;i<=10;i++)
{
static int f=1;
f=f*2;
printf("%d\n",f);
}
}
/********************************
测试volatile
********************************/
void func_volatile(void)
{
volatile int i=10;
int arr_i[1000] = {};
for(int j = 0;j<1000;j++)
{
arr_i[j] = i;
printf("arr_i[%d] = %d\n",j,arr_i[j]);
}
}
void main(void)
{
func_volatile();
func_static();
func_const();
}