指针未反映在函数中更改值时更改

时间:2017-08-23 21:55:29

标签: c pass-by-reference

我正在使用数组实现链接列表。它具有反向功能 定义如下

void Reverse(List *l)
{
    List *m=CreateList(ListSize(l));
    for(int i=0;i<l->count;i++)
    {
        m->array[i]=l->array[l->count-i-1];
        m->count++;
    }
    free(l->array);
    free(l);
    l=m;
    //Traverse(l); Here it prints the reversed List

}

它将List结构作为参数。我是从主要的这个叫它

int main()
{
    size=5;
    List *l=CreateList(size);
    Reverse(l);
    Traverse(l); //Here the list is not printing the reversed list !

}

为什么我对l做出的更改没有显示在main()中? 谢谢!

3 个答案:

答案 0 :(得分:2)

你必须传递一个双指针才能改变指针指向的位置。

void Reverse(List **l);
Reverse(&l);

来自www-cs-students.stanford.edu

的C语言无法通过引用传递
  

在C中,通过传递a的地址来模拟传递引用   变量(指针)并取消引用该地址   用于读取或写入实际变量的函数。这将被提及   as&#34; C style pass-by-reference。&#34;

答案 1 :(得分:1)

执行l = m后,您只需在l内设置Reverse即可。 lReverse的参数列表的一部分。更改值时,只会在调用Reverse期间更改该值。它永远不会传播给调用者。

您可以使用Filip的方法传播该值。

或者,您可以:

  1. Reverse重新定义为:List *Reverse(List *l)
  2. 添加return m作为其中的最后一个语句
  3. 并致电:l = Reverse(l)
  4. 但是,这有点浪费。您也可以进行就地逆转:

    void Reverse(List *l)
    {
        int left = 0;
        int right = l->count - 1;
    
        // NOTE: this should be whatever the type of array[0] is:
        int tmp;
    
        for (;  left < right;  ++left, --right) {
            tmp = l->array[left];
            l->array[left] = l->array[right];
            l->array[right] = tmp;
        }
    }
    

    <强>更新

      

    当我在最后一行做* l = * m代码有效但我不知道为什么!

    即使这有一个错误。

    这是因为您要替换l指向的整个内容。基本上,您创建了一个新的[反向]列表m,填充它,然后将其复制回l

    在执行free(l)之前执行*l = *m 错误。您正在取消引用指向已释放内存的指针。

    想做free(l->array),但 free(l)

    此外,在执行*l = *m后,您需要执行free(m)。否则,struct m指向[{1}}指向[{1}}指向[{1}}指向m->array指向的l->array内存泄漏,因为它会保存在*l = *m中]

    这是不必要的复杂性和容易出错。

    你根据需要做了两倍的工作。执行l->count = m->count; for (int i = 0; i < m->count; ++i) l->array[i] = m->array[i]; 时,您确实在做:

    *l = *m

    换句话说,即使它似乎有用,也不要做free(l)。使用三种更简单/更正确的方法之一。

    更新#2:

      

    即使l指向的内存不存在,它似乎工作正常(* l = * m)。请告诉我free()在这种情况下实际上做了什么

    是的,似乎可以正常工作,但工作正常[在一般情况下]。

    执行l后,free(l)指向的内容不可用。内存分配器假设您已经 no 进一步使用此内存[因为当您执行free(l)时,您告诉它就是这样]。分配器可以自由地使用该内存它所希望的

    1. 在多线程环境中,在您调用malloc并将控制权返回给您之间,另一个线程可以执行*l = *m,现在您有两个线程指向同一内存并使用它用于不同的目的。执行后续free(l)会破坏其他线程存储在那里的数据。这引入了一个微妙的,间歇性的,难以发现的错误。
    2. 在单线程环境中,内存分配器可能会使用内存来存储元数据,以用于自己的[内部]目的。再次,之前它从*l = *m返回。因此,当您执行malloc时,您可能会破坏分配器的内部数据结构(反之亦然)。下次发出malloc时,分配器可能会发生段错误。
    3. 下次发出l时,它可能会返回指向main正指向的相同内存的指针(例如,您创建第二个列表[在l2 = CreateList(10)]中通过调用l)。现在,l2struct具有相同的值(即它们指向相同的l)。因此,不是l2l2是单独的列表,而是碰撞。或者,l2->array可能不同,但l可能会与*l = *m
    4. 重叠

      以下是一般资源分配/发布问题的一个示例。由于您不知道内部分配或发布功能的作用,因此在资源被释放/释放后,您无法安全地访问资源内的任何。下面的发布功能添加了一行来说明为什么使用#include <malloc.h> struct resource { int count; int *array; }; struct resource * allocate_resource(int count) { struct resource *ptr; ptr = malloc(sizeof(struct resource)); ptr->count = count; ptr->array = malloc(sizeof(int) * count); return ptr; } void free_resource(struct resource *ptr) { free(ptr->array); // prevents "*l = *m" from "seeming to work" ptr->array = NULL; free(ptr); } int main(void) { while (1) { struct resource *x = allocate_resource(20); // x may be utilized here ... free_resource(x); // x may _not_ be utilized here ... // this will segfault x->array[0] = 23; } return 0; }

      执行的操作不安全
      df['mycol'] = pd.to_numeric(df['mycol'], errors='coerce')
      

答案 2 :(得分:1)

在C中,函数参数始终按值传递。这意味着函数ReverseList() l是函数调用中传递的List指针的副本。因此,当创建反转的List并将地址分配给函数中的l时,这对Listmain()的原始指针没有影响(因为l中的Reverse()只是lmain()的副本。函数名称中的变量与调用者中的相应名称不同,可以帮助保持这种直接。

一种解决方案是将指向List的指针传递到Reverse()函数:

void Reverse(List **lptr)
{
    List *m=CreateList(ListSize(*lptr));
    for(int i=0;i<(*lptr)->count;i++)
    {
        m->array[i]=(*lptr)->array[(*lptr)->count-i-1];
        m->count++;
    }
    free((*lptr)->array);
    free(*lptr);
    *lptr=m;
    //Traverse(l); Here it prints the reversed List
}

使用Reverse(&l)调用此函数。这里,由于在List中使用指向Reverse()指针的指针的副本,lptr指向l中的指针main(),{{可以取消引用1}},并且可以将lptr的值分配给m中找到的Listl)的实际指针。

另一种解决方案是更改main()函数以向调用者返回指向Reverse()的指针。然后将返回的值分配给List

l

此外,如果List * Reverse(List *l) { List *m=CreateList(ListSize(l)); for(int i=0;i<l->count;i++) { m->array[i]=l->array[l->count-i-1]; m->count++; } free(l->array); free(l); return m; //Traverse(l); Here it prints the reversed List } int main(void) { size=5; List *l=CreateList(size); l = Reverse(l); Traverse(l); //Here the list is not printing the reversed list ! return 0; } 尚未检查分配错误,则代码应在CreateList()之前的分配之前检查这些错误。