指针、指针变量与内存空间——解惑
一年前,我曾今在ChinaUnix写过一篇博客《关于定义一个指针与指针变量》然后搬家来了CSDN。这篇博客中写道了很多关于指针和指针变量以及空间分配的一些常见错误。但是,到现在为止,无论是CSDN的网友还是一些已经工作的同事以及大三大四的学生,陆陆续续的有人在问我关于指针与指针变量还有空间分配问题。我想在这里再写一篇博客解惑指针
问题1
view plaincopy to clipboardprint?
int idata = 5;
int *p = idata//为什么这里不对?
既然通常*p表示对指针p指向数据的引用,为什么*p = idata不能行呢?
回答:int *p和引用时的*p概念是不一样的。定义数据的时候 int *p所表示的是定义了一个指向int数据的指针p。并不是数据引用时的*p.
所以,int *p只是定义了一个指向int数据的指针p,这个指针p所存放的是一个地址(32位),而idata是一个int数据,int数据不能赋值给一个地址。除了定义以外的其他地方,*p所表示就是p所指向的数据。
所以以上语句作出以下更改就对了:
view plaincopy to clipboardprint?
int idata = 5;
int *p = &idata;//p存放idata的地址
问题2:
既然问题1中已经说了,定义是只是定义了一个指针p,下面的语句为什么是对的呢?
view plaincopy to clipboardprint?
char *p = "hello world";//为什么是对的?
回答:
C语言中,字符字符串常量是按字符串数组来处理的,会在内存中开辟一个字符串数组用来存放该字符串常量,然后把该字符串数字的首元素地址赋值给p。
以上语句其实等价于下面:
view plaincopy to clipboardprint?
char *p = "hello world";
//等价于
char tmp[] = "hello world";
char *p = tmp;
//等价于
char tmp[] = "hello world";
char *p = NULL;//初始化,避免编译错误
p = tmp;
问题3:
对于结构体指针,struct mystruct *pstruct,然后对pstruct进行操作,为什么有时候正确,有时候又报内存错误?
回答:
指针的操作分为输入与输出。所谓输入:即将指向结构体的指针pstruct穿进去给别人处理。输出:即别的函数需要输出,需要写的。
你所谓的有时候正确有时候又不正确,其实是因为你没有搞清楚究竟该谁分配空间。一定要铭记:定义一个指针只是定义了一个存放地址的指针变量,他只能存放地址,定义一个指针并没有为他所指向的数据分配空间。例如 struct mystruct *p,定义了一个指向struct mystruct的指针变量p,并没有分配struct mystruct大小的数据空间。如果p没有指向任何数据,你对它进行写操作,必定会出内存错误。
但是如果这样做:
struct mystruct myst;
struct mystruct *p = &myst;
然后再对p进行操作,就不会出错。说到底,还是没有弄清楚程序设计需要谁去为数据分配空间的问题。
最近在温故《C ++ primer》这本书,其中有一句话非常经典:
When attempting to understand pointer declarations, read them
from right to left.
理解指针定义的时候,应该从右往左读
定义变量是由系统自动申请的,比如定义int i;系统自动申请一个整型变量的内存空间,定义指针只是申请一个指针的空间(一般是2字节),指向的位置需要自己申请,或指向一个已经由系统申请的空间,自己申请的必须自己free掉,系统申请的函数调用完后系统自动释放
在函数定义指针或者变量已经为指针本身和变量本身分配了内存所以用指针指向一个已经定义的变量时不需再分配内存
但是数据结构中用指针指向结构体时只为指针本身分配了内存如果要对结结构体填入内容就要分配一个结构体大小的内存才可以
但只自己分配的内存一定要养成用free()的好习惯
比如说定义一个结构体
struct node{
int man;
int what;
}ok;
定义一个指针
struct node *p;
此时p就可以对结构体进行操作但非常危险因为没有对p初始化以下两种都是初始化
p=&ok;//这里就不用分配内存了原因就是上面所说的
p=(struct node *)malloc(sizeof(struct node));
现在p才可以安心的使用