我正在使用数组实现链接列表。它具有反向功能 定义如下
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()中? 谢谢!
答案 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
即可。 l
是Reverse
的参数列表的一部分。更改值时,只会在调用Reverse
期间更改该值。它永远不会传播给调用者。
您可以使用Filip的方法传播该值。
或者,您可以:
Reverse
重新定义为:List *Reverse(List *l)
return m
作为其中的最后一个语句l = Reverse(l)
。但是,这有点浪费。您也可以进行就地逆转:
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)
时,您告诉它就是这样]。分配器可以自由地使用该内存它所希望的:
malloc
并将控制权返回给您之间,另一个线程可以执行*l = *m
,现在您有两个线程指向同一内存并使用它用于不同的目的。执行后续free(l)
会破坏其他线程存储在那里的数据。这引入了一个微妙的,间歇性的,难以发现的错误。*l = *m
返回。因此,当您执行malloc
时,您可能会破坏分配器的内部数据结构(反之亦然)。下次发出malloc
时,分配器可能会发生段错误。l
时,它可能会返回指向main
正指向的相同内存的指针(例如,您创建第二个列表[在l2 = CreateList(10)
]中通过调用l
)。现在,l2
和struct
具有相同的值(即它们指向相同的l
)。因此,不是l2
和l2
是单独的列表,而是碰撞。或者,l2->array
可能不同,但l
可能会与*l = *m
以下是一般资源分配/发布问题的一个示例。由于您不知道内部分配或发布功能的作用,因此在资源被释放/释放后,您无法安全地访问资源内的任何。下面的发布功能添加了一行来说明为什么使用#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
时,这对List
中main()
的原始指针没有影响(因为l
中的Reverse()
只是l
中main()
的副本。函数名称中的变量与调用者中的相应名称不同,可以帮助保持这种直接。
一种解决方案是将指向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
中找到的List
(l
)的实际指针。
另一种解决方案是更改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()
之前的分配之前检查这些错误。