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

问题描述 投票:0回答:4

所以这是我的代码:

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)就可以解决问题,但是我需要一个不同的方法,即使函数返回到原始向量也能工作。

c pointers memory-management memory-leaks
4个回答
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
投票

当然可以。向量t被分配两次,并释放一次。整个架构看起来有问题。


0
投票

是的,你正在泄露记忆。从未发布过。 也通过指针而不是值传递结构。返回矢量也很昂贵。

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

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

OUTPUT:

2       10

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的(新)值,但是不再有任何方法可以访问旧的动态分配的内存。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.