字符指针与字符数组真正的区别
先看一个示例
#include <stdio.h>int mainchar *= "hello"char = "hello""p: %s\n""q: %s\n"return 0#include <stdio.h>int mainchar *= "hello"char = "hello"0= 's'0= 's'return 0所有的Linux进程的虚拟内存空间都是以这种方式组织的,只不过不同进程因为映射表不同,所以 同一虚拟地址对应不同的物理地址。如果进程需要共享一块内存区,只需要在映射表中把同一虚拟内存 地址映射到相同物理地址就可以了,比如上图中的Kernel virutal memory区域,这个区域是操作系统 内核的代码,所有进程都需要共享,所以操作系统就可以把所有进程的这一区域映射到相同物理地址处。
上图的下半部分是Process virtual memory,代码进程使用的虚拟内存空间,可以看出他们被分成了 几个块,这些块代表了程序使用内存的不同方式。我们先来看一段代码,并结合上图说明一下程序使用 内存的不同方式。
示例3
#include <stdio.h>#include <stdlib.h>int mainchar *= "hello"char = "world"char *= char *sizeofchar*60= 's'0= 's'0= 's'"p is:%s""q is:%s""r is:%s"return 0.file "tcharp.c" .section .rodata.string "hello".string "p is:%s".string "q is:%s".string "r is:%s" .text .globl main .type main@function# char *p = "hello" movl $.LC028%esp# char q[] = "world" movl $181943896738%espmovw $10042%esp# char *r = (char *)malloc(sizeof(char)*6) movl $6%espcall malloc movl %eax32%esp# p[0] = 's' movl 28%esp%eax movb $115%eax# q[0] = 's' movb $11538%esp# r[0] = 's' movl 32%esp%eax movb $115%eaxmovl $.LC1%eax movl 28%esp%edx # save p movl %edx4%espmovl %eax%espcall printf movl $.LC2%eax leal 38%esp%edx # save q movl %edx4%espmovl %eax%espcall printf movl $.LC3%eax movl 32%esp%edx # save r movl %edx4%espmovl %eax%espcall printf从上述汇编代码可以看出p,q,r三种使用内存的方式。从初始化上看, p指向的"hello",初始化时,直接指向了一个固定的位置,这意味着代码执行的时候, 这个位置已经有数据了。q指向的"world",初始化是由代码完成的,你把"world"经ASCII码转化成数字形式, 对比一下就会发现,那两个数字,1819438967,100,对应的就是"world"。而r的初始化,是调用malloc得到的。
从这段汇编代码。我们从直觉上会感觉到这三种使用内存方式的不同,接下来,我们再来看一下Linux运行时存储器映像。
.text 段放着已经编译的程序机器代码。
.rodata 段放着只读数据,printf函数参数中的字符串,p指向的"hello", 都在这存着。正因为这个段是只读的,所以不能修改,代码0= 's'执行时就会出现段错误。
.data 段放着已经初始化的全局变量,.bss 段变着没有初始化的全局变量。
再往上是 Run-time heap, 我们用malloc分配的内存空间都在这一段。
接着是User Stack,程序中的局部变量都在这一段,我们q指向的"world"就存储在这里。 从图中也可以看到,%esp指向栈顶,再回头看一下汇编代码,你可能就明白之前相对于(%esp)地址所做的操作意味着什么。这里特别要区分 地址与数据 。
p,q,r是局部变量,它们的值都是地址,这个地址作为局部变量的值,在User Stack里存储。
p表示的地址指向数据"hello",这是不可变量,在.rodata段中存储。q表示的地址指向的数据"world",作为局部变量的数据,在User Stack段存储。 r表示的地址指向的数据,在Run-time heap中存储。为了验证我们的想法,我们做一个实验,把p,q,r三者地址打印出来, 再把三者指向的数据的地址打印出来。 然后查看内存分配。
示例4
#include <stdio.h>#include <stdlib.h>int mainchar *= "hello"char = "world"char *= char *sizeofchar*6int "addr of p:%p\n"&"addr of q:%p\n"&"addr of r:%p\n"&"addr of p's data:%p\n""addr of q's data:%p\n""addr of r's data:%p\n""%d\n"&return 0文后的话从上面的过程可以看出,要想真正理解C语言,你需要了解汇编,需要了解操作系统, 而Linux提供了一系列工具,方便你探索整个系统的运行机制。如果你也想了解它, 请开始使用它。
还是那句话。既然看起来不错,为什么不试试呢?
文中图片均来自《深入理解计算机系统》一书。
转载请注明出处: http://blog.csdn.net/on_1y/article/details/13030439
- 1楼liyongming1982昨天 22:08
- 很详细,尤其是细节部分,谢谢分享