剑指 Offer 25. 合并两个排序的链表 - 力扣(LeetCode) (leetcode-cn.com)
错误信息
AddressSanitizer
AddressSanitizer is a fast memory error detector(内存错误探测器). It consists of a compiler instrumentation module (编译器检测模块)and a run-time library. The tool can detect the following types of bugs:
1. Out-of-bounds accesses to heap, stack and globals //堆、栈、全局变量越界访问
2. Use-after-free
3. Use-after-return
4. Use-after-scope //作用域外使用
5. Double-free, invalid free
6. Memory leaks (experimental)
SEGV
-
From Cadence Community
SEGV means "segmentation fault"(分段故障). It simply mean that the program is accessing a memory that it should not. This is due to software error, that lead to corrupted memory pointers, etc.Simply put, this error message is not useful to find the cause of the software crash.
-
From Wikipedia
In computing, a segmentation fault (often shortened to segfault) or access violation(访问冲突) is a fault, or failure condition, raised by hardware with memory protection, notifying an OS the software has attempted to access a restricted area of memory (a memory access violation). On stantard x86 computers, this is a form of general protection fault. The OS kernel will, in response, usually perform some corrective action(纠正措施), generally passing the fault on to the offending process by sending the process a signal. Process can in some cases install a custom signal handler(自定义信号处理程序), allowing them to recover on their own, but otherwise the OS default signal handler(操作系统默认信号处理程序) is used, generally causing abnormal termination(异常终止) of the process (a program crash), and sometimes a core dump(核心转储).
ABORTING:终止
错误代码
class lst {
ListNode* p;
const ListNode* preHead;
public:
lst() :p(new ListNode(0)), preHead(p) {}
lst(ListNode* l) :p(l) {}
~lst() {
delete preHead;
}
ListNode* head() const {
return preHead->next;
}
void operator++() {
p = p->next;
}
lst operator++(int k) {
ListNode* tmp = p;
p = p->next;
return tmp;
}
bool not_empty() {
return p != NULL;
}
int _val() const {
return p->val;
}
ListNode* ptr() const {
return p;
}
void add(const lst L) {//参数也是局部变量,在函数结束之后,作为参数的对象会被析构
p->next = L.ptr();
p = p->next; //*问题出在这里,这条语句应该去掉
}
bool compare(const lst& L) const {
return this->_val() > L._val();
}
};
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
lst L1(l1), L2(l2), iter;
while (L1.not_empty() && L2.not_empty()) {
iter.add(L2.compare(L1) ? L1++ : L2++);
++iter;
}
iter.add(L1.not_empty() ? L1 : L2);
return iter.head();
}
};
如果注释掉析构函数,出现问题:
调试过程中发现,每次执行完add函数之后,析构函数都会被调用一次。猜想应该是由于add函数传递的参数是对象而非对象的引用,作为函数内部局部变量的对象在函数调用完之后会被析构。
经过调试,发现错因是add函数的第二条语句"p = p->next"属实多余,不该出现在这个位置,去掉之后,顺利通过.