C free():在其他函数中分配的无效指针

时间:2014-08-08 13:24:20

标签: c

我是StackOverflow的新手。我现在正在学习C指针。

这是我的代码:

#include <stdio.h>
#include <stdlib.h>

int alloc(int* p){
    p = (int*) malloc (sizeof(int));
    if(!p){
        puts("fail\n");
        return 0;
    }
    *p = 4;
    printf("%d\n",*p);
    return 1;
}

int main(){

    int* pointer;

    if(!alloc(pointer)){
        return -1;
    }else{

        printf("%d\n",*pointer);
    }

    free(pointer);

    return 0;
}

我编译:gcc -o main main.c

错误:free():指针无效:0xb77ac000 ***

我的代码出了什么问题?

5 个答案:

答案 0 :(得分:4)

C中的参数始终按值传递 。因此,当您调用alloc(pointer)时,您只需传入pointer包含的垃圾值。在函数内部,赋值p = (int*)...仅修改局部变量/参数p。相反,您需要将pointer地址传递到alloc,如下所示:

int alloc(int **p) {
    *p = malloc(sizeof(int)); // side note - notice the lack of a cast
    ...
    **p = 4; // <---- notice the double indirection here
    printf("%d\n", **p); // <---- same here
    return 1;
}

主要是,你可以这样叫alloc

if (!(alloc(&pointer))) {
    ....

然后,您的代码将起作用。

答案 1 :(得分:1)

C中的所有内容都是按值传递的。这意味着函数始终在他们传递给函数的本地副本上运行。通常,指针是模仿传递引用方案的好方法,因为指针和该指针的副本都包含相同的内存地址。换句话说,指针及其副本都指向同一个空格。

在您的代码中,问题是函数alloc获取了您自己传入的指针的本地副本。因此当您执行p = (int*) malloc (sizeof(int));时,您需要更改{{1}的值成为新的内存地址,但ppointer的值保持不变。

你可以通过传递一个指向指针,或者返回新值main来解决这个问题。

答案 2 :(得分:1)

您的代码中存在两个主要问题。

首先,alloc函数通过malloc创建一个指针,但从不释放它,也不返回指向调用函数的指针。这可以保证内存永远不会通过free命令释放指针地址,现在你有内存泄漏。

其次,int* pointer中的变量main未按您的想法进行修改。在C中,函数参数是&#34;由值&#34;传递。您有两种方法可以解决此问题:

  1. 将指针传递给您想要修改的变量(在您的情况下,指向指向int的指针)
  2. 让函数返回指向调用它的函数的指针。
  3. 以下是我的建议的两个实现:

    方法1


    #include <stdio.h>
    #include <stdlib.h>
    
    int alloc(int** p);
    
    int alloc(int** p) {
       if (!p) {
          printf("Invalid argument\n");
          return (-1);
       }
       if ((*p = (int*)malloc(sizeof(int))) == NULL) {
          printf("Memory allocation error\n");
          return (-1);
       }
       **p = 123;
       printf("p:%p - *p:%p - **p:%d\n", p, *p, **p);
       return 0;
    }
    
    int main(){
       int* pointer;
    
       if(alloc(&pointer) != 0){
          printf("Error calling function\n");
       }else{
          printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
       }
    
       free(pointer);
    
       return 0;
    }
    

    方法1的示例运行


    p:0xbfbea07c - *p:0x8656008 - **p:123
    &pointer:0xbfbea07cointer - pointer:0x8656008ointer - *pointer:123
    

    方法2


    #include <stdio.h>
    #include <stdlib.h>
    
    int* alloc(void) {
       int* p;
       if ((p = (int*)malloc(sizeof(int))) == NULL) {
          printf("Memory allocation error\n");
          return (NULL);
       }
       *p = 123;
       printf("p:%p - *p:%d\n", p, *p);
       return p;
    }
    
    int main(){
       int* pointer = alloc();
    
       if(pointer == NULL) {
          printf("Error calling function\n");
       }else{
          printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
       }
    
       free(pointer);
       pointer = NULL;
    
       return 0;
    }
    

    方法2的示例运行


    p:0x858e008 - *p:123
    &pointer:0xbf9bb1ac- pointer:0x858e008- *pointer:123
    

答案 3 :(得分:0)

您正在将指针值传递到alloc函数中。虽然该函数采用指向int的指针,但该指针本身不能被该函数修改。如果您alloc接受**p,请设置*p = ...,然后从主要传递&pointer,它就可以正常工作。

#include <stdio.h>
#include <stdlib.h>
int alloc(int** p){
  *p = (int*) malloc (sizeof(int)); 
  if(!*p){
    puts("fail\n"); 
    return 0; 
  } 
  **p = 4; 
  printf("%d\n",**p);
  return 1; 
} 
int main() { 
  int* pointer; 
  if(!alloc(&pointer)){ 
    return -1;
  } else { 
    printf("%d\n",*pointer);
  } 
  free(pointer);
  return 0;
}

答案 4 :(得分:0)

如果希望函数写入类型为T的非数组参数,则必须传递指向该参数的指针。

void func( T *ptr )
{
  *ptr = new_value;
}

void foo ( void )
{
  T var;
  func( &var ); // writes new value to var
}

如果T是指针类型Q *,则它看起来像

void func( Q **ptr )
{
  *ptr = new_pointer_value;
}

void foo ( void )
{
  Q *var;
  func( &var ); // writes new pointer value to var
}

如果Q是指针类型R *,您将获得

void func( R ***ptr )
{
  *ptr = new_pointer_to_pointer_value;
}

void foo ( void )
{
  R **var;
  func( &var ); // writes new pointer to pointer value to var
}

三种情况下的模式相同;您传递变量var地址,因此形式参数ptr必须比实际参数var多一个间接级别。

一个音节尼特:而不是写作

p = (int *) malloc( sizeof (int) );

使用

p = malloc( sizeof *p );

代替。

在C中(截至1989年标准),您不需要投射malloc的结果; void指针可以分配给其他指针类型,反之亦然,而不需要强制转换(在C ++中这是 true,但是如果你正在编写C ++,你应该使用{{无论如何,1}}运算符而不是new。此外,根据1989年版本的语言,如果您忘记包含malloc或在范围内没有stdlib.h声明,使用演员表会掩盖错误。然而,自1999年版以来,这并不是一个问题,所以现在更多的是可读性而不是其他任何问题。

表达式malloc的类型为*p,因此int的结果与sizeof *p的结果相同。这样,如果您更改sizeof (int)的类型,则无需修改p来电。

要分配值数组,您可以使用类似

的内容
malloc

或者,如果您希望最初将所有内容归零,请使用

T *p = malloc( sizeof *p * NUM_ELEMENTS );