【问题标题】:C free(): invalid pointer allocated in other functionC free():在其他函数中分配的无效指针
【发布时间】:2014-08-08 13:24:20
【问题描述】:

我是 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 ***

我的代码有什么问题?

【问题讨论】:

标签: c


【解决方案1】:

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;
}

在 main 中,您可以像这样调用alloc

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

然后,你的代码就可以工作了。

【讨论】:

  • malloc(sizeof(int)) 工作。为什么是 malloc(sizeof(int*)) ?
  • @Drew: sizeof **p 会更好。
【解决方案2】:

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

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

您可以通过传递指向指针的指针或返回 p 的新值来解决此问题。

【讨论】:

    【解决方案3】:

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

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

    其次,main 中的变量 int* pointer 并没有像您想象的那样被修改。在 C 中,函数参数是“按值传递”的。你有两种方法可以解决这个问题:

    1. 将指针传递给要修改的变量(在您的情况下,是指向 int 指针的指针)
    2. 让函数返回指向调用它的函数的指针。

    以下是我的建议的两种实现方式:

    方法 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
    

    【讨论】:

      【解决方案4】:

      您正在将指针按值传递给alloc 函数。尽管该函数需要一个指向 int 的指针,但该指针本身不能被函数修改。如果你让alloc 接受**p,设置*p = ...,并从main 传入&amp;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;
      }
      

      【讨论】:

        【解决方案5】:

        如果您希望函数写入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++ 中是 not true,但如果您正在编写 C++,则应该使用 new 运算符而不是malloc)。此外,在该语言的 1989 版本下,如果您忘记包含 stdlib.h 或在范围内没有 malloc 的声明,则使用强制转换会掩盖错误。不过,自 1999 年版本以来,这一直不是问题,所以现在更多的是可读性问题。

        表达式*p的类型是int,所以sizeof *p的结果和sizeof (int)的结果是一样的。这样,如果您更改了p 的类型,您就不必修改malloc 调用。

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

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

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

        T *p = calloc( sizeof *p, NUM_ELEMENTS );
        

        【讨论】:

          猜你喜欢
          • 2015-03-31
          • 1970-01-01
          • 2021-05-16
          • 1970-01-01
          • 1970-01-01
          • 2012-02-21
          • 1970-01-01
          • 2013-06-27
          • 1970-01-01
          相关资源
          最近更新 更多