大学时候没好好学,导致实际用诸如char *a[]的时候,畏畏缩缩的,含泪花了1整体系统地复习了一下,记录一下学习心得。
问题1:如果定义了一个字符指针char *a,问系统到底因为这句话,分配了多大的空间?
对于涉及不到底层的同学,可能一辈子都不会考虑这个问题,而堆或者栈,一旦硬件大小确定了,它的空间就定死了,你每定义一个变量,这块空间就要划出相应的大小,甚至略大于这个大小(地址对齐),用来分配给你定义的变量。有时候我就比较好奇,系统到底分配了多大给我定义的变量。
以前没学好,一直以为分配了char的大小,就一个byte的大小,结果现在知道了,对于指针来说,指针分配空间是一个int的空间大小,即sizeof(int),不同环境下这个值是不一样的,我这里就默认int是32位,即4个bytes了。而带来的问题是,我用char定义了一个指针,分配的是32位地址,那我这个char又是干什么用的?我的理解是,可以想象成偏移地址,即需要连续读取的长度。举例说明一下:
如上图,如果a = 0x01,那么*a = 2,相当于寻址时,a代表了我要寻找的起始地址,而char决定了我的从这个起始地址开始要寻找的长度,由于char占用1个byte,即len为1,于是得到结果*a = 2。类比一下,如果我定义的是int *a,然后a = 0x01,那么*a会是多少了?再来类比分析一下,a=0x01,那么起始地址是0x01,那么我要连续读多少位呢?一个int的大小,即32位,4个bytes,那么0x01~0x04这4位都将被寻址到。对于小端设备,*a = 0x05040302。
所以说,对于char *a问题,其实系统给你分配的地址大小为一个指针的大小,而前面的char只是用来寻址的偏移量,跟系统分配空间没有关系。
问题2:char *a = "i love currant",这期间系统分配了多大空间?
虽然这只有一句话,但是系统却做了3件事情:
1.首先在常量区,释放了14个bytes的空间,用来存"i love currant",并且为了区分中止,自动在结尾释放了一个1byte放‘\0’,所以常量区就消耗了至少15个btyes;
2.定义了一个指针a,释放了一个指针的大小,即4个bytes;
3.将a 等于 "i love currant"这句话的首地址,即a指向这句话的首地址。
由问题2引申3个问题:
问题2.1:如果char b = a[2],b等于多少?
a指向"i love currant"的首地址,即i的地址,偏移2位,所以b = ‘l’;
问题2.2:可以a[2] = 'p'吗?
不可以,指针a指向的是常量区,常量区的内容只读,不写。
问题2.3:怎么才能实现a[2] = 'p'?
从定义初下手,定义char a[] = "i love currant",那么a[2] = 'p'合法,操作以后字符串变成了"i pove currant"
再由问题2.3引申问题3:
问题3:char *a = "i love currant"和char a[] = "i love currant",sizeof(a),结果一样吗?
不一样。这两个申请空间的过程完全不同。
char *a = "i love currant",仅对a来说,系统只给a分配了一个指针大小的空间,即4个bytes,而存"i love currant"的地方在常量区,虽然sizeof(a)=4,但其实总系统消耗量可不止4。
char a[] = "i love currant",这其实是数组的一种初始化方式,系统不知道这个数组要分配空间到底多大,于是先计算放"i love currant"需要多大,总共14个字符,所以是14bytes,但是别忘了,字符需要一个'\0'在内存里跟别人隔开,中止区分,所以先算出存"i love currant"需要15个bytes,于是给数组a开辟了15个bytes的空间大小,然后将"i love currant"+'\0'放到开辟的空间里。所以这里的sizeof(a) = 15。你以为这就完了?不,a既是变量名,也是首地址,所以还是需要留一个指针的大小,存让a本身存下字符串首指针。
以上就是我自我学习的理解,不一定全对,有问题还请相互指教。