打印本文 关闭窗口 | ||
C语言入门教程-内存地址来源于瑞达科技网 | ||
作者:佚名 文章来源:网络 点击数 更新时间:2011/1/18 文章录入:瑞达 责任编辑:瑞达科技 | ||
|
||
内存地址 如果您在计算机硬件的层面上理解了内存地址的原理,前面的讨论就会变得更加清晰了。您若还没有阅读过位和字节,那么现在应该去读一遍这篇文章,它会帮您弄清位、字节和字的概念。 所有计算机都配有内存,也称RAM(随机存取存储器)。比如您的计算机现在可能配有16、32或64兆字节的RAM。RAM用于存储计算机正在执行的程序以及程序使用的数据(即程序的变量和数据结构)。内存可以看作是一个简单的字节数组。在这个数组中,每个内存单元都有自己的地址:第一个字节的地址是0,后面依次是1、2、3,等等。内存地址相当于普通数组的下标。计算机可以随时访问内存的任何位置(所以称为“随机存取存储器”)。根据需要,多个字节可以组合起来构成较大的变量、数组和结构体。例如,一个浮点型变量占用4个连续字节的内存空间。您可以像下面这样在程序中声明一个全局变量: float f; 上面这条语句的意思是说:“声明一个名为f的可以保存一个浮点值的内存位置。”程序执行的时候,计算机就会在内存中某个位置为变量f预留空间。这个位置在内存空间中有确定的地址,如下图所示:
变量f在内存某处占用四个字节的空间。此位置有确定的地址,本例中是248,440。 您认为的变量f在计算机看来就是一个具体的内存地址(如248,440)。因此,当您写下这样的语句时: f=3.14;
编译器可能把它翻译成:“将数值3.14装入到内存地址是248,440的位置。”计算机总是通过操作地址和操作地址的值来使用内存的。 另外,计算机的这种使用内存的方式还会带来一些“副作用”。例如,您的程序包含了下面的代码: int i, s[4], t[4], u=0;
您很可能会看到这样的程序输出: s:t
t[0]和u的值为什么不对?仔细观察代码就会发现,两个for循环在访问数组时都越界了一个元素。在内存中,两个数组是相邻存储的,如下图所示:
因此,当向s[4]这个并不存在的数组元素写数据时,实际上覆盖了t[0],因为它正处于s[4]的位置上。当向t[4]写数据时,实际上就覆盖了u。对于计算机来说,s[4]只是一个可以写数据的内存位置而已。您会发现尽管计算机执行了程序,但程序却是不正确或不正常的。这个程序在运行时损坏了t 数组。执行下面的语句将会产生更加严重的后果: s[1000000]=5;
s[1000000] 这个位置很可能在程序的内存空间之外。也就是说,您向不属于您程序的内存空间写入数据。在具备存储空间保护的系统上(如UNIX和Windows 98/NT),这样的语句会使系统终止程序的执行。而在其他系统(如Windows 3.1和早期的Mac)会听任程序为所欲为。结果是另一个程序的代码或变量被破坏了。这种侵犯的后果小到不产生任何影响,大到导致彻底的系统崩溃。在内存中,变量i、s、t、u具有前后相邻的确定地址。因此,如果您对一个变量越界写入,计算机会照您说的做,但将破坏另一处内存位置的数据。 因为C和C++在访问数组元素时不做任何形式的边界检查,所以您作为一名程序员自己一定要严加注意数组边界,不要超越。对超越数组边界内容的无意读写总是会导致程序出现问题。 下面的代码是另一个例子: #include
这段代码告诉编译器打印p保存的地址和i占用的地址。变量p一开始是一个随意的数值或0。i的地址一般是一个很大的数字。例如,运行这段代码后得到的输出是: 0 2147478276
可知i的地址是2147478276。p=&i;这条语句执行之后,就保存了i的地址。再试试下面的代码: #include
这段代码告诉编译器打印p指向的值。然而p尚未初始化,它保存的地址是0或一个随机地址。多数情况下这将引发一个段错误(或某些其他运行时错误),表明您使用了一个指向无效内存空间的指针。段错误几乎总是由未初始化的指针或错误的内存地址导致的。 通过以上的介绍,现在我们可以从新的角度来理解指针了。请看下面的例子: #include
程序的运行过程是这样的:
变量i占4字节的内存。指针p也占4字节(在当今使用的多数计算机上,一个指针占4字节内存。现在大部分CPU的内存地址都是32位的,尽管64位寻址已渐成趋势)。i所代表的内存位置有一个确定的地址,本例中是248,440。执行过p=&i;后,指针p也将保存同样的地址。因此变量*p和i是等价的。 指针p原样保存着i的地址。当执行如下的语句时: printf("%d", p);
程序就会打印变量i的实际内存地址。 |
||
打印本文 关闭窗口 |