结构体中定义string变量

2024-01-23 08:32

本文主要是介绍结构体中定义string变量,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

我编写一个程序,在结构体中定义了一个string类型类型的变量:如下:

typedef struct GS_DB_Event_Item_Stru
{
    string strFieldName;
   uint16    usType;    //1    // 1 number, 2 string
  union
  {
    int32  nValue;
    char*  pValue;
   }value;
}GS_DB_Event_Item;

直接使用是可以的,例如:

GS_DB_Event_Item *pEvent = new GS_DB_Event_Item_Stru;

pEvent->strFieldName = "hello";

但是如果通过函数传值再赋值就不可以了,代码如下:

void testString(char *pcName)

{

        GS_DB_Event_Item *pEvent = new GS_DB_Event_Item_Stru;

        memset(pEvent , 0, sizeof(GS_DB_Event_Item ));

        pEvent->strFieldName = pcName;

}

调用的地方:

testString("hello");

如果这么调用的话会有segment fault. 错误, 具体信息如下:

GNU gdb Red Hat Linux (5.2.1-4)
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux"...
(gdb) r
Starting program: /opt/webex/test/bin/teststl

Program received signal SIGSEGV, Segmentation fault.
std::string::operator=(char const*) (this=0x805c3a0, __s=0x8055ea2 "hello")
    at /usr/src/build/146482-i386/BUILD/gcc-3.2-20020903/obj-i386-redhat-linux/i386-redhat-linux/libstdc++-v3/include/bits/basic_string.h:154
154     /usr/src/build/146482-i386/BUILD/gcc-3.2-20020903/obj-i386-redhat-linux/i386-redhat-linux/libstdc++-v3/include/bits/basic_string.h: No such file or directory.
        in /usr/src/build/146482-i386/BUILD/gcc-3.2-20020903/obj-i386-redhat-linux/i386-redhat-linux/libstdc++-v3/include/bits/basic_string.h
(gdb) bt
#0  std::string::operator=(char const*) (this=0x805c3a0, __s=0x8055ea2 "hello")
    at /usr/src/build/146482-i386/BUILD/gcc-3.2-20020903/obj-i386-redhat-linux/i386-redhat-linux/libstdc++-v3/include/bits/basic_string.h:154
#1  0x08049cc6 in testString(char*) (pChar=0x8055ea2 "hello") at teststl.cpp:10
#2  0x08049d0b in main (argc=1, argv=0xbffff404) at teststl.cpp:17
#3  0x40175914 in __libc_start_main () from /lib/libc.so.6
(gdb) f 1

于是,有编写了另外一段代码测试:

typedef struct Test_String_Stru_
{
    string strName;
    int    nID;
}Test_String_Stru;

Test_String_Stru *pStru = new Test_String_Stru;
       pStru->strName = "hello";
    printf("test string is %s \n", pStru->strName.c_str());

这时,没有segment fault, 可以正常运行。

但是如果编写代码如下:

    Test_String_Stru *pStru = new Test_String_Stru;
    memset(pStru, 0, sizeof(Test_String_Stru));
    pStru->strName = "hello";
    printf("test string is %s \n", pStru->strName.c_str());

   就会出现段错误。 看来,问题处在memset上,难道string不能使用memset来初始化??

  问题已经有所头绪,于是,又编写代码如下:

string strTestString;
    memset(&strTestString, 0, sizeof(string));
    strTestString = "hello1";
    printf("strTestString is %s \n", strTestString.c_str());

segment fault又再次出现了,最终的原因可能就是因为是使用了memset导致的。为什么string不能使用memset呢?

于是,猜想string类的内部,string有一些变量,会保存string类的信息,如果使用memset,这些变量的值会被修改。从而导致string里的值被修改,如果这时再对其赋值的话,可能像会对空指针赋值一样,导致非法访问错误。

具体的原因需要深入到string的实现中,由于string的实现是多种多样的,在这里就挑2种来看一下:

 

 

从这两幅图中可以看出,string的内部有一个指针,这个指针指向具体的string的信息。

从下面的调用栈,打印的string的一个对象的信息可以看出,确实存在一个指针,指向一块内存,而内存有一些信息。(我使用的是Linux8.0 redhat

Breakpoint 1, main (argc=1, argv=0xbffff404) at teststl.cpp:184
184         printf("the size of string is %d", sizeof(string));
(gdb) n
185         string *pStr = new string;
(gdb) n
186         delete pStr;
(gdb) p pStr
$1 = (basic_string<char,std::char_traits<char>,std::allocator<char> > *) 0x805c480
(gdb) x /20w 0x805c480
0x805c480:      0x4012f78c      0x00000000      0x00000000      0x00001b79
0x805c490:      0x00000000      0x00000000      0x00000000      0x00000000
0x805c4a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x805c4b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x805c4c0:      0x00000000      0x00000000      0x00000000      0x00000000
(gdb) x /20w  0x4012f78c
0x4012f78c <_ZNSs20_S_empty_rep_storageE+12>:   0x00000000      0x00000000      0x00000000      0x00000000
0x4012f79c <_ZNSbIwSt11char_traitsIwESaIwEE20_S_empty_rep_storageE+12>: 0x00000000      0x00000000      0x00000000      0x00000000
0x4012f7ac <_ZSt8__ioinit+8>:   0x00000000      0x00000000      0x00000000      0x00000000
0x4012f7bc <_ZSt8__ioinit+24>:  0x00000000      0x00000000      0x00000000      0x00000000
0x4012f7cc <emergency_buffer+12>:       0x00000000      0x00000000      0x00000000      0x00000000
(gdb)
那么我们在memset之后,string的内容是什么呢?让我们继续向下看:

the size of string is 4test string is hello
192         string strTestString;
(gdb) n
193         memset(&strTestString, 0, sizeof(string));
(gdb) p &strTestString
$2 = (basic_string<char,std::char_traits<char>,std::allocator<char> > *) 0xbffff390
(gdb) x /20w 0xbffff390
0xbffff390:     0x4012f78c      0xbffff3a4      0xbffff3a8      0x080569d1
0xbffff3a0:     0x4028db48      0x4028d370      0x0805c480      0x0805c480
0xbffff3b0:     0x4016aec8      0x4028d370      0xbffff3d8      0x40175914
0xbffff3c0:     0x00000001      0xbffff404      0xbffff40c      0x400124b8
0xbffff3d0:     0x00000001      0x08049b10      0x00000000      0x08049b31
(gdb) x /20w 0x4012f78c
0x4012f78c <_ZNSs20_S_empty_rep_storageE+12>:   0x00000000      0x00000000      0x00000000      0x00000000
0x4012f79c <_ZNSbIwSt11char_traitsIwESaIwEE20_S_empty_rep_storageE+12>: 0x00000000      0x00000000      0x00000000      0x00000000
0x4012f7ac <_ZSt8__ioinit+8>:   0x00000000      0x00000000      0x00000000      0x00000000
0x4012f7bc <_ZSt8__ioinit+24>:  0x00000000      0x00000000      0x00000000      0x00000000
0x4012f7cc <emergency_buffer+12>:       0x00000000      0x00000000      0x00000000      0x00000000
(gdb) n
194         strTestString = "hello1";
(gdb) p &strTestString
$3 = (basic_string<char,std::char_traits<char>,std::allocator<char> > *) 0xbffff390
(gdb) x/20w 0xbffff390
0xbffff390:     0x00000000      0xbffff3a4      0xbffff3a8      0x080569d1
0xbffff3a0:     0x4028db48      0x4028d370      0x0805c480      0x0805c480
0xbffff3b0:     0x4016aec8      0x4028d370      0xbffff3d8      0x40175914
0xbffff3c0:     0x00000001      0xbffff404      0xbffff40c      0x400124b8
0xbffff3d0:     0x00000001      0x08049b10      0x00000000      0x08049b31

可以发现红色的部分,在memset之后,代表string的指针变为空。

那么如果一个string放在一个结构体中也是同样的道理了。

(gdb) n
187         Test_String_Stru *pStru = new Test_String_Stru;
(gdb) n
188         memset(pStru, 0, sizeof(Test_String_Stru));
(gdb) p *pStru
$1 = {strName = {static npos = Cannot access memory at address 0x86dec28
(gdb) p sizeof(Test_String_Stru)
$2 = 8
(gdb) x /20w 0x86dec28
0x86dec28:      Cannot access memory at address 0x86dec28
(gdb) p pStru
$3 = (Test_String_Stru_ *) 0x805c480
(gdb) x /20w 0x805c480
0x805c480:      0x4012f78c      0x00000000      0x00000000      0x00001b79
0x805c490:      0x00000000      0x00000000      0x00000000      0x00000000
0x805c4a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x805c4b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x805c4c0:      0x00000000      0x00000000      0x00000000      0x00000000
(gdb) n
189         pStru->strName = "hello";
(gdb) x /20w 0x805c480
0x805c480:      0x00000000      0x00000000      0x00000000      0x00001b79
0x805c490:      0x00000000      0x00000000      0x00000000      0x00000000
0x805c4a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x805c4b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x805c4c0:      0x00000000      0x00000000      0x00000000      0x00000000

综上所述,对于string的对象是不能使用memset的,无论是单独使用还是放在结构体中。

所以,结构体中使用string一定要小心,最好使用char *,这样使用memset就不会出错。

===========================================================================================================

如:struct    test
{
string str;
};
之后在main函数中为什么不能赋值;
int main()
{
test test1={"strtest"};
return 0;
}
这样之后就会报错;
求解:为什么??还是因为在结构体中不能定义string变量????
using std::string;已经声明
谢谢各位的回答!主要问题是
如果将name变量声明为字符数组,则可以使用初始化列表进行初始化,如
struct test
{
char name[20];
};
则在main函数中可以这样初始化:
int main()
{
test test1{"strTest"};
return 0;
}
这样程序会正常运行,但,string name; 不行,为什么???
string是标准库中的复杂对象,并不是C++内建数据类型。所以不支持那种大括号内跟一个字符串的初始化赋值方式。
解决办法是使用结构体的构造函数。
struct test
{
test(const char* s): str(s){}
string str;
};
int main()
{
test test1("strtest");
return 0;
}

这篇关于结构体中定义string变量的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/635811

相关文章

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

Python之变量命名规则详解

《Python之变量命名规则详解》Python变量命名需遵守语法规范(字母开头、不使用关键字),遵循三要(自解释、明确功能)和三不要(避免缩写、语法错误、滥用下划线)原则,确保代码易读易维护... 目录1. 硬性规则2. “三要” 原则2.1. 要体现变量的 “实际作用”,拒绝 “无意义命名”2.2. 要让

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

redis数据结构之String详解

《redis数据结构之String详解》Redis以String为基础类型,因C字符串效率低、非二进制安全等问题,采用SDS动态字符串实现高效存储,通过RedisObject封装,支持多种编码方式(如... 目录一、为什么Redis选String作为基础类型?二、SDS底层数据结构三、RedisObject

Java集合中的链表与结构详解

《Java集合中的链表与结构详解》链表是一种物理存储结构上非连续的存储结构,数据元素的逻辑顺序的通过链表中的引用链接次序实现,文章对比ArrayList与LinkedList的结构差异,详细讲解了链表... 目录一、链表概念与结构二、当向单链表的实现2.1 准备工作2.2 初始化链表2.3 打印数据、链表长

创建springBoot模块没有目录结构的解决方案

《创建springBoot模块没有目录结构的解决方案》2023版IntelliJIDEA创建模块时可能出现目录结构识别错误,导致文件显示异常,解决方法为选择模块后点击确认,重新校准项目结构设置,确保源... 目录创建spChina编程ringBoot模块没有目录结构解决方案总结创建springBoot模块没有目录