对于c/c++开发者来说,学好并且可以熟练的使用指针,是非常不易,而且容易出错的,想必所有的c/c++开发者都有相同的经历。作者我和大家一样,也遇到过许多的问题。现将指针学习中可能出现的错误予以整理,供大家参考!

1、首先需要了解指针的作用

指针是用来存放数据地址的。就是说,开发者可以使用一个指针变量,存放变量、函数、指针的地址。如int a=0;int *p=&a;这时就将a的地址存放在了变量p的内存空间中,不过这个变量p就是我们下来需要了解的指针变量。

2、既然指针变量中存放的是内存地址,能不能使用基本数据类型存放地址,而不引入指针类型?

需要知道地址:地址是一个32位的16进制整数。既然是32位,也就是说需要4个字节来存放该地址。这样如果使用基本的数据类型char、short、int(有些机器int为2字节)等存储,就会出现地址截取,出错。

而且指针变量还有另外一个作用,按照指针变量的类型,访问内存空间。如int *p;首先系统确定需要访问的数据为int类型,然后调用sizeof函数获得int类型的字节长度len,最后从p存放的地址处开始,连续访问len个字节,即获得一个int行数据。

因此,如果需要使用地址,就需要引入指针类型。

3、指针作为参数时,需要注意的问题

我们知道函数的参数,既可以是值传递,也可以是引用传递,也可以传递指针。

对于值传递:基本的数据类型传递时不会有太大的影响,但是对于自定义数据类型、类对象传递时一般不要选择值传递。减少产生临时变量,影响效率。

引用传递:c++中的特有属性,对于C语言是不适用的。能够使用引用的地方,一定可以使用指针,但是可以使用指针的地方,不一定能够使用引用

指针传递:最高效的传参方式,不会有任何的临时数据产生。

这里最需要注意的就是,字符数组作为参数时,出现的诸多问题:

1)

void getmemory(char* p,int num)
{
p=(char*)malloc(num);
}
int main(void)
{
char*p=NULL;
getmemory(p,10);
strcpy(p,"hello");
return 0;
}

上面的c函数,到底会出现什么问题了?

main函数中p和getmemory中的p不是一回事,main函数中的p只是一个指针变量,它并没有存放任何数据的地址,其实就是一个变量的值传递,因此getmemory中的p只是main函数中p的一个副本,因此p=(char*)malloc(num);将申请到的地址赋值给了一个副本,这样main函数中的p仍为null,因此执行strcpy函数是出错;而且getmemory函数中调用了malloc函数,申请到的内存没有被释放,内存泄露。

2)基于上面传递变量副本的错误,我们可以传递p的地址给getmemory函数


void getmemory(char** p,int num)
{
p=(char*)malloc(num);
}
int main(void)
{
char*p=NULL;
getmemory(p,10);
strcpy(&p,"hello");
free(p);
p=NULL;
return 0;
}



现在我们将main函数中指针变量p的地址传递给了getmemory函数,因此*p=(char*)malloc(num);这样就将申请到的内存空间的首地址传赋值给了p,函数可以正确运行。

3)当然我们也可以使用变量的副本


char* getmemory(int num)
{
char* p=(char*)malloc(num);
return p;
}
int main(void)
{
char*p=NULL;
p=getmemory(10);
strcpy(p,"hello");
free(p);
p=NULL;
return 0;
}

getmemory函数中的char*p确实是一个局部变量,在该函数结束后,该变量的内存就会被释放,这样不是就错了吗。其实这样理解只对了一半。我们知道malloc函数是从堆空间申请内存的,堆空间的内存如果开发者不显式的free掉,就会出现内存泄露,只有当程序异常退出后,系统才会回收内存。只要malloc申请内存成功,那么只要没有free掉,就会一直存在,char *p这个局部变量的内存被释放了,但是malloc申请的内存还没有被释放,因此执行return p;就相当于将申请的内存的首地址返回给了主调函数。就相当于用局部变量接收了全局变量的地址(这个在链表、树、图中经常用到)。

因此该函数可以正常执行。

4)


char* getmemory(int num)
{
char p[]={"hello"};
return p;
}
int main(void)
{
char*p=NULL;
p=getmemory(10);
strcpy(p,"hello123");
free(p);
p=NULL;
return 0;
}



其实getmemory函数中的char p[]={"hello"};这个字符数组是一个局部变量,函数执行完成后,p空间会被函数,所有main函数中strcpy函数执行错误。注意3)和4)的不同。

5)


char* getmemory(int num)
{
char *p=hello"";
return p;
}
int main(void)
{
char*p=NULL;
p=getmemory(10);
strcpy(p,"hello123");
free(p);
p=NULL;
return 0;
}

上面的这段代码,眨一看好像是正确的,其实一半正确,一半错误。getmemory函数可以正常返回。但是strcpy函数执行失败。hello是一个字符串常量,它被存放在静态存储区,因此试图改变常量内存,函数执行失败!


今天的内容就先更新这些,如果有新的内容将尽早更新,谢谢大家阅览,有不对之处,请各位亲们批评指正。