我一直在使用C编程语言作为项目的一部分。仅供参考,进入和列表的结构是非常基本的数据结构,并定义为
typedef struct entry entry_t;
typedef struct list list_t;
struct entry
{
void * data;
entry_t * next;
};
struct list
{
size_t size;
entry_t * head;
entry_t * tail;
};
head
和tail
分别指向第一个和最后一个条目。列表中没有这样的开销条目,但列表中的所有数据条目都没有,因此如果列表中只有一个条目,head
和tail
应指向相同的条目。此外,还有一个片段可以删除列表中的所有条目
list_t list;
entry_t * current, * next;
for(
current=list->head,
next=current->next,
free(current);
current!=list->tail;
current=next,
next=current->next,
free(current)
);
问题是在释放current
指针后评估内存地址list->tail
和current
的值之间的比较。假设current
和list->tail
现在指向同一块内存,然后current
被释放,评估的结果是什么,更重要的是结果(无论是什么)您体验中所有不同编译器的确定性?在我的例子中,程序在MSVC中编译并正确运行,表示在current
被释放后,内存地址list->tail
和current
的值相等。
答案 0 :(得分:2)
在这一点上并不重要,但是如果你清除了清单,那么请原谅明显的,但是谁在乎尾巴(或尺寸)。无论如何,他们即将失效。为什么不简单:
// assuming list is a valid
list_t* list;
while (list->head)
{
entry_t *tmp = list->head;
list->head = list->head->next;
free(tmp);
}
list->head = list->tail = NULL;
list->size = 0;
答案 1 :(得分:1)
从技术上讲,你违反了规则。按6.2.4(2)
对象的生命周期是程序执行的一部分,在此期间保证为其保留存储。存在一个对象,具有一个常量地址,并在其整个生命周期内保留其最后存储的值。如果在其生命周期之外引用对象,则行为未定义。当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定。
的C2011标准的n1570草案(在C99标准中几乎相同),在free
current
之后current
其值变得不确定(如果list->tail
恰好发生在free
之前指向与list->tail
相同的对象,NULL
的值也变得不确定。因此在比较中使用它会调用未定义的行为。
在一个假设的实现中,它跟踪指针的有效性并检查每个比较等,它可能会崩溃或做其他有趣的事情。
然而,在实践中,我不希望任何实现这样做,所以它几乎肯定会产生预期的结果。
作为WhozCraig pointed out,实际上有一个平台在进行跟踪。但是,这会将所有无效指针视为{{1}},因此,如果我理解正确,即使存在相关代码也会产生预期结果。
答案 2 :(得分:0)
评估的结果是什么
C标准表示结果未定义。
更重要的是,结果(无论是什么)是确定性的 在您体验的所有不同编译器中
内存一旦被进程分配,通常不会返回到操作系统,直到进程终止。
我所知道的所有编译器都会将current!=list->tail
评估为false,而不会抛出异常。
答案 3 :(得分:0)
以下是for loop
实施
entry_t *current,*prev,*next;
for(
current = list->head;
current != NULL;
prev=current,
current = current->next,
free(prev),
prev=NULL
);