近期在使用结构体指针时遇到段错误,虽然最后解决了,但是有必要在此记录各种坑和解决方案。
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。否则会出现段错误。具体深层次原因,待解!!!!