IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]C/C++静态数组与动态数组的区别

    bendanban发表于 2016-04-25 19:11:38
    love 0

    简介

    以下三行代码有什么区别?

    int a[10];
    int *a = (int*)malloc(sizeof(int)*10);
    int *a = new int[10];
    • 第一行代码定义a为包含10个int类型元素的整形数组。
    • 第二行和第三行分别使用的是C和C++来定义动态数组,他们的结果是相同的。a都可以表示为一个动态数组。

    我们可以使用a[1]来取数组a的第1个元素。那他们有什么区别呢?


    解释

    我们从指针开始说起。所谓指针,就是用来存放内存地址的一个变量,首先,指针是个变量;其次,指针存放的是内存地址。

    指针的定义中包含了一个重要的说明:指针中存放的内存地址处的内容应该如何解析。例如:int *a; 说明a是一个指针,他存放的地址处的数据被解析为一系列连续的int型数据。

    那int a[10],可以说明a是一个指针么?其实,这样说是不准确的。a其实本身就是一个内存地址。只是我们在实际运行之前并不知道他真正代表哪个地址。就像宏在编译的时候被替换成宏定义的内容,静态数组a实际上在执行的时候是被替换成真实的内存地址的。也就是说a已经是内存地址了,不是变量。

    那么对于int a[10] 和 int *b = new int[10],a[2]和b[2]有什么区别呢?

    1. a[2],b[2]在赋值符号=的右端的时候。此时表示取a[2]和b[2]的值。对于a[2],首先a代表的是个内存地址,在这个内存地址处偏移sizeof(int)*2个字节,取连续sizeof(int)个字节,并将其解析为int类型的数。对于b[2],首先b是一个指针,其值是一个内存地址,首先b这个变量在内存中的地址被找到,然后取连续的sizeof(int*)个字节,解析为一个内存地址,然后在这个地址处偏移sizeof(int)*2个字节,取连续sizeof(int)个字节,并将其解析为int类型的数。
    2. a[2],b[2]在赋值符号=的左端的时候。表示向相应的内存位置赋值。赋值符号右端的表达式的结果不管是什么类型的值,都会被默认强制类型转化为int型数据。对于a[2],a代表的是个内存地址,在这个内存地址处偏移sizeof(int)*2个字节,向连续的sizeof(int)个字节内存中写入赋值号右端的结果。对于b[2],首先b这个变量在内存中的地址被找到,然后取连续的sizeof(int*)个字节,解析为一个内存地址,然后在这个地址处偏移sizeof(int)*2个字节之后,向连续的sizeof(int)个字节内存中写入赋值号右端的结果。

    实验

    试验下前面讨论的内容:

    #include <stdio.h>
    #include <stdlib.h>
    #include <inttypes.h>
    int main(int argc, char** argv){
        int a[10];
        printf("%.16X\n", (uint64_t)(&a));
        printf("%.16X\n", (uint64_t)(a));
        int *b = new int[10];
        printf("%.16X\n", (uint64_t)(&b));
        printf("%.16X\n", (uint64_t)(b));
        delete[] b; b = NULL;
        return EXIT_SUCCESS;
    }

    某次执行结果:

    000000003093F838
    000000003093F838
    000000003093F878
    00000000309A8D90

    根据输出结果,可以推断,a和&a的值是相同的,说明a已经是地址了,取地址后还是原先的地址,所以两次地址是一样的。

    后两次输出结果不同,是应为b是一个指针,是变量,变量的地址与他存储的内存地址是不同的。



沪ICP备19023445号-2号
友情链接