这个C代码是否会泄漏内存?

时间:2017-12-06 21:25:42

标签: c pointers memory-management memory-leaks

所以这是我的代码:

typedef struct {
    int x;
    int *t;
}vector;

vector fct (vector v){
    vector w;
    int i;
    w.x=v.x;
    w.t=malloc(w.x *sizeof(int));
    for (i=0; i<w.x; i++)
        w.t[i]=2*v.t[i];
    return w;
}


int main (){
    int i;
    vector v;
    v.x=2;
    v.t=malloc(2*sizeof(int));
    v.t[0]=1; v.t[1]=5;
    v=fct(v);
    for (i=0; i<2; i++)
        printf("%d \t",v.t[i]);
    puts("");
    free(v.t);
    return 0;
}

我非常担心它是否会导致内存泄漏,以及如何解决这个问题。 哦,我知道如果我定义另一个向量,那就说w,这样 w = fct(v) 它会清除问题,但我需要一个不同的方法,即使函数返回到原始向量也能工作。

4 个答案:

答案 0 :(得分:4)

v.t=malloc(2*sizeof(int));

在此您将已分配的内存分配给v.t

v=fct(v);

然后在此处使用v返回的内容覆盖fct的所有字段。这会丢弃v.t的旧值,导致内存泄漏。

free结束时对main的调用释放了fct内部分配的内存。

您可以通过保存v.t并在已保存的指针上调用free来修复此泄漏:

vector v;
int *vt_sav;
v.x=2;
v.t=malloc(2*sizeof(int));
vt_sav = v.t;
v.t[0]=1; v.t[1]=5;
v=fct(v);
free(vt_sav);

答案 1 :(得分:1)

确实如此。向量t被分配两次,并释放一次。整个架构看起来有问题。

答案 2 :(得分:0)

是的,你正在泄漏记忆。 w.t永远不会被释放 也通过指针而不是值传递结构。返回矢量也很昂贵。

您的新程序可能如下所示:

#include <stdio.h>


typedef struct {
    int x;
    int *t;
}vector;

void fct (vector *v, vector * w){

    int i;

    w->x = v->x;

    for (i=0; i<w->x; i++)
        w->t[i]=2*v->t[i];
}


int main (){
    int i;
    vector v;
    vector w;

    v.x=2;

    v.t = malloc(2*sizeof(int));
    w.t = malloc(2*sizeof(int));

    v.t[0]=1;
    v.t[1]=5;

    fct(&v,&w);

    for (i=0; i<2; i++)
        printf("%d \t",w.t[i]);


    puts("");

    free(v.t);
    free(w.t);

    return 0;
}

输出:

2       10

答案 3 :(得分:0)

  

我非常担心它是否会导致内存泄漏,以及如何解决这个问题。

确实如此。在main()中,您可以为其分配内存并指向v.t;然后用fct()的返回值覆盖该指针。原始指针丢失,你没有其他副本,所以指向内存泄露。

  

哦,我知道如果我定义另一个向量,让我们说w,这样w = fct(v)就可以解决问题,但是我需要一种不同的方法,即使是函数返回到原始向量。

每次动态内存分配都有释放内存的义务。您可以认为该义务仅与指向该内存的指针的一个副本相关联,作为一种概念标记。您可以自由(理论上)将标记转移到指针的不同副本。然而,如果带有标签的副本超出范围或被不同的值覆盖,那么你会泄漏指向的内存。

考虑一下这适用于您的情况:

  1. 您分配内存并指定指向v.t的指针。这最初是指向已分配内存的指针的唯一副本,因此释放该内存的义务与之相关。

  2. 您将v的副本(包括v.t的副本)传递给函数fct()。您有两种选择:免费义务可以保留v.t的原始副本,也可以转移到该功能收到的副本。这是fct()定义的固有特征,应该用它来记录 - 你不能在逐个呼叫的基础上进行选择。由于fct()没有释放指针,因此您隐含地选择了自由保留原始副本的义务。

  3. fct()执行自己的分配并返回结果指针的副本;这是执行该功能后唯一幸存的副本,因此免费义务必须随之而来。

  4. 通过使用不同的值覆盖原始v.t,同时它有义务释放,您泄漏原始内存。仍然有义务释放v.t的(新)值,但是没有任何方法可以访问旧的动态分配的内存。

  5. 现在你有一个选项:是否将义务转移到函数调用的一部分。假设你确实转移了它;在这种情况下,fct()必须在返回之前执行free()。但是,在这种情况下,main()在调用v.t后不得使用fct()的原始值,是否会使用该函数的结果覆盖v

    所以你有一个选择:fct()负责释放v.t(它可以传递给另一个函数,如果它希望,或者它可以通过它的返回值返回给调用者) ,或fct()不承担这一责任。其呼叫者需要相应的行为。你无法双管齐下。