英文:
What could be causing the Segmentation Fault when attempting to print a 2D vector
问题
这是一个作业问题。我正在处理我的Hash Table
作业,并在尝试打印表格时遇到了一些问题。
约束条件:
- C++11
- 不能使用
std::map
或std::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(¤t_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(¤t_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 <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; //returns the hash
}
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);
// DATE FORMAT: 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;
return true;
}
int main() {
CovidDB db;
// Create two DataEntry objects
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);
// 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 << "here";
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<DataEntry*> 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; // <-- 这会在 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->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.
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)
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->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; // <-- 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论