我有一个名为addMod
的函数,当调用该函数时,会将一个节点添加到Module
结构LinkedLists数组的某个索引中,该数组称为System
结构中包含的modules
。Module
结构有一个字符串字段、两个 int 字段和一个指向下一个Module
的指针,前三个字段根据addMod
中提供的参数进行初始化。addMod
大致如下所示:
int addMod(System *system, const char *text, int num1, int num2, int index) {
Module *temp = malloc(sizeof(Module));
Module *current;
temp->next = NULL;
if ([any of the constructors are invalid]) return 0;
temp->text = malloc(strlen(text)+1);
strcpy(temp->text, text);
temp->num1 = num1; temp->num2 = num2;
if (!system->modules[index]) {
system->modules[index] = temp; //If there are no modules in the LinkedList at the given index, makes the head = temp.
}
else {
if (system->compare(temp, system->modules[index]) <= 0) { //compare is a func pointer field of system that compares two Modules to see in what order they should be. Here, we check if temp should become the head of modules[index].
temp->next = system->modules[index]; //Assigns the current head as the module following temp.
system->modules[index] = temp; //Makes temp the current head.
}
else {
current = system->modules[index];
while (current->next && system->compare(temp, current->next) > 0) { //While current isn't the last node in the LinkedList and temp comes after the node after current
current = current->next;
}
temp->next = current->next; //Adds temp in between current and current->next.
current->next = temp;
}
}
return 1;
}
以上所有工作都按预期工作,除了在打印system
的内容时,控制台指示存在内存泄漏,我认为这是因为我未能根据 valgrind 告诉我的内容正确释放temp
。我的问题是不知道在哪里释放它 - 似乎我把它放在任何地方都会导致打印内容后出现段错误。根据我的理解,我必须确保没有其他变量取决于temp
持有的值,但我似乎找不到一种方法来做到这一点,考虑到我的 if 语句的每个可能结尾都会导致将temp
分配给modules
中的节点。在逻辑和return 1
之间放置free(temp)
也会产生段错误,我假设是因为在连续多次调用addMod
时,我经常再次错误地temp
。
总之,要将一个新节点添加到可能填充也可能不填充的 LinkedList,其中这个新节点可以插入 LinkedList 中的任何任意位置,我必须将内存分配给一个临时节点,以便以后可以插入它。成功插入节点后,在哪里释放此分配的内存?
假设您对System
实例的管理是合理的(这是一个很大的假设,因为我看不到该代码),那么您在temp
的内存分配中存在巨大漏洞,在"构造函数"检查失败的情况下,随后会出现硬return 0
。更切中要害:
Module *temp = malloc(sizeof(Module)); // memory allocated here...
Module *current;
temp->next = NULL;
if ([any of the constructors are invalid])
return 0; // and leaked here.
这可能就像交换支票一样简单。显然,应该释放动态分配的其他代码也应该被考虑和评估。
更简单的方法
节点添加代码很复杂,不需要如此。最后,您真正应该关心的是找到新节点所在的位置。
- 如果表中的槽为空,则它是该列表中的第一个节点。
- 如果表中的插槽不为空,请找到排序的位置并将其插入其中。
这两者都可以通过使用指针到指针的单个while循环来完成,其中所述实体持有指针的地址,该指针将在上述任何一种情况下保持新节点,并且作为奖励,手术插入实际上是两个分配。
它是这样完成的。请注意,此代码的大部分只是安全地创建Module
对象。实际插入只是一个 while 循环和一些指针分配。它假定System
中的表最初包含 NULL 条目:
int addMod(System *system, const char *text, int num1, int num2, int index)
{
// allocate new node here
Module *temp = malloc(sizeof *temp);
if (temp == NULL)
{
perror("Failed to allocate new Module");
return 0;
}
size_t len = strlen(text);
temp->text = malloc(len + 1);
if (temp->text == NULL)
{
perror("Failed to allocate module name");
free(temp);
return 0;
}
// finish copying member data
memcpy(temp->text, text, len);
temp->text[len] = 0;
temp->num1 = num1;
temp->num2 = num2;
// now find where it belongs, and set next appropriately
Module **pp = system->modules + index;
while (*pp && system->compare(temp, *pp) <= 0)
pp = &(*pp)->next;
temp->next = *pp;
*pp = temp;
return 1;
}
理解这是从推导出我认为您的System
类型的样子,因为它从未出现过:
typedef struct System
{
Module *modules[MAX_MODULES];
int (*compare)(const Module* lhs, const Module *rhs);
} System;
我相当有信心它与此类似。当然,如果不是,你必须适应。我建议您查看此内容并在调试器中逐步完成它。观看现场直播是无可替代的。
祝你好运。