C++内存中的字符指针与数组

这里我们来看一下字符串的存储
字符串str1,str2,str3,str4,str7;
整数:startAddress, n1
数组:str5,str6,以及p2
原程序如下

int main()
{
    printf("Hello world!\n");
    int startAddr = 0x12345678;
    int nn1 = 0x12005600;
    int nn2 = 0x00120056;

    char* str1 = "hello";
    //str1[2] = 'a';      //不能访问
    char* str2 = "it";
    //int* p1 = {1, 2, 3, 4};
    int p2[] = {4, 3, 2, 1};
    int n1 = 0x78654321;
    char* str3 = "";
    int n2 = 0x00120034;
    char* str4 = "he";

    char str5[] = {1, 2 , 3, 4};
    char str6[] = "hello";
    char* str7 = "llo";
    int n3 = 0x78005600;

    printf("n: %d, %d, %d\n", n1, n2, n3);
    printf("start address: %p\n", &startAddr);
    printf("str1 address: %p\n", str1);
    printf("str2 address: %p\n", str2);
    printf("str3 address: %p\n", str3);
    printf("str4 address: %p\n", str4);
    printf("str5 address: %p\n", str5);
    printf("str6 address: %p\n", str6);
    printf("str7 address: %p\n", str7);

    //printf("p1 address: %p\n", &(*p1);
    printf("p2 address: %p\n", &p2);

    printf("strlen str1: %d\n", strlen(str1) );
    printf("strlen str2: %d\n", strlen(str2) );
    printf("strlen str3: %d\n", strlen(str3) );
    printf("strlen str4: %d\n", strlen(str4) );
    printf("strlen str5: %d\n", strlen(str5) );
    return 0;
}

结果如下图,左侧打印了地址信息,右侧是地址。
在这里插入图片描述

从上图可以看出,
起始点的int数据用黑线标记,起始地址后的那些整数和指针以栈的形式从高字节0x0060feec处开始,逐个填入。
起点后蓝线标注整型数据,绿线标注字符串指针数据。
字符串指针仅仅只是存储了一个地址,比如0x00403044,它把这些字符串数据放在了数据区,而不是函数栈内。
字符数组是存储在栈内的,如起始点前面的蓝色部分数据,字符串数组“hello"与字符数组{1,2,3,4}
int整数数组也是存储在栈内,每个数据占据4个字节长度。
但是为什么它没按照我书写定义的顺序存储呢?
数组存储在最后面(低地址),原因是什么呢?被优化了?

最后我们来看看数据区
在这里插入图片描述

从对应的地址可以看出,数据区中的确存储了我们字符串指针指向的数据
除此之外,还可以发现,printf函数中传入的参数那些字符串也在数据区中。

扩展:
上述代码的汇编,以及自己的理解,仅供参考

0x00401334	push   %ebp
0x00401335	mov    %esp,%ebp
0x00401337	push   %edi
0x00401338	push   %esi
0x00401339	push   %ebx
0x0040133A	and    $0xfffffff0,%esp
0x0040133D	sub    $0x50,%esp
0x00401340	call   0x4165f0 <__main>

0x00401345	movl   $0x12345678,0x4c(%esp)   //int startAddr = 0x12345678;

0x0040134D	movl   $0x12005600,0x48(%esp)  //int nn1 = 0x12005600;
0x00401355	movl   $0x120056,0x44(%esp)    //int nn2 = 0x00120056;

0x0040135D	movl   $0x46e024,0x40(%esp)    //char* str1 = "hello";
0x00401365	movl   $0x46e02a,0x3c(%esp)    //char* str2 = "it";

0x0040136D	lea    0x14(%esp),%edx         //int p2[] = {4, 3, 2, 1};
0x00401371	mov    $0x46d000,%ebx
0x00401376	mov    $0x4,%eax
0x0040137B	mov    %edx,%edi
0x0040137D	mov    %ebx,%esi
0x0040137F	mov    %eax,%ecx
0x00401381	rep movsl %ds:(%esi),%es:(%edi)

0x00401383	movl   $0x78654321,0x38(%esp)  //int n1 = 0x78654321;

0x0040138B	movl   $0x46e02d,0x34(%esp)    //char* str3 = "";

0x00401393	movl   $0x120034,0x30(%esp)    //int n2 = 0x00120034;

0x0040139B	movl   $0x46e02e,0x2c(%esp)    //char* str4 = "he";

0x004013A3	movb   $0x1,0x10(%esp)        //char str5[] = {1, 2 , 3, 4};
0x004013A8	movb   $0x2,0x11(%esp)
0x004013AD	movb   $0x3,0x12(%esp)
0x004013B2	movb   $0x4,0x13(%esp)

0x004013B7	movl   $0x6c6c6568,0xa(%esp)  //char str6[] = "hello";
0x004013BF	movw   $0x6f,0xe(%esp)

0x004013C6	movl   $0x46e031,0x28(%esp)   //char* str7 = "llo";

0x004013CE	movl   $0x78005600,0x24(%esp)  //int n3 = 0x78005600;

0x004013D6	mov    $0x0,%eax           //return 0;

0x004013DB	lea    -0xc(%ebp),%esp
0x004013DE	pop    %ebx
0x004013DF	pop    %esi
0x004013E0	pop    %edi
0x004013E1	pop    %ebp
0x004013E2	ret

从中可以看到,首先对于数组,它与普通的数据并不存储在一起。

首先编译器应该知道main函数中数组占用空间大小len(sets)以及非数组成员的大小len(non)。通过len(sets)与len(non)的和确定main函数栈空间的大小,当碰到数组时,从len(non)的偏移往后分配空间。

最后,字符数组直接实现赋值,而对于int型数组,则是先将其值放在了数据区。最后从数据区复制到额外区

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值