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 nodenode *ptr = new node 等)。 感谢您的帮助!抱歉,我不熟悉 0/3/5 的规则? 包含中的delete ptr; 也无济于事,并且可能是您的段错误的原因。当你为 ptr 分配一个新节点时,你用hash_table[hash_val] 覆盖它,并删除你仍然指向的数据,同时泄露原始分配。 正如之前的评论者所说,代码存在很多问题。与您的问题直接相关的另一个问题是removewhile (strcmp(ptr-&gt;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

Linux下segfault上的自重启程序

c++ segfault 在一个平台(MacOSX)但不是另一个(Linux)

当单独的文件中的类时,使用asio独立的Segfault

gcc+mingw 下的 C++ segfault 但不是 gcc+linux

使用向量和 fstream 的代码中的 Segfault 11? C++