1. 指针作为函数参数进行传递
下面的代码本意是想在main中定义一个指针p,然后将其传给func_memory()函数,让func_memory函数申请一块内存,然后在main函数中对这块内存进行拷贝操作。
如下的代码运行会产生“segment Fault”,程序直接崩溃。
int main(void)
{
char *str = "hello world";
char *p = NULL;
func_memory(p, strlen(str)+1);
memcpy(p, str, strlen(str));
printf("p_data=%s", p);
if (p){
free(p);
}
return 0 ;
}
void func_memory(void *p1, int len)
{
p1 = malloc(len);
if (NULL != p1){
memset(p1, 0 , len);
}
}
原因分析:main中在调用func_memory()的时候,是将实参p的值传递给了形参p1,是值传递,即p1=p=NULL。而这个传递是单向的,p和p1位于两个独立的栈帧上,对p1赋值,不会修改p。除将p的值传递给p1外,二者没有任何关系。所以,在func_memory()中,p1指向了malloc的内存,而调用函数中的p还是NULL,没有指向任何有效的内存。所以对p的操作会引起 "segment Fault"。
解决办法:
方法一:传递地址
在调用函数中将指针的地址传递给被调函数,在被调函数中通过指针的地址对指针进行赋值。
int main(void)
{
char *str = "hello world";
char *p = NULL;
func_memory(&p, strlen(str)+1);
memcpy(p, str, strlen(str));
printf("p_data=%s", p);
if (p){
free(p);
}
return 0 ;
}
void func_memory(void **p1, int len)
{
*p1 = malloc(len);
memset(*p1, 0 , len);
}
代码分析:
char *p=NULL;编译器对于这条语句的理解是:分配一块内存,这块内存的名字是p,内存中存放的是一个指向char型数据的地址,但是这个地址目前是NULL,也就是没有存放任何char型数据的地址。
在调用函数func_memory时,相当于 "void **p1 = &p;", p1的值为p的地址,也就是说p1这个变量中存放的是p的地址(假设p的内存地址为 "0x1000", 这个地址上的值为NULL,变量p1的地址为 "0x1004",这块地址上存储的值为0x1000。)。"*p1" 表示为p1所指的内存进行赋值操作,也就是为0x1000这个内存进行赋值操作,就是将malloc内存的地址值赋给了p,也就是说:p指向了这块内存。
知识点说明:p为指针,那么 *p = xxx,就表示为p所指向的内存赋值为xxx,p所指向的内存就是指针变量p中存放的那个内存。
int a = 10;
int *p = &a;
*p = 100; //*p = p = 100
char *p = NULL;
char **p1 = &p;
*p1 = 0x1004; //*p1 = p = 0x1004
方法一:将malloc的地址返回
要知道malloc的内存存在于堆上,除非手动释放或者程序退出,否则是会一直存在的。所以我们可以将malloc的内存地址返回给被调用函数。
int main(void)
{
char *str = "hello world";
char *p = NULL;
p = (char *)func_memory(strlen(str)+1);
if (NULL != p){
memcpy(p, str, strlen(str));
printf("p_data=%s", p);
free(p);
}
return 0 ;
}
void *func_memory(int len)
{
void *p1 = NULL;
p1 = malloc(len);
if (NULL != p1){
memset(*p1, 0 , len);
}
return p1;
}
注意点:对于上面的malloc和free分别在两个不同的函数的场景中,一定不要忘记free。
2. 对指针sizeof
sizeof(p):sizeof 是c语言的关键字(sizeof加括号,完全是为了使括号内的内容成为一个整体),对一个指针执行sizeof操作,计算的是指针的长度(指针的长度与平台和编译器有关,通常32位系统为4字节,64位系统为8字节),而不是指针指向内容的长度。
char *p = NULL;
p = (char *)malloc(sizeof(char)*15);
memset(p, 0, sizeof(char)*15);
sizeof(p); //32位系统下,gcc编译器下值为4,虽然p指向15个字节的空间