Linux 中的 Segfault,在 Mac OS 上运行良好
Posted
技术标签:
【中文标题】Linux 中的 Segfault,在 Mac OS 上运行良好【英文标题】:Segfault in Linux, works fine on Mac OS 【发布时间】:2015-09-29 03:58:13 【问题描述】:我正在做一个 C++ 家庭作业,我们必须在其中构建一个单链表哈希表。我已经在 Mac 上编写了我的代码 - 它可以很好地编译并完美地生成预期的输出。但是,当我在 Linux 中运行程序时,会出现段错误(核心转储)。使用 gdb 调试时,我收到消息
Program received signal SIGSEGV, Segmentation fault.
__strcmp_sse2 () at ../sysdeps/x86_64/multiarch/../strcmp.S:210
210 ../sysdeps/x86_64/multiarch/../strcmp.S: No such file or directory.
我在本网站上其他发布的问题中读到,在这种情况下 gdb 具有误导性,并且该问题与“strcmp”功能无关。但是,我无法查看代码中的问题所在。如果有人能指出我正确的方向,将不胜感激。 TIA。
//string_set.cpp
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "string_set.h"
using namespace std;
string_set::string_set()
for (int i = 0; i < HASH_TABLE_SIZE; i++) //initializing empty hash table
hash_table[i] = NULL;
//end for
iterator_index = 0;
iterator_node = hash_table[iterator_index];
void string_set::add(const char *s)
int hash_val = hash_function(s);
if (contains(s) == 1)
throw duplicate_exception();
//end if
node *a = new node;
if (a==NULL)
throw memory_exception();
//end if
a->s = new char[strlen(s) + 1];
if (a == NULL)
delete a;
throw memory_exception();
//end if
strcpy(a->s, s);
a->next = hash_table[hash_val];
hash_table[hash_val] = a;
if (contains(s) == 0)
throw memory_exception();
//end if
else
reset();
//end else
void string_set::remove(const char *s)
if (contains(s) == 0)
throw not_found_exception();
//end if
int hash_val = hash_function(s);
node *prev = new node;
prev = hash_table[hash_val];
node *ptr = new node;
ptr = hash_table[hash_val];
while (strcmp(ptr->s, s) != 0) //
prev = ptr;
ptr = ptr->next;
//end while
if (prev == ptr) //if node to be deleted is first in list
hash_table[hash_val] = ptr->next;
//end if
delete ptr->s;
prev->next = ptr->next;
delete ptr;
reset();
int string_set::contains(const char *s)
int hash_val = hash_function(s);
node *ptr = new node;
ptr = hash_table[hash_val];
while (ptr != NULL)
if (strcmp(s, ptr->s) == 0) //
delete ptr;
return 1;
//end if
else
ptr = ptr->next;
//end else
//end while
return 0;
void string_set::reset()
iterator_index = 0;
iterator_node = hash_table[iterator_index];
const char *string_set::next()
if (iterator_node != NULL)
char copy[strlen(iterator_node->s) + 1];
strcpy(copy, iterator_node->s);
iterator_node = iterator_node->next;
return copy;
//end if
while (iterator_index < HASH_TABLE_SIZE - 1)
while (iterator_node == NULL)
++iterator_index;
iterator_node = hash_table[iterator_index];
if ((iterator_index == HASH_TABLE_SIZE - 1) && (iterator_node == NULL))
return NULL;
//end nested while
char copy[strlen(iterator_node->s) + 1];
strcpy(copy, iterator_node->s);
iterator_node = iterator_node->next;
return copy;
//end while
return NULL;
string_set::~string_set()
reset();
node *ptr = new node;
ptr = iterator_node;
while (ptr != NULL)
delete ptr->s;
next();
ptr = iterator_node;
//end while
delete ptr;
int string_set::hash_function(const char *s)
int sum = 0;
for (unsigned int ind = 0; ind < strlen(s); ind++) //summing elements in string s
sum += s[ind];
sum = sum % HASH_TABLE_SIZE;
//end for
return sum % HASH_TABLE_SIZE;
string_set.h
using namespace std;
class string_set
public:
/*Purpose
initialize the set to contain no elements
* Preconditions
none
* Exceptions
none
*/
string_set();
/*Purpose
* add s to the set
* if s is successfully added, reset the iterator
* Preconditions
* s is a legal string
* Exceptions
* if s is already present then throw duplicate_exception
* else if s there is not enough memory to add s then throw memory_exception
*/
void add(const char *s);
/*Purpose
* remove s from the set
* if s is successfully removed, reset the iterator
* Preconditions
* s is a legal string
* Exceptions
* if s is not present then throw not_found_exception
*/
void remove(const char *s);
/*Purpose
* return 1 if s is in the set and 0 otherwise
* Preconditions
* s is a legal string
* Exceptions
* none
*/
int contains(const char *s);
/*Purpose
* reset the iterator to the first element
* Preconditions
* none
* Exceptions
* none
*/
void reset();
/*Purpose
* return a pointer to the next set element
* return NULL if no more elements remain
* Preconditions
* none
* Exceptions
* none
*/
const char *next();
/*Purpose
* delete all dynamically allocated memory
* Preconditions
* none
* Exceptions
* none
*/
~string_set();
private:
/*Purpose
* return the hash value h associated with s
* h must consist of: (sum of the characters in s) mod HASH_TABLE_SIZE
* Preconditions
* s is a legal string
* Exceptions
* none
* Examples
* hash_function("a") returns 97
* hash_function("ab") returns 95
* hash_function("ba") returns 95
* hash_function("") returns 0
*/
int hash_function(const char *s);
enum HASH_TABLE_SIZE = 100;
class node
public:
char *s;
node *next;
;
// hash_table[i] is the head of a linked list of nodes
node *hash_table[HASH_TABLE_SIZE];
// iterator position
int iterator_index; // index in hash_table
node *iterator_node; // node in hash_table[iterator_index];
;
class duplicate_exception ;
class memory_exception ;
class not_found_exception ;
【问题讨论】:
这段代码有很多不可靠的地方(带有指针成员的类,没有 0/3/5 规则,可变长度数组,原始内存分配),但也许是导致你问题是string_set::next()
返回一个指向本地数组的指针 (copy
)。还有一些明显的内存泄漏(node *prev = new node
、node *ptr = new node
等)。
感谢您的帮助!抱歉,我不熟悉 0/3/5 的规则?
包含中的delete ptr;
也无济于事,并且可能是您的段错误的原因。当你为 ptr 分配一个新节点时,你用hash_table[hash_val]
覆盖它,并删除你仍然指向的数据,同时泄露原始分配。
正如之前的评论者所说,代码存在很多问题。与您的问题直接相关的另一个问题是remove
:while (strcmp(ptr->s, s) != 0)
。在进行比较之前,您需要检查 ptr
是否为 NULL。
@anon en.cppreference.com/w/cpp/language/rule_of_three
【参考方案1】:
contains
函数中的这些代码行:
if (strcmp(s, ptr->s) == 0) //
delete ptr;
将删除您刚刚找到的节点的内存,当您稍后尝试使用该节点时会导致未定义的行为。
在代码中的几个地方,您为指针分配了一个新节点,然后立即将指针指向不同的位置——这将导致内存泄漏,并可能导致您删除您无意删除的内容。
node *ptr = new node;
ptr = hash_table[hash_val];
应该是
node *ptr = hash_table[hash_val];
然后就不需要相应的delete
(除非您实际上是在删除节点)。
【讨论】:
谢谢! RE: 节点 *ptr = 新节点; ptr = hash_table[hash_val];毕竟不应该听我的教授的话......以上是关于Linux 中的 Segfault,在 Mac OS 上运行良好的主要内容,如果未能解决你的问题,请参考以下文章
从Assembly调用C函数(printf)时的Segfault
c++ segfault 在一个平台(MacOSX)但不是另一个(Linux)