关于malloc与字符指针的一些易错点

来源:互联网 发布:易吧进销存软件下载 编辑:程序博客网 时间:2024/06/03 16:25

 有如下一段代码,意图把“zhongxiaoming"字符串赋值进以p为首地址的空间为15字节的内存空间,然后释放p所指向的内存,以免出现内存泄露。

该代码出现几个问题,涉及到内存的赋值、malloc函数以及free函数的用法,以及字符串的相关知识。

 1 #include <stdio.h>

  2 #include <stdlib.h>
  3 
  4 int main()
  5 {
  6         char *p = (char*)malloc(15);
  7         int i=0;
  8         p="zhongxiaoming";
  9         for(;i<15;i++)
 10         {       
 11                 printf("p[%d]:%c\t",i,*(p+i));
 12         }
 13         printf("\n");
 14         free(p);
 15         p=NULL;
 16         printf("ok\n");
 17         return 0;

 18 }

===================================================================

编译运行后:

Love-Yan:pointertest MD101$ make
gcc -o malloctest malloctest.c -g
Love-Yan:pointertest MD101$ ./malloctest
p[0]:z p[1]:h p[2]:o p[3]:n p[4]:g p[5]:x p[6]:i p[7]:a p[8]:o p[9]:m p[10]:i p[11]:np[12]:gp[13]:p[14]:p
malloctest(3232) malloc: *** error for object 0x107a45f4e: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

可知道,pointer being freed was not allocated。意思是,意图释放的指针(p)没有被分配,这是什么意思呢?明明malloc了15字节的空间,怎么说没有被分配呢?

原来:  

malloc========================================

8         p="zhongxiaoming"; 这行语句打乱了所有的计划,导致分配出来的15字节空间丢失了,内存泄露掉了。

 6         char *p = (char*)malloc(15);这时候的p才是15字节的真正主人。

按照本意,我们采用strcpy就可以把“zhongxiaoming”拷贝进p指向的内存。不过,要记得加进<string.h>头文件哦。具体代码:

strcpy(p,"zhongxiaoming");这样,p对应的连续15个内存地址就依次被赋值了,当然,只是赋值了strlen(“zhongxiaoming”)+1个字节,后面的应该保持不变,因为malloc分配出来的空间不会对内存进行初始化,而new操作符分配出来的会初始化。


字符串、内存静态区======================================

第八行代码把在静态区创建的字符串常量“zhongxiaoming”的首地址赋值给了p,此时,指针变量p的值发生了变化,不再是指向15个字节的首地址了。

此时,可以通过p对字符串常量进行读的操作(无写操作,字符常量不允许修改,通常在静态区的内容,很多都是字符常量、整形常量等等,譬如int a=12;doule b=123.123123;

这里的12和123.123123都是放在静态区的,他们都有个地址,这些常量与a、b对应,读a也就是读a对应的12.可是如果再有对a 的重新赋值,则常量区的12将会在某个时刻被系统回收掉,可以肯定的是,程序结束后肯定被释放掉了,呵呵。。。重新赋值a,如a=12312,则又在静态区创建12312与a对应,以此类推。),在此特别引申一点:

指针对应的字符串的访问还可以通过poiner[i]操作符进行访问。当然,在这里是想把“zhongxiaoming”全部读出来。而p又指向其对应的地址(其实,用&(“zhongxiaoming”)可得到其地址),故我们可以通过p[i]进行访问,当然了,不能写哦,常量嘛,静态区嘛。。。那我们就这样完成了对常量区字符串“zhongxiaoming”的读操作啦。当然,这是没有修改过的源代码的功能。

free===================================================

按照没有修改过的源代码,直接就free(p),也太夸张了吧,把p(也就是&(“zhongxiaoming”)对应的内存释放),这是要逆天了?想去释放静态区的内存。。嘿嘿,这可是系统自己的事,最好还是别干预了。所以,系统报错。。。说,malloctest(2617) malloc: *** error for object 0x107b27f48: pointer being freed was not allocated。也就是说,这不是你分配的内存,这段内存不归你管。。。

修改代码==================================================

而加入strcpy的新代码,要对p对应的内容进行访问也就是有【】操作符或者*(p+i)了,千万别写成&p+i哦,这样子可是会挎了15个字节访问了哦。。。我们把代码修改下:

#include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 int main()
  5 {
  6         char *p = (char*)malloc(15);
  7         int i=0;
  8         memset(p,'A',15);
  9         for(;i<15;i++)
 10         {              
 11                  printf("p[%d]:%c\t",i,p[i]);
 12         }
 13         printf("\n\n");
 14         
 15         strcpy(p,"zhongxiaoming");
 16         for(i=0;i<15;i++)
 17         {       
 18                 printf("p[%d]:%c\t",i,p[i]);
 19         }
 20         printf("\n");
 21         free(p);
 22         p=NULL;
 23         return 0;
 24 }

运行:

Love-Yan:pointertest MD101$ make
gcc -o malloctest malloctest.c -g
Love-Yan:pointertest MD101$ ./malloctest
p[0]:z p[1]:h p[2]:o p[3]:n p[4]:g p[5]:x p[6]:i p[7]:a p[8]:o p[9]:m p[10]:i p[11]:np[12]:g p[13]:p[14]:
Love-Yan:pointertest MD101$ 

大功告成。。。

不过,在这里,如果要考究下strcpy对p的15个字节处理了多少个呢?我们可以先用memset来对这15个字节进行下初始化,然后再输出看看就知道了。

Love-Yan:pointertest MD101$ make
gcc -o malloctest malloctest.c -g
Love-Yan:pointertest MD101$ ./malloctest
p[0]:A p[1]:A p[2]:A p[3]:A p[4]:A p[5]:A p[6]:A p[7]:A p[8]:A p[9]:A p[10]:A p[11]:Ap[12]:Ap[13]:Ap[14]:A


p[0]:z p[1]:h p[2]:o p[3]:n p[4]:g p[5]:x p[6]:i p[7]:a p[8]:o p[9]:m p[10]:i p[11]:np[12]:gp[13]:p[14]:A
Love-Yan:pointertest MD101$ 

good news。。。只是对前面的部分字节进行了赋值。可是第十四了也就是p[13]里边的内容是空的。。这是怎么回事?

我们知道字符串的结尾是'\0‘对吧,里边会不会就是'\0'呢?我们可以gdb一下。看看这个p[13]是什么。

果然。。。

(gdb) p p[13]
$2 = 0 '\0'
(gdb)