什么可能导致在尝试打印二维向量时出现分段错误?

huangapple go评论71阅读模式
英文:

What could be causing the Segmentation Fault when attempting to print a 2D vector

问题

这是一个作业问题。我正在处理我的Hash Table作业,并在尝试打印表格时遇到了一些问题。

约束条件:

  • C++11
  • 不能使用std::mapstd::unordered_map

最小可重现示例

#include <iostream>
#include <vector>
#include <atomic>
#include <ctime>
#include <iomanip>
#include <string>

class DataEntry {
public:
  std::string get_date() { return date; }
  std::string get_country() { return country; }
  int get_c_cases() { return c_cases; }
  int get_c_deaths() { return c_deaths; }
  inline void set_date(std::string set_date) { this->date = set_date;};
  inline void set_country(std::string set_country) { this->country = set_country;};
  inline void set_c_deaths(int set_c_deaths) { this->c_deaths = set_c_deaths;};
  inline void set_c_cases(int set_c_cases) { this->c_cases = set_c_cases;};

private:
  std::string date;
  std::string country;
  int c_cases;
  int c_deaths;
};

class CovidDB {
private:
  std::vector<std::vector<DataEntry*>> HashTable;
  int size = 17;

public:
  void display_table();
  bool add(DataEntry* entry);
  int hash(std::string country);
};

int CovidDB::hash(std::string country) {
  int sum = 0;
  int count = 0;
  
  for (char c : country) {
    sum = sum + ((count + 1) * c);
    count++;
  }
  return sum % size; //返回哈希值
}

void CovidDB::display_table() {
  for (const auto& vec : HashTable) {
    for (const auto& entry : vec) {
      if (entry != nullptr) {
        std::cout << "[Date: " << entry->get_date() << "], "
                  << "[Country: " << entry->get_country() << "], "
                  << "[Cases: " << entry->get_c_cases() << "], "
                  << "[Deaths: " << entry->get_c_deaths() << "]" << std::endl;
      }
    }
  }
}

bool CovidDB::add(DataEntry* entry) {
  time_t now = time(0);
  tm* ltm = localtime(&now);
  // 日期格式: mm/dd/yy
  std::string current_date_str = std::to_string(1 + ltm->tm_mon) + "/" + std::to_string(ltm->tm_mday) + "/" + std::to_string(ltm->tm_year % 100);
  std::istringstream iss(current_date_str);
  std::tm current_date = {};
  iss >> std::get_time(&current_date, "%m/%d/%y");
  
  std::tm entry_date = {};
  std::istringstream iss2(entry->get_date());
  iss2 >> std::get_time(&entry_date, "%m/%d/%y");
  
  if (mktime(&current_date) > mktime(&entry_date)) {
    std::cout << "[Record rejected]" << std::endl;   
    return false;
  }
  
  int index = hash(entry->get_country());
  
  if (HashTable[index].empty()) {
    HashTable[index].push_back((entry));
  } else {
    bool added = false;
    for (DataEntry* existing_entry : HashTable[index]) {

      std::atomic<bool> valid(false);
      valid.store(hash(existing_entry->get_country()) == hash(entry->get_country()) &&
                       existing_entry->get_country() == entry->get_country());
      if (valid) {
        existing_entry->set_date(entry->get_date());
        existing_entry->set_c_cases(existing_entry->get_c_cases() + entry->get_c_cases());
        existing_entry->set_c_deaths(existing_entry->get_c_deaths() + entry->get_c_deaths());
        added = true;
        delete entry;
        break;
      }
    }
    if (!added) {
      HashTable[index].push_back(entry);
    }
  }
  return true;
}

int main() {
  CovidDB db;

  // 创建两个DataEntry对象
  DataEntry* entry1 = new DataEntry();
  entry1->set_date("01/01/23");
  entry1->set_country("Slovenia");
  entry1->set_c_cases(1);
  entry1->set_c_deaths(1);

  DataEntry* entry2 = new DataEntry();
  entry2->set_date("02/02/23");
  entry2->set_country("Slovenia");
  entry2->set_c_cases(1);
  entry2->set_c_deaths(1);

  // 将条目添加到CovidDB
  db.add(entry1);
  db.add(entry2);

  // 显示表格
  db.display_table();

  // 释放内存
  delete entry1;
  delete entry2;

  return 0;
}

打印函数似乎在80%的情况下工作正常(估计),例如,当我从.csv文件中推送数据到2D向量并打印时,它工作正常,但当我尝试将相同hash的2个条目分组时出现段错误...

例如:

Country: Slovenia
Date: 01/01/23
Cases: 1
Deaths: 1
Country: Slovenia
Date: 02/02/23
Cases: 1
Deaths: 1

它会导致段错误... 我知道SEGFAULT意味着尝试访问不属于自己的内存(通常尝试解引用nullptr)。

在提问之前,我尝试了很多方法:

橡皮鸭调试

我注意到外部循环运行hash-1次,通过在循环之间添加std::court << "here";,这意味着当涉及到entry的索引时会出现问题。

我还将auto更改为std::vector<DataEntry*> vec以及DataEntry*,因为外部向量是向量的向量,而内部向量是DataEntry指针的向量。

调试

我尝试使用gdb调试可执行文件,因为无法配置我的Vs Code调试器,但它会抛出错误:

缺少独立的调试信息,请使用:yum debuginfo-install glibc-2.28-211.el8.x86_64 libgcc-8.5.0-
<details>
<summary>英文:</summary>
This is a [homework](https://meta.stackoverflow.com/questions/334822/how-do-i-ask-and-answer-homework-questions) question. I am working on my `Hash Table` assignment and I ran into some issues when trying to print the table.
Constraints:
- C++11
- No `std::map` or `std::unordered_map`
**Minimal Reproducible Example**
```C++
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;atomic&gt;
#include &lt;ctime&gt;
#include &lt;iomanip&gt;
#include &lt;string&gt;
class DataEntry {
public:
std::string get_date() { return date; }
std::string get_country() { return country; }
int get_c_cases() { return c_cases; }
int get_c_deaths() { return c_deaths; }
inline void set_date(std::string set_date) { this-&gt;date = set_date;};
inline void set_country(std::string set_country) { this-&gt;country = set_country;};
inline void set_c_deaths(int set_c_deaths) { this-&gt;c_deaths = set_c_deaths;};
inline void set_c_cases(int set_c_cases) { this-&gt;c_cases = set_c_cases;};
private:
std::string date;
std::string country;
int c_cases;
int c_deaths;
};
class CovidDB {
private:
std::vector&lt;std::vector&lt;DataEntry*&gt;&gt; HashTable;
int size = 17;
public:
void display_table();
bool add(DataEntry* entry);
int hash(std::string country);
};
int CovidDB::hash(std::string country) {
int sum = 0;
int count = 0;
for (char c : country) {
sum = sum + ((count + 1) * c);
count++;
}
return sum % size; //returns the hash
}
void CovidDB::display_table() {
for (const auto&amp; vec : HashTable) {
for (const auto&amp; entry : vec) {
if (entry != nullptr) {
std::cout &lt;&lt; &quot;[Date: &quot; &lt;&lt; entry-&gt;get_date() &lt;&lt; &quot;], &quot;
&lt;&lt; &quot;[Country: &quot; &lt;&lt; entry-&gt;get_country() &lt;&lt; &quot;], &quot;
&lt;&lt; &quot;[Cases: &quot; &lt;&lt; entry-&gt;get_c_cases() &lt;&lt; &quot;], &quot;
&lt;&lt; &quot;[Deaths: &quot; &lt;&lt; entry-&gt;get_c_deaths() &lt;&lt; &quot;]&quot; &lt;&lt; std::endl;
}
}
}
}
bool CovidDB::add(DataEntry* entry) {
time_t now = time(0);
tm* ltm = localtime(&amp;now);
// DATE FORMAT: mm/dd/yy
std::string current_date_str = std::to_string(1 + ltm-&gt;tm_mon) + &quot;/&quot; + std::to_string(ltm-&gt;tm_mday) + &quot;/&quot; + std::to_string(ltm-&gt;tm_year % 100);
std::istringstream iss(current_date_str);
std::tm current_date = {};
iss &gt;&gt; std::get_time(&amp;current_date, &quot;%m/%d/%y&quot;);
std::tm entry_date = {};
std::istringstream iss2(entry -&gt; get_date());
iss2 &gt;&gt; std::get_time(&amp;entry_date, &quot;%m/%d/%y&quot;);
if (mktime(&amp;current_date) &gt; mktime(&amp;entry_date)) {
std::cout &lt;&lt; &quot;[Record rejected]&quot; &lt;&lt; std::endl;   
return false;
}
int index = hash(entry -&gt; get_country());
if (HashTable[index].empty()) {
HashTable[index].push_back((entry));
} else {
bool added = false;
for (DataEntry* existing_entry : HashTable[index]) {
std::atomic&lt;bool&gt; valid(false);
valid.store(hash(existing_entry-&gt;get_country()) == hash(entry-&gt;get_country()) &amp;&amp;
existing_entry-&gt;get_country() == entry-&gt;get_country());
if (valid) {
existing_entry-&gt;set_date(entry -&gt; get_date());
existing_entry-&gt;set_c_cases(existing_entry-&gt;get_c_cases() + entry-&gt;get_c_cases());
existing_entry-&gt;set_c_deaths(existing_entry-&gt;get_c_deaths() + entry-&gt;get_c_deaths());
added = true;
delete entry;
break;
}
}
if (!added) {
HashTable[index].push_back(entry);
}
}
return true;
return true;
}
int main() {
CovidDB db;
// Create two DataEntry objects
DataEntry* entry1 = new DataEntry();
entry1-&gt;set_date(&quot;01/01/23&quot;);
entry1-&gt;set_country(&quot;Slovenia&quot;);
entry1-&gt;set_c_cases(1);
entry1-&gt;set_c_deaths(1);
DataEntry* entry2 = new DataEntry();
entry2-&gt;set_date(&quot;02/02/23&quot;);
entry2-&gt;set_country(&quot;Slovenia&quot;);
entry2-&gt;set_c_cases(1);
entry2-&gt;set_c_deaths(1);
// Add the entries to the CovidDB
db.add(entry1);
db.add(entry2);
// Display the table
db.display_table();
// Clean up memory
delete entry1;
delete entry2;
return 0;
}

The print function seems to work fine for 80% of the time (estimate), for instance when I am pushing data from .csv file into the 2D vector and print it works fine, but when I try to group 2 entries of the same hash

eg:

Country: Slovenia
Date: 01/01/23
Cases: 1
Deaths: 1
Country: Slovenia
Date: 02/02/23
Cases: 1
Deaths: 1

It segfaults...I am aware that SEGFAULT means one is trying to access memory that doesn't belong to him (usually trying to deref a nullptr)

I tried loads of stuff before asking a question here:

Rubber duck Debugging

I noticed that the outer loop runs hash-1 times by putting std::court &lt;&lt; &quot;here&quot;; in-between the loops, which means that something goes wrong when it comes to the index of the entry.

I also changed auto to std::vecotr&lt;DataEntry*&gt; vec and to DataEntry* since the outer vector is a vector of vectors and the inner vectors are vectors of DataEntry pointers.

Debugging

I tried debugging the executable with gbd, since I can't configure my Vs Code debugger, but it throws an error

Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-211.el8.x86_64 libgcc-8.5.0-16.el8_7.x86_64 libstdc++-8.5.0-16.el8_7.x86_64

I googled it and the only solution I found was to root install these libraries, which I can't, since this is the school's server and running sudo will get me kicked off.

I tried the XCode debugger but for some reason my code there runs differently...Could it be because the ssh is Linux and the other one isn't?

Guards

I added "guards" to prevent printing an empty hash table, and a guard so that I'm not de-referencing a nullptr, unfortunately, had no effect.

答案1

得分: 2

main程序中,存在一个问题出现在add()函数中,在日期代码之后的第一行:

int index = hash(entry->get_country());
if (HashTable[index].empty()) {
    HashTable[index].push_back((entry));
}

HashTable是一个空向量,但你正在访问它的index位置,这是越界访问。

如果你使用at()而不是[],错误应该会变得明显。

示例

terminate called after throwing an instance of 'std::out_of_range'
  what():  vector::_M_range_check: __n (which is 6) >= this->size() (which is 0)

编辑:由于你提到构造函数将内部向量调整大小为17个条目,另一个潜在的错误是add()函数在传递后delete了该条目,但你的main程序在调用add()之后也delete了相同的条目。

bool CovidDB::add(DataEntry* entry) {
//...
if (valid) {
        existing_entry->set_date(entry -> get_date());
        existing_entry->set_c_cases(existing_entry->get_c_cases() + entry->get_c_cases());
        existing_entry->set_c_deaths(existing_entry->get_c_deaths() + entry->get_c_deaths());
        added = true;
        delete entry;  // &lt;-- 这会在 entry 上发出 delete 调用
        break;
...
int main()
{
   ...
   // 清理内存
   delete entry1;
   delete entry2;

修复方法是在add()函数中删除delete操作。

英文:

Given the main program, one issue is in add(), at the very first line after the date code:

int index = hash(entry-&gt;get_country());
if (HashTable[index].empty()) {
HashTable[index].push_back((entry));
}

The HashTable is an empty vector, yet you are accessing it at index, which is out-of-bounds.

If you used at() instead of [], the error should become obvious.

Example

terminate called after throwing an instance of &#39;std::out_of_range&#39;
what():  vector::_M_range_check: __n (which is 6) &gt;= this-&gt;size() (which is 0)

Edit: Since you mentioned that the constructor resizes the internal vector to 17 entries, the other potential error is that the add() function delete's the entry that was passed, but your main program also delete's the same entry after add() is called.

bool CovidDB::add(DataEntry* entry) {
//...
if (valid) {
existing_entry-&gt;set_date(entry -&gt; get_date());
existing_entry-&gt;set_c_cases(existing_entry-&gt;get_c_cases() + entry-&gt;get_c_cases());
existing_entry-&gt;set_c_deaths(existing_entry-&gt;get_c_deaths() + entry-&gt;get_c_deaths());
added = true;
delete entry;  // &lt;-- This will issue a delete call on entry
break;

...

int main()
{
...
// Clean up memory
delete entry1;
delete entry2;

The fix is to remove the delete in the add() function.

huangapple
  • 本文由 发表于 2023年5月28日 05:12:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76349067.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定