数组名、指针和地址

首先看这个:

#include <stdio.h>
#include <iostream>
using namespace std;

int main() {
    int a[2] = {1, 2};
    cout << "The address of int_array: " << endl;
    cout << a << " " << &a << endl << endl;
    
    double b[2] = {1.2, 1.3};
    cout << "The address of double_array: " << endl;
    cout << b << " " << &b << endl << endl;
    
    char c[2] = {'a', 'b'};
    cout << "The address of char_array: " << endl;
    cout << c << " " << &c << endl << endl;
    
    int d[5] = {1, 2, 3, 4, 5};
    int dd[5] = {6, 7, 8, 9, 0};
    int j = 2, k = 1, i = 3;
    cout << d[i] << " " << i[d] << endl << endl;
    //this code is so strange, but in fact, d[i] = *(d + i) = *(i + d) = i[d].
    return 0;
}

这里发现,a和&a好像是一样的,还有char类型的怎么就不一样?

首先是关于a和&a:
#include <stdio.h>
int main() {
    int a[5] = {1, 2, 3, 4, 5};
    printf("a = %p\n", a);
    printf("&a = %p\n", &a);
    printf("a + 1 = %p\n", a + 1);
    printf("&a + 1 = %p\n", &a + 1);
    return 0;
}

显然,a是数组第一个元素的地址,而&a指的是整个数组(两者长度根本不同)

后来自己写了些东西:
#include <iostream>
using namespace std;

int main() {
    int a[5] = {305210130, 1164203589, 2023197048, 4, 5};//前三个数字在十六进制中表示分别是12312312、45645645、78978978,这样写主要为了测试方便
    int *ptr1 = (int *)(&a + 1);
    int *ptr2 = (int *)((int)a + 1);
    
    for (int i = 0; i < 20; i++) {//01
        cout << hex << *(int *)((int)a + i) << dec << ' ';
    }
    cout << endl << endl;
    
    
    cout << "&a + 1 : " << &a + 1 << endl;//02
    cout << "*(&a + 1) : " << *(&a + 1) << endl;//03
    cout << "**(&a + 1) : " << **(&a + 1) << endl;//04
    cout << "*(a + 5) : " << *(a + 5) << endl;//05
    cout << "(int *)(&a + 1) : " << (int *)(&a + 1) << endl;//06
    cout << "*((int *)(&a + 1)) : " << *((int *)(&a + 1))<< endl;//07
    cout << "*ptr1 : " << *ptr1 << endl;//08
    cout << "ptr1 : " << ptr1 << endl;//09
    cout << "ptr1[-1] : " << ptr1[-1] << endl;//10
    cout << "ptr1[-5] : " << ptr1[-5] << endl;//11
    cout << "(int)a : " << (int)a << endl;//12
    cout << "(int)a + 1 : " << (int)a + 1 << endl;//13
    cout << "(int *)((int)a + 1) : " << (int *)((int)a + 1) << endl;//14
    cout << "the address of a's first element : " << a << endl;//15
    cout << "*ptr2 : " << *ptr2 << endl;//16
    cout << "ptr2 : " << ptr2 << endl;//17
    cout << "the hex of *ptr2(*ptr2 = (int *)((int)a + 1)) : " << hex << *ptr2 << dec << endl;//18
    ptr2 = (int *)((int)a + 3);//19
    cout << "the hex of *ptr2(*ptr2 = (int *)((int)a + 3)) : " << hex << *ptr2 << dec << endl;//20
    
    return 0;
}

 现在来试着解释一下,解释点对应代码中的注释序号:
01、
这篇博客里对数据的储存做了很好地说明,可以解释这一点
我的电脑用的显然是Little Endian,这么一来,
实际数据为:(十六进制下)
12 31 23 12 45 64 56 45 78 97 89 78 00 00 00 04 00 00 00 05
内存中的数据应为:(第一行是标号,第二行是数据,同样在16进制下)
0x22ff————2d 2e 2f  30 31  32 33 34  35  36 37 38 39 3a 3b 3c 3d 3e 3f  40 41 42 43 44
                          12 23 31 12 45  56  64 45 78  89 97 78 04 00 00 00 05 00 00 00 ?? ?? ?? ??
另外一点要了解的是, *(int *)((int)a + i)的意思,(int)a将a的地址转化成int类型(注释12), 然后(int)a + 1是地址加一,这个一是真正的一,不按照int的大小加四(注释13), (int *)((int)a + i)再将int类型的地址转化为指向int的地址(也就是16进制),也就是0x22ff31(注释14),最后取内容。
那么输出结果也就明白了:
0x22ff30:  12312312
0x22ff31:  45123123
0x22ff31:  56451231
.
.
.
注意高位的零被省略了:
0x22ff3a:  00047897——>47897

02、
这里指出了&a的含义:依然是数组的地址(特殊的地址),但是表示了长度,所以后面的加一直接加上了一个数组的长度(也就是20, 转化为十六进制就是14),输出就是0x22ff30 + 14;

03、这里就说明了02中&a的特殊性,相当于自己指向自己?所以取内容仍然是自己;

04、取两次,取第一次是地址,再来一次是地址上的内容;

05、这里是为了验证04的正确性;

06到11都是对上述的实验,注意ptr1的类型决定了地址偏移的大小(-1就是-1个int长度);

12到15还行吧,不太难;

16、这个时候ptr2的地址是0x22ff31那么由01中的解释,*ptr2就是45123123,转化为十进制就是1158820131;

17、16中已讲到;

剩下的几个就是对01的验证了。

注意到这么一道题:

这么一来就没什么问题了,&a + 1指的是数组最后一位的下一个地址,而ptr1[-1] = *(ptr1 + (-1)),也就是数组最后一位,内容是5;
而这个时候的数组值为:(注意进制)
00 00 00 01 00 00 00 02 00 00 。。。
在内存中:(注意进制)
01 00 00 00 02 00 00 00 03 00 。。。
这样一来a的地址对应的是上面的第三个00,转化为int,加一(真正的一),也就是第三个00的下一个——02,再将它转化为指向int的,也就是00 00 00 02,真实值(16进制)02000000,也就是2000000。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值