我有些困惑如何检查内存分配是否失败,以防止解引用NULL
指针引起的未定义行为。我知道malloc
(和类似的函数)可能会失败并返回NULL
,因此必须在继续程序的其余部分之前始终检查返回的地址。我不理解的是如何处理这种情况的最佳方式。换句话说,当malloc
调用返回NULL
时,程序应该怎么做?
我正在开发的一个双向链表实现时,遇到了这个问题。
struct ListNode {
struct ListNode* previous;
struct ListNode* next;
void* object;
};
struct ListNode* newListNode(void* object) {
struct ListNode* self = malloc(sizeof(*self));
if(self != NULL) {
self->next = NULL;
self->previous = NULL;
self->object = object;
}
return self;
}
只有节点的指针正确分配了,节点才能被初始化。如果没有正确分配,该构造函数将返回NULL
。
我还编写了一个函数,它从已存在的节点开始创建一个新节点(调用newListNode
函数),然后返回它。
struct ListNode* createNextNode(struct ListNode* self, void* object) {
struct ListNode* newNext = newListNode(object);
if(newNext != NULL) {
newNext->previous = self;
struct ListNode* oldNext = self->next;
self->next = newNext;
if(oldNext != NULL) {
newNext->next = oldNext;
oldNext->previous = self->next;
}
}
return newNext;
}
如果
newListNode
返回NULL
,createNextNode
也返回NULL
,并且传递给该函数的节点不会受到影响。然后,ListNode结构用于实现实际的链表。struct LinkedList {
struct ListNode* first;
struct ListNode* last;
unsigned int length;
};
_Bool addToLinkedList(struct LinkedList* self, void* object) {
struct ListNode* newNode;
if(self->length == 0) {
newNode = newListNode(object);
self->first = newNode;
}
else {
newNode = createNextNode(self->last, object);
}
if(newNode != NULL) {
self->last = newNode;
self->length++;
}
return newNode != NULL;
}
如果创建新节点失败,则
addToLinkedList
函数返回 0,而链表本身保持不变。最后,让我们考虑这个将链表中所有元素添加到另一个链表的函数。
void addAllToLinkedList(struct LinkedList* self, const struct LinkedList* other) {
struct ListNode* node = other->first;
while(node != NULL) {
addToLinkedList(self, node->object);
node = node->next;
}
}
如何处理
addToLinkedList
可能返回0的情况?据我所知,当无法再分配内存时,malloc
会失败,因此我认为在分配失败后进行的后续调用也会失败,这样理解对吗?所以,如果返回0,由于无法添加任何新元素到列表中,循环是否应该立即停止?另外,按照我现在的写法,把所有这些检查一个接一个地堆叠在一起,这样做是正确的吗?这不是多余的吗?如果
malloc
失败就立即终止程序,这样做是否有问题?我读到过这样做会对多线程程序产生问题,并且在某些情况下,程序可能能够继续运行而无需进一步分配内存,因此将其视为致命错误在任何情况下都是不正确的。这样做是对的吗?对于这篇很长的文章,非常抱歉,谢谢你的帮助!
malloc
返回NULL
,那么很可能您的程序出现了严重错误,几乎始终是致命错误。 - Jabberwockymalloc
返回NULL
,后续的调用是否也会返回NULL
?这取决于情况。答案大多数情况下是“是”。很难给出一个普遍的答案。 - Jabberwocky