首页 » C语言解惑 » C语言解惑全文在线阅读

《C语言解惑》18.3 动态内存

关灯直达底部

数组、指针和动态内存也是密切相关的。容易出现的错误仍然是边界和初始化问题。

18.3.1 非数组的指针

【例18.8】下面程序将数组t和s中的内容赋给指针变量p,但输出结果并没有包括s的全部内容。找出错误之处并改正之。


#include <stdio.h>#include <string.h>int main (){     int i=0,j=0;     char t="abcdefghij",s="klmnopqrstuvwxyz",*p;     p=t;     i=strlen(t);     while (( p[i+j] = s[j]) !='/0' )           j++;     printf("%s/n",p);     return 0;}  

原因是用数组t初始化指针的想法是想利用超出t的存储空间来存储s,这是危险的做法。越界之后,并不能保证有连续的有效存储空间用以存储字符串s。

可以另外定义一个大于s和t总长度的字符数组。例如


char st[30];p=st;  

然后使用如下两个循环完成赋值:


while (( p[i] = t[i]) !='/0' )           i++;while (( p[i+j] = s[j]) !='/0' )          j++;p[i+j]='/0';  

一般采用申请动态内存的方法,即为指针变量申请足够的存储空间。


p=(char*)malloc ( strlen(t)+strlen(t)+1)  

strlen函数计算的是实际字符串长度,所以要增加一个结束位。实际使用时,需要判别申请是否成功。这块内存虽然是非数组的指针,但却可以像数组那样使用下标。程序中演示了两种反序输出的方法,特别是演示下标为负值的使用方法,以便更好地理解动态内存的特点及指针的灵活使用方法。


//完整的程序#include <stdio.h>#include <string.h>#include <stdlib.h>int main (){       int i=0,j=0;       char t="abcdefghij",s="klmnopqrstuvwxyz",*p;       if ( (p=(char*)malloc ( strlen(t)+strlen(t)+8)) == NULL )  {             printf ( "内存分配错误!/n" );             exit(1);       }       while (( p[i] = t[i]) !='/0' )           i++;       while (( p[i+j] = s[j]) !='/0' )           j++;       p[i+j]='/0';       printf("%s/n",p);       for(i=25; i>-1; i--)             printf("%c",p[i]);       printf("/n");       p=p+25;       for(i=0; i>-26; i--)             printf("%c",p[i]);       printf("/n");       p=p-25;         free(p);       return 0;}  

程序输出结果如下:


abcdefghijklmnopqrstuvwxyzzyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcba  

释放内存,必须保证指针指向申请的动态内存的开始位置,否则会出错。所以程序中执行“p=p-25;”。申请内存时多申请了6个,是为了保证free可靠执行。

数值数组的使用方法与此类似,不再赘述。

18.3.2 NULL指针

在语句


if ( (p=(char*)malloc ( strlen(t) + strlen(t) + 8)) == NULL )  

中使用了空指针。空指针的表示为:


p=NULL;  

有时在赋值或比较运算的情况下会使用NULL指针,但在其他情况不能使用NULL指针。因为NULL指针并不指向任何对象,而且空指针也不是空字符串,所以对空指针p而言,使用如下两个语句会得到什么结果呢?


printf("%s/n", p);printf(p);  

为了代码的文档化,常采取如下定义:


#define NULL 0  

由此可见,p的行为没有定义,这两条语句在不同的机器上可能有不同的效果。

在禁止读取内存0地址的机器上,语句


printf("%d/n", *p);  

将会执行失败。在允许的机器上,则会以十进制方式输出内存位置0中存放的字符内容。

要注意的是,空指针并不是空字符串。无论使用0还是NULL,效果都是相同的。当将0赋值给一个指针变量时,绝对不能企图使用该指针所指向的内存中存储的内容。

有些C语言实现对内存位置0只允许读,不允许写。在这种情况下,NULL指针指向的也是垃圾信息,所以也不能错用NULL指针。

所以,对指针进行递增和递减操作必须预防越界。在达到最后一个边界时,要特别小心谨慎。释放不用的内存时,必须保证指针指向所申请内存的首地址,否则就会出错。在某些场合,为了保证释放,甚至需要多申请部分内存区域。