C++

C/C++内存分区模型

2018-03-31  本文已影响11人  温暖春阳
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>


//extern int a = 10; 默认外部链接
int a = 10; //全局区
//静态全局变量是内部链接
static int b = 20; //静态区

//内部链接和外部链接有什么区别?
//1. 如果变量是内部链接的话,那么此变量只能在当前文件内访问
//2. 如果是变量是外部链接的话,那么此变量可以被其他文件使用


//1. 全局静态变量和局部静态变量都存储在静态区,都是在程序运行期间都是合法有效
//2. 局部静态变量符号的可见范围仅限于当前函数内部,全局静态变量可见范围从定义到文件结尾

//头文件不要放定义,只能放声明

void test01()
{
    static int c = 30; //静态区
}

//头文件不参与编译,每一个.c文件,我们叫做一个编译单元
//编译器独立编译每一个.c文件
void test02()
{
    //声明,表示告诉编译器这个符号是存在的,你让我先编译通过,让连接器去找到底这个符号在那
    extern int g_a;

    printf("g_a = %d\n", g_a);
}


//--------------------------------------
//常量区 字符串常量 全局const变量


//1. const全局和局部变量区别?
//const全局变量在常量区,不能修改(直接或者间接)
const int g_c = 100;
void test03()
{
    //直接修改不行
    //g_c = 200;

    //间接修改也不行
    int *p = (int *)&g_c;
    *p = 200;

    //全局const放在常量区,一旦初始化,不能修改
}

//2. const局部变量
void test04()
{
    //栈上
    const int a = 100;
    //a = 200;

    int *p = (int *)&a;
    *p = 200;

    printf("a = %d\n", a);

}


void test05()
{
    //"hello world!" char*类型字符串
#if 0
    char *p = "hello world!";

    printf("%d\n", &"hello world!");
    printf("%d\n", p);


    printf("p = %s\n", p);
    p[0] = 'A';
    printf("p = %s\n", p);

#endif

    char *p1 = "hello world!";
    char *p2 = "hello world!";

    printf("p1 = %d\n", p1);
    printf("p2 = %d\n", p2);
}





int main(){

    //test04();
    test05();

    system("pause");
    return EXIT_SUCCESS;
}

全局静态区内的变量在编译阶段已经分配好内存空间并初始化。这块内存在程序运行期间一直存在,它主要存储全局变量、静态变量和常量。

注意:
  1. 这里不区分初始化和未初始化的数据区,是因为静态存储区内的变量若不显示初始化,则编译器会自动以默认的方式进行初始化,即静态存储区内不存在未初始化的变量。
  2. 全局静态存储区内的常量分为常变量和字符串常量,一经初始化,不可修改。静态存储内的常变量是全局变量,与局部常变量不同,区别在于局部常变量存放于栈,实际可间接通过指针或者引用进行修改,而全局常变量存放于静态常量区则不可以间接修改。
  3. 字符串常量存储在全局/静态存储区的常量区。
    示例代码:
int v1 = 10;//全局/静态区
const int v2 = 20; //常量,一旦初始化,不可修改
static int v3 = 20; //全局/静态区
char *p1; //全局/静态区,编译器默认初始化为NULL

//那么全局static int 和 全局int变量有什么区别?

void test()
{
    static int v4 = 20; //全局/静态区
}

加深理解:

char* func()
{
    static char arr[] = "hello world!"; //在静态区存储 可读可写
    arr[2] = 'c';
    char* p = "hello world!"; //全局/静态区-字符串常量区 
    //p[2] = 'c'; //只读,不可修改 
    printf("%d\n",arr);
    printf("%d\n",p);
    printf("%s\n", arr);
    return arr;
}
void test()
{
    char* p = func();
    printf("%s\n",p);
}

字符串常量是否可修改?字符串常量优化:

ANSI C中规定:修改字符串常量,结果是未定义的。
ANSI C并没有规定编译器的实现者对字符串的处理,例如:

  1. 有些编译器可修改字符串常量,有些编译器则不可修改字符串常量。
  2. 有些编译器把多个相同的字符串常量看成一个(这种优化可能出现在字符串常量中,节省空间),有些则不进行此优化。如果进行优化,则可能导致修改一个字符串常量导致另外的字符串常量也发生变化,结果不可知。
所以尽量不要去修改字符串常量!

总结

在理解C/C++内存分区时,常会碰到如下术语:数据区,堆,栈,静态区,常量区,全局区,字符串常量区,文字常量区,代码区等等,初学者被搞得云里雾里。在这里,尝试捋清楚以上分区的关系。

数据区包括:堆,栈,全局/静态存储区。

代码区:存放程序编译后的二进制代码,不可寻址区。

可以说,C/C++内存分区其实只有两个,即代码区和数据区。

上一篇下一篇

猜你喜欢

热点阅读