C语言编程常见问题解答之指针和内存分配

C语言编程常见问题解答之指针和内存分配,第1张

C语言编程常见问题解答之指针和内存分配,第2张

它为指针C编程提供了强有力的支持——如果你能正确灵活地使用指针,就可以直接切入问题的核心,或者把程序分割成小块。善用指针的程序会非常高效、简洁、精炼。
使用指针,您可以将数据写入内存中的任何位置。但是,一旦你的程序中出现“野”指针,也就是指向错误位置的指针,你的数据就有危险了——存储在堆中的数据可能被破坏,用于管理堆的数据结构可能被破坏,甚至操作系统的数据也可能被修改。有时候,以上三种损害。
之后可能会发生什么取决于两件事:一是内存中的数据损坏的程度;第二,内存损坏的部分会用多少次?在某些情况下,某些函数(可能是内存分配函数、自定义函数或标准库函数)不会立即(或稍后)正常工作。在其他情况下,程序可能会停止运行并报告错误消息。或者程序可能会挂起;或者程序可能陷入无限循环;或者程序可能产生错误的结果;或者看起来程序还在正常运行,因为程序并没有被本质破坏。
值得注意的是,即使程序出现了根本性的错误,也有可能程序运行很长时间,然后出现明显的性能异常;或者说,调试时程序运行完美,只有用户使用时才会出现异常。
在C语言程序中,任何通配符指针或越界数组下标都可能导致系统崩溃。两次释放内存的操作也会导致这种结果。你可能见过一些C程序员写的程序中的严重错误。现在你可以知道一些原因了。
一些内存分配工具可以帮助你发现内存分配中的问题,比如漏洞(leak,见7.21)、释放一个指针两次、野指针、下标越界等等。但是这些工具并不通用。它们只能在特定的操作系统中使用,甚至只能在特定版本的编译器中使用。如果你找到了这样的工具,那就试试吧,因为它可以节省你很多时间,提高你软件的质量。
指针的算术运算是C语言(及其衍生语言,如C++)特有的功能。汇编语言允许你对地址进行操作,但是这个操作不涉及数据类型。大多数高级语言根本不允许你用指针做任何事情。你只能看到指针指向的地方。
C指针的算术运算和街道地址类似。假设你住在一个城市,每个街区的所有街道都有地址。街道的一边用连续的偶数作为地址,另一边用连续的奇数作为地址。如果你想知道河路158号北边第五栋房子的地址..街,你不会加158和5,去163;你会先把5(你要数前面的5栋房子)乘以2(每栋房子之间的地址间距),然后加到158,去River Rd..街道。同样,如果一个指针指向地址158(十进制数)中的一个两字节的短整型值,那么在指针上加3=5,结果将是一个指向地址168(十进制数)中的短整型值的指针(指针加减操作的详细描述见7.7和7.8)。
街道地址的操作只能在特定的街区进行。同样,指针的算术运算只能在特定的数组中进行。实际上,这不是一个限制,因为指针的算术运算只有在特定数组中执行才有意义。对于指针的算术运算,数组不一定是数组变量。例如,函数malloc()或calloc()的返回值是一个指针,它指向堆中应用的数组。
指针的描述看起来有点混乱。请看下面的例子:
char * p;
上面例子中的描述表明p是一个字符。符号“*”是指针运算符,也称为间接引用运算符。当一个程序间接引用一个指针时,它实际上指的是指针所指向的数据。
在大多数计算机中,只有一个指针,但在某些计算机中,指向数据和函数的指针可以不同,也可以指向字节(如char。和void *指针)和指向该单词的指针可能不同。这对sizeof运算符没有影响。但是,有些C程序或程序员认为任何指针都会被存储为int值,或者至少是long值,这是无法保证的,尤其是在IBM PC兼容的计算机上。

注意:以下讨论与Macintosh或UNIX程序员无关;

原IBM PC兼容机使用的处理器不能有效地处理16位以上的指针(这个结论还有争议。16位指针是偏移量,见9.3中基址和偏移量的讨论)。虽然最初的IBM PC最终可以使用20位指针,但这需要很大的麻烦。因此,从一开始,各种基于IBM兼容机的软件就试图突破这一限制。
为了让20位指针指向数据,您需要指示编译器使用正确的存储模式,例如压缩存储模式。在中等存储模式下,可以用20位指针指向该函数。在Yamato-Giant存储模式下,一个20位的指针可以同时指向数据和函数。在任何存储模式下,你可能需要使用远指针(见7.18和7.19)。
基于286的系统可以突破20位指针的限制,但实现起来有些困难。自386年以来,IBM兼容计算机已经能够使用真正的32位地址。比如一些操作系统像MS-Windows和OS/2已经实现了这一点,但是MS-DOS还没有实现。
如果您的MS-DOS程序用完了基本内存,您可能需要从扩展内存或扩展内存中分配更多的内存。很多版本的编译器和函数库都提供了这种技术,但是各不相同。这些技术基本不具备通用性。其中有些可以在大多数MS-DOS和MS-WindowsC编译器中使用,有些只能在少数特定编译器中使用,有些只能在特定附加函数库的支持下使用。如果您手头有可以提供这项技术的软件,请查看它的文档以获得更详细的信息。
7.1什么是间接引用?
对于所解释的变量,变量名是对变量值的直接引用。对于指向变量或内存中任何对象的指针,指针是对对象值的间接引用。如果p是指针,p的值就是其对象的地址;*p的意思是“使间接引用操作符作用于p”,*p的值是p指向的对象的值,
*p是一个左值。就像变量一样,你可以通过在*p的右边添加一个赋值操作符来改变*p的值,如果p是一个常量的指针,*p是一个不能修改的左值,也就是说,它不能放在赋值操作符的左边。请看下面的例子:
例7.1间接引用的例子

# include
int
main()
{
int I;
int * p;
I = 5;
p = & I;/* now * p = = I */
/* % pi详见FAQ VII。28 * /
printf("i=%d,p=%P,* p= %d\n ",I,P,* P);
* p = 6;/ *与i = 6 * /
printf("i=%d,p=%P,* p= %d\n ",I,P,* P);
返回0;/ *见常见问题解答XVI。4 * / }
}

上面的例子说明,如果p是变量I的指针,那么在I出现的任何地方,都可以用*p代替I。上例中,P指向I (P =&I)后,打印I或*p的结果是一样的;你甚至可以给*p赋值,结果就跟你给I赋值一样。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C语言编程常见问题解答之指针和内存分配

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情