结构体中定义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

相关文章

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2

如何使用Maven创建web目录结构

《如何使用Maven创建web目录结构》:本文主要介绍如何使用Maven创建web目录结构的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录创建web工程第一步第二步第三步第四步第五步第六步第七步总结创建web工程第一步js通过Maven骨架创pytho

Python循环结构全面解析

《Python循环结构全面解析》循环中的代码会执行特定的次数,或者是执行到特定条件成立时结束循环,或者是针对某一集合中的所有项目都执行一次,这篇文章给大家介绍Python循环结构解析,感兴趣的朋友跟随... 目录for-in循环while循环循环控制语句break语句continue语句else子句嵌套的循

Python变量与数据类型全解析(最新整理)

《Python变量与数据类型全解析(最新整理)》文章介绍Python变量作为数据载体,命名需遵循字母数字下划线规则,不可数字开头,大小写敏感,避免关键字,本文给大家介绍Python变量与数据类型全解析... 目录1、变量变量命名规范python数据类型1、基本数据类型数值类型(Number):布尔类型(bo

CSS Anchor Positioning重新定义锚点定位的时代来临(最新推荐)

《CSSAnchorPositioning重新定义锚点定位的时代来临(最新推荐)》CSSAnchorPositioning是一项仍在草案中的新特性,由Chrome125开始提供原生支持需... 目录 css Anchor Positioning:重新定义「锚定定位」的时代来了! 什么是 Anchor Pos

一文全面详解Python变量作用域

《一文全面详解Python变量作用域》变量作用域是Python中非常重要的概念,它决定了在哪里可以访问变量,下面我将用通俗易懂的方式,结合代码示例和图表,带你全面了解Python变量作用域,需要的朋友... 目录一、什么是变量作用域?二、python的四种作用域作用域查找顺序图示三、各作用域详解1. 局部作

java String.join()方法实例详解

《javaString.join()方法实例详解》String.join()是Java提供的一个实用方法,用于将多个字符串按照指定的分隔符连接成一个字符串,这一方法是Java8中引入的,极大地简化了... 目录bVARxMJava String.join() 方法详解1. 方法定义2. 基本用法2.1 拼接

Python+PyQt5实现文件夹结构映射工具

《Python+PyQt5实现文件夹结构映射工具》在日常工作中,我们经常需要对文件夹结构进行复制和备份,本文将带来一款基于PyQt5开发的文件夹结构映射工具,感兴趣的小伙伴可以跟随小编一起学习一下... 目录概述功能亮点展示效果软件使用步骤代码解析1. 主窗口设计(FolderCopyApp)2. 拖拽路径

java变量内存中存储的使用方式

《java变量内存中存储的使用方式》:本文主要介绍java变量内存中存储的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍2、变量的定义3、 变量的类型4、 变量的作用域5、 内存中的存储方式总结1、介绍在 Java 中,变量是用于存储程序中数据

C 语言中enum枚举的定义和使用小结

《C语言中enum枚举的定义和使用小结》在C语言里,enum(枚举)是一种用户自定义的数据类型,它能够让你创建一组具名的整数常量,下面我会从定义、使用、特性等方面详细介绍enum,感兴趣的朋友一起看... 目录1、引言2、基本定义3、定义枚举变量4、自定义枚举常量的值5、枚举与switch语句结合使用6、枚