使用带map容器的struct结构体指针引发的段错误

本文探讨了在C++中使用包含容器如vector和map的结构体时可能遇到的问题及解决办法,特别是针对内存分配和初始化的具体实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 近期在使用结构体指针时遇到段错误,虽然最后解决了,但是有必要在此记录各种坑和解决方案。

1. 结构体指针没有初始化:

#include <map>
#include <iostream>
#include <unistd.h>
#include <vector>


using namespace std;

struct node
{
	int id;
	float length;
	vector<int> passwords;
	struct node *next;
};

int main(int argc, char **argv)
{
    struct node *n;
    
    n->id =1;
    n->length=1.24;
    n->passwords.push_back(1);
    n->passwords.push_back(2);
    n->passwords.push_back(3);
    n->next = NULL;
    
    printf("sizeof(struct node) = %d\n",sizeof(struct node));
    printf("sizeof(int) = %d\n",sizeof(int));
    printf("sizeof(float) = %d\n",sizeof(float));
    printf("sizeof(vector<int>) = %d\n",sizeof(vector<int>));
    printf("sizeof(struct node*) = %d\n",sizeof(struct node*));
    
    printf("n addr = %p\n",n);
    printf("n->id addr = %p\n",&(n->id));
    printf("n->length addr = %p\n",&(n->length));
    printf("n->passwords addr = %p\n",&(n->passwords));
    printf("n->next addr = %p\n",&(n->next));
     
    
    return 0;
}

代码执行后,报段错误,什么输出都灭有!

这个好解决,是因为指针n为随机值,灭有进行初始化。增加n = (struct node *)malloc(sizeof(struct node));即可。

2.  struct中有vector这种结构

#include <map>
#include <iostream>
#include <unistd.h>
#include <vector>


using namespace std;

struct node
{
	int id;
	float length;
	vector<int> passwords;
	struct node *next;
};

int main(int argc, char **argv)
{
    struct node *n = ( struct node *)malloc(sizeof( struct node));
    
    n->id =1;
    n->length=1.24;
    n->passwords.push_back(1);
    n->passwords.push_back(2);
    n->passwords.push_back(3);
    n->next = NULL;
    
    printf("sizeof(struct node) = %d\n",sizeof(struct node));
    printf("sizeof(int) = %d\n",sizeof(int));
    printf("sizeof(float) = %d\n",sizeof(float));
    printf("sizeof(vector<int>) = %d\n",sizeof(vector<int>));
    printf("sizeof(struct node*) = %d\n",sizeof(struct node*));
    
    printf("n addr = %p\n",n);
    printf("n->id addr = %p\n",&(n->id));
    printf("n->length addr = %p\n",&(n->length));
    printf("n->passwords addr = %p\n",&(n->passwords));
    printf("n->next addr = %p\n",&(n->next));
     
    
    return 0;
}

 说明struct中带了vector这种容器时,我们使用malloc对结构体对象指针进行初始化是没有问题的。

更进一步,我们发现sizeof(vector<int>>)的大小为24,这个就有点意思了,实际上跟插入vector的数据量无关。我们打印一下vector的各项地址:

#include <map>
#include <iostream>
#include <unistd.h>
#include <vector>


using namespace std;

struct node
{
	int id;
	float length;
	vector<int> passwords;
	struct node *next;
};

int main(int argc, char **argv)
{
    struct node *n=(struct node*)malloc(sizeof(struct node));
    
    n->id =1;
    n->length=1.24;
    n->passwords.push_back(1);
    n->passwords.push_back(2);
    n->passwords.push_back(3);
    n->passwords.push_back(4);
    n->passwords.push_back(5);
    n->passwords.push_back(6);
    n->passwords.push_back(7);
    n->passwords.push_back(8);
    n->passwords.push_back(9);
    n->next = NULL;
    
    printf("sizeof(struct node) = %d\n",sizeof(struct node));
    printf("sizeof(int) = %d\n",sizeof(int));
    printf("sizeof(float) = %d\n",sizeof(float));
    printf("sizeof(vector<int>) = %d\n",sizeof(vector<int>));
    printf("sizeof(struct node*) = %d\n",sizeof(struct node*));
    
    printf("n addr = %p\n",n);
    printf("n->id addr = %p\n",&(n->id));
    printf("n->length addr = %p\n",&(n->length));
    printf("n->passwords addr = %p\n",&(n->passwords));
    printf("n->next addr = %p\n",&(n->next));
     
    for(int i=0;i<24;i++)
    {
      printf("%02X ",*(((unsigned char *)(&(n->passwords)))+i));
    }
    for(int i=0;i<9;i++)
    {
      printf("n->passwords[%d] addr = %p\n",i,&((n->passwords[i])));
    }
    return 0;
}

这里可以看到struct中给vector<int>申请的24个字节,存储了3个值。经过多次验证,可以确定分别为vector的首地址(第一个元素的地址),下一个插入的地址,和将来vector进行扩展时的地址(当vector的下一个插入地址达到了未来扩展地址,则vector会再申请一段空间来用)。

经过多次验证,确定在struct中使用vector并没有什么问题。

3.  struct中有map这种结构

#include <map>
#include <iostream>
#include <unistd.h>
#include <vector>


using namespace std;

struct node
{
	int id;
	float length;
	vector<int> passwords;
	map<std::string,int> amap;
	struct node *next;
};

int main(int argc, char **argv)
{
    struct node *n=(struct node*)malloc(sizeof(struct node));
    
    n->id =1;
    n->length=1.24;
    n->passwords.push_back(1);
    n->passwords.push_back(2);
    n->passwords.push_back(3);
    n->passwords.push_back(4);
    n->passwords.push_back(5);
    n->passwords.push_back(6);
    n->passwords.push_back(7);
    n->passwords.push_back(8);
    n->passwords.push_back(9);
    n->next = NULL;
    
    printf("sizeof(struct node) = %d\n",sizeof(struct node));
    printf("sizeof(int) = %d\n",sizeof(int));
    printf("sizeof(float) = %d\n",sizeof(float));
    printf("sizeof(vector<int>) = %d\n",sizeof(vector<int>));
    printf("sizeof(map<std::string,int>) = %d\n",sizeof(map<std::string,int>));
    printf("sizeof(struct node*) = %d\n",sizeof(struct node*));
    
    printf("n addr = %p\n",n);
    printf("n->id addr = %p\n",&(n->id));
    printf("n->length addr = %p\n",&(n->length));
    printf("n->passwords addr = %p\n",&(n->passwords));
    printf("n->next addr = %p\n",&(n->next));
    printf("n->amap addr = %p\n",&(n->amap));
     
    for(int i=0;i<24;i++)
    {
      printf("%02X ",*(((unsigned char *)(&(n->passwords)))+i));
    }
    for(int i=0;i<9;i++)
    {
      printf("n->passwords[%d] addr = %p\n",i,&((n->passwords[i])));
    }
    
    n->amap.insert(std::make_pair("123",1));
    printf("insert key/value finished!\n");
    return 0;
}

发现,sizeof(map<std::string,int>)为48字节,估计和vector的情形一致。但是后续的插入失败。我们想着前面我已经为node申请空间了,并且n->amap是有地址的,为什么还无法插入呢?我们把这48个字节打印出来:

#include <map>
#include <iostream>
#include <unistd.h>
#include <vector>


using namespace std;

struct node
{
	int id;
	float length;
	vector<int> passwords;
	map<std::string,int> amap;
	struct node *next;
};

int main(int argc, char **argv)
{
    struct node *n=(struct node*)malloc(sizeof(struct node));
    
    n->id =1;
    n->length=1.24;
    n->passwords.push_back(1);
    n->passwords.push_back(2);
    n->passwords.push_back(3);
    n->passwords.push_back(4);
    n->passwords.push_back(5);
    n->passwords.push_back(6);
    n->passwords.push_back(7);
    n->passwords.push_back(8);
    n->passwords.push_back(9);
    n->next = NULL;
    
    printf("sizeof(struct node) = %d\n",sizeof(struct node));
    printf("sizeof(int) = %d\n",sizeof(int));
    printf("sizeof(float) = %d\n",sizeof(float));
    printf("sizeof(vector<int>) = %d\n",sizeof(vector<int>));
    printf("sizeof(map<std::string,int>) = %d\n",sizeof(map<std::string,int>));
    printf("sizeof(struct node*) = %d\n",sizeof(struct node*));
    
    printf("n addr = %p\n",n);
    printf("n->id addr = %p\n",&(n->id));
    printf("n->length addr = %p\n",&(n->length));
    printf("n->passwords addr = %p\n",&(n->passwords));
    printf("n->next addr = %p\n",&(n->next));
    printf("n->amap addr = %p\n",&(n->amap));
    
    
    
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("*******************\n");
    
    for(int i=0;i<24;i++)
    {
      printf("%02X ",*(((unsigned char *)(&(n->passwords)))+i));
    }
    for(int i=0;i<9;i++)
    {
      printf("n->passwords[%d] addr = %p\n",i,&((n->passwords[i])));
    }
    
    n->amap.insert(std::make_pair("123",1));
    printf("insert key/value finished!\n");
    return 0;
}

发现map所占的48个字节全是0,如果真的是和vector相似,那么后面往0这个地址插入内容,肯定出错。

#include <map>
#include <iostream>
#include <unistd.h>
#include <vector>


using namespace std;

struct node
{
	int id;
	float length;
	vector<int> passwords;
	map<std::string,int> amap;
	struct node *next;
};

int main(int argc, char **argv)
{
    struct node *n=(struct node*)malloc(sizeof(struct node));
    
    n->id =1;
    n->length=1.24;
    n->passwords.push_back(1);
    n->passwords.push_back(2);
    n->passwords.push_back(3);
    n->passwords.push_back(4);
    n->passwords.push_back(5);
    n->passwords.push_back(6);
    n->passwords.push_back(7);
    n->passwords.push_back(8);
    n->passwords.push_back(9);
    n->next = NULL;
    
    printf("sizeof(struct node) = %d\n",sizeof(struct node));
    printf("sizeof(int) = %d\n",sizeof(int));
    printf("sizeof(float) = %d\n",sizeof(float));
    printf("sizeof(vector<int>) = %d\n",sizeof(vector<int>));
    printf("sizeof(map<std::string,int>) = %d\n",sizeof(map<std::string,int>));
    printf("sizeof(struct node*) = %d\n",sizeof(struct node*));
    
    printf("n addr = %p\n",n);
    printf("n->id addr = %p\n",&(n->id));
    printf("n->length addr = %p\n",&(n->length));
    printf("n->passwords addr = %p\n",&(n->passwords));
    printf("n->next addr = %p\n",&(n->next));
    printf("n->amap addr = %p\n",&(n->amap));
    
    
    
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("*******************\n");
    
    for(int i=0;i<24;i++)
    {
      printf("%02X ",*(((unsigned char *)(&(n->passwords)))+i));
    }
    for(int i=0;i<9;i++)
    {
      printf("n->passwords[%d] addr = %p\n",i,&((n->passwords[i])));
    }
    
    std::map<std::string,int> tmpMap;
    
    tmpMap.insert(std::make_pair("123",1));
    
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(tmpMap)))+i));
    }
    printf("----------------------\n");
    
    n->amap = tmpMap;
    
    printf("insert key/value finished!\n");
     
     for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(tmpMap)))+i));
    }
    printf("+++++++++++++++++++++\n");
    
     for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("*******************\n");
    
    printf("n->amap[\"123\"]=%d\n",n->amap["123"]);
    n->amap["234"]=2;
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("*=========================\n");
    printf("n->amap[\"234\"]=%d\n",n->amap["234"]);
    
    n->amap.insert(std::make_pair("345",3));
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("||||||||||||||||||||||\n");
    
    printf("n->amap[\"345\"]=%d\n",n->amap["345"]);
    return 0;
}

通过上述结果,我们发现,只要将n->amap进行了初始化(先将一个临时map赋值,然后将内容给它),后面就可以使用各种方式进行插入。

#include <map>
#include <iostream>
#include <unistd.h>
#include <vector>


using namespace std;

struct node
{
	int id;
	float length;
	vector<int> passwords;
	map<std::string,int> amap;
	struct node *next;
};

int main(int argc, char **argv)
{
    struct node *n=(struct node*)malloc(sizeof(struct node));
    
    n->id =1;
    n->length=1.24;
    n->passwords.push_back(1);
    n->passwords.push_back(2);
    n->passwords.push_back(3);
    n->passwords.push_back(4);
    n->passwords.push_back(5);
    n->passwords.push_back(6);
    n->passwords.push_back(7);
    n->passwords.push_back(8);
    n->passwords.push_back(9);
    n->next = NULL;
    
    printf("sizeof(struct node) = %d\n",sizeof(struct node));
    printf("sizeof(int) = %d\n",sizeof(int));
    printf("sizeof(float) = %d\n",sizeof(float));
    printf("sizeof(vector<int>) = %d\n",sizeof(vector<int>));
    printf("sizeof(map<std::string,int>) = %d\n",sizeof(map<std::string,int>));
    printf("sizeof(struct node*) = %d\n",sizeof(struct node*));
    
    printf("n addr = %p\n",n);
    printf("n->id addr = %p\n",&(n->id));
    printf("n->length addr = %p\n",&(n->length));
    printf("n->passwords addr = %p\n",&(n->passwords));
    printf("n->next addr = %p\n",&(n->next));
    printf("n->amap addr = %p\n",&(n->amap));
    
    
    
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("*******************\n");
    
    for(int i=0;i<24;i++)
    {
      printf("%02X ",*(((unsigned char *)(&(n->passwords)))+i));
    }
    for(int i=0;i<9;i++)
    {
      printf("n->passwords[%d] addr = %p\n",i,&((n->passwords[i])));
    }
    
    std::map<std::string,int> tmpMap;
    std::map<std::string,int> *tmpMap2 =(std::map<std::string,int>*)malloc(sizeof(std::map<std::string,int>));
    printf("malloc a map!\n");
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)tmpMap2)+i));
    }
    printf("xxxxxxxxxxxxxxxxxxxx\n");
    tmpMap2->insert(std::make_pair("123",1));
    printf("malloc and insert to map!\n");
    
    tmpMap.insert(std::make_pair("123",1));
    
    /*tmpMap2 = &tmpMap;
     for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)tmpMap2)+i));
    }
    printf("yyyyyyyyyyyyyyyyyyyy\n");
    */
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(tmpMap)))+i));
    }
    printf("----------------------\n");
    
    n->amap = tmpMap;
    
    printf("insert key/value finished!\n");
     
     for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(tmpMap)))+i));
    }
    printf("+++++++++++++++++++++\n");
    
     for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("*******************\n");
    
    printf("n->amap[\"123\"]=%d\n",n->amap["123"]);
    n->amap["234"]=2;
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("*=========================\n");
    printf("n->amap[\"234\"]=%d\n",n->amap["234"]);
    
    n->amap.insert(std::make_pair("345",3));
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("||||||||||||||||||||||\n");
    
    printf("n->amap[\"345\"]=%d\n",n->amap["345"]);
    return 0;
}

上述,我们将map进行了malloc,然后调用insert函数,也是出现段错误。

 这说明无论哪种情况,map的指针即使malloc申请了地址,也无法使用insert函数进行插入。如果把map指针指向一个具体的map,就可以使用。

而对于结构体中的map,我们只能把它当作一个没有初始化的map(或者说,并没有给它开辟空间)。

#include <map>
#include <iostream>
#include <unistd.h>
#include <vector>


using namespace std;

struct node
{
	int id;
	float length;
	vector<int> passwords;
	map<std::string,int> amap;
	struct node *next;
};

int main(int argc, char **argv)
{
    struct node *n=(struct node*)malloc(sizeof(struct node));
    
    n->id =1;
    n->length=1.24;
    n->passwords.push_back(1);
    n->passwords.push_back(2);
    n->passwords.push_back(3);
    n->passwords.push_back(4);
    n->passwords.push_back(5);
    n->passwords.push_back(6);
    n->passwords.push_back(7);
    n->passwords.push_back(8);
    n->passwords.push_back(9);
    n->next = NULL;
    
    printf("sizeof(struct node) = %d\n",sizeof(struct node));
    printf("sizeof(int) = %d\n",sizeof(int));
    printf("sizeof(float) = %d\n",sizeof(float));
    printf("sizeof(vector<int>) = %d\n",sizeof(vector<int>));
    printf("sizeof(map<std::string,int>) = %d\n",sizeof(map<std::string,int>));
    printf("sizeof(struct node*) = %d\n",sizeof(struct node*));
    
    printf("n addr = %p\n",n);
    printf("n->id addr = %p\n",&(n->id));
    printf("n->length addr = %p\n",&(n->length));
    printf("n->passwords addr = %p\n",&(n->passwords));
    printf("n->next addr = %p\n",&(n->next));
    printf("n->amap addr = %p\n",&(n->amap));
    
    
    
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("*******************\n");
    
    for(int i=0;i<24;i++)
    {
      printf("%02X ",*(((unsigned char *)(&(n->passwords)))+i));
    }
    for(int i=0;i<9;i++)
    {
      printf("n->passwords[%d] addr = %p\n",i,&((n->passwords[i])));
    }
    
    std::map<std::string,int> tmpMap;
    std::map<std::string,int> *tmpMap2 =(std::map<std::string,int>*)malloc(sizeof(std::map<std::string,int>));
    printf("malloc a map!\n");
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)tmpMap2)+i));
    }
    printf("xxxxxxxxxxxxxxxxxxxx\n");
   // tmpMap2->insert(std::make_pair("123",1));
    //printf("malloc and insert to map!\n");
    
    tmpMap.insert(std::make_pair("123",1));
    
    tmpMap2 = &tmpMap;
     for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)tmpMap2)+i));
    }
    printf("yyyyyyyyyyyyyyyyyyyy\n");
    
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(tmpMap)))+i));
    }
    printf("----------------------\n");
    
    n->amap = tmpMap;
    
    printf("insert key/value finished!\n");
     
     for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(tmpMap)))+i));
    }
    printf("+++++++++++++++++++++\n");
    
     for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("*******************\n");
    
    printf("n->amap[\"123\"]=%d\n",n->amap["123"]);
    n->amap["234"]=2;
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("*=========================\n");
    printf("n->amap[\"234\"]=%d\n",n->amap["234"]);
    
    n->amap.insert(std::make_pair("345",3));
    for(int i=0;i<48;i++)
    {
     printf("%02X ",*(((unsigned char *)(&(n->amap)))+i));
    }
    printf("||||||||||||||||||||||\n");
    
    printf("n->amap[\"345\"]=%d\n",n->amap["345"]);
    return 0;
}

即使把结构体中的amap改成指针,上述问题同样存在。

结论:struct中如果有map容器,则一定要用一个临时map对struct中的map赋值,然后才可以直接使用struct中的map。否则会出现段错误。具体深层次原因,待解!!!!

### 如何从 C++ 的 `map` 中取出结构体元素 在 C++ 中,要从 `std::map` 容器中检索存储的结构体对象,可以使用键来访问对应的值。下面展示了一个具体的例子: 假设有一个名为 `Person` 的结构体定义如下[^1]: ```cpp struct Person { std::string name; std::string last_name; int age; // 使用宏定义使结构可内省 BOOST_HANA_DEFINE_STRUCT(Person, (std::string, name), (std::string, last_name), (int, age)); }; ``` 创建并初始化一个包含 `Person` 对象的地图之后,可以通过提供相应的键来获取该键所映射到的对象实例。 #### 获取单个条目 如果想要通过特定的关键字取得单一项目,则可以直接利用下标运算符 (`operator[]`) 或者成员函数 `at()` 方法来进行操作。需要注意的是,当指定不存在于容器中的键时,这两种方式的行为有所不同——前者会在找不到匹配项的情况下自动插入一个新的默认构造出来的元素;而后者则会抛出异常 `out_of_range` 来报告错误情况。 下面是具体实现代码片段: ```cpp #include <iostream> #include <map> #include <memory> // 假设已经包含了必要的头文件以及命名空间声明... void print_person(const Person& p) { std::cout << "Name: " << p.name << ", Last Name: " << p.last_name << ", Age: " << p.age << '\n'; } int main() { // 创建一个关联字符串作为键、共享指针指向 Person 类型数据的地图 std::map<std::string, std::shared_ptr<Person>> people_map; // 插入一些测试数据... auto person_john = std::make_shared<Person>(Person{"John", "Doe", 30}); people_map["john"] = person_john; try { // 尝试读取已存在的记录 const auto& found_person = *people_map.at("john"); print_person(found_person); // 如果尝试访问不存在的键将会引发 out_of_range 异常 // 这里仅用于示范目的,在实际应用中应先检查是否存在此键 // const auto& missing_person = *people_map.at("nonexistent_key"); } catch (const std::out_of_range &e) { std::cerr << e.what(); } return 0; } ``` 这段程序展示了如何安全地从地图中提取结构体,并处理可能遇到的各种情形。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值