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

相关文章

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可

IDEA如何将String类型转json格式

《IDEA如何将String类型转json格式》在Java中,字符串字面量中的转义字符会被自动转换,但通过网络获取的字符串可能不会自动转换,为了解决IDEA无法识别JSON字符串的问题,可以在本地对字... 目录问题描述问题原因解决方案总结问题描述最近做项目需要使用Ai生成json,可生成String类型

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

结构体和联合体的区别及说明

《结构体和联合体的区别及说明》文章主要介绍了C语言中的结构体和联合体,结构体是一种自定义的复合数据类型,可以包含多个成员,每个成员可以是不同的数据类型,联合体是一种特殊的数据结构,可以在内存中共享同一... 目录结构体和联合体的区别1. 结构体(Struct)2. 联合体(Union)3. 联合体与结构体的

java如何调用kettle设置变量和参数

《java如何调用kettle设置变量和参数》文章简要介绍了如何在Java中调用Kettle,并重点讨论了变量和参数的区别,以及在Java代码中如何正确设置和使用这些变量,避免覆盖Kettle中已设置... 目录Java调用kettle设置变量和参数java代码中变量会覆盖kettle里面设置的变量总结ja

Perl 特殊变量详解

《Perl特殊变量详解》Perl语言中包含了许多特殊变量,这些变量在Perl程序的执行过程中扮演着重要的角色,:本文主要介绍Perl特殊变量,需要的朋友可以参考下... perl 特殊变量Perl 语言中包含了许多特殊变量,这些变量在 Perl 程序的执行过程中扮演着重要的角色。特殊变量通常用于存储程序的

PostgreSQL如何查询表结构和索引信息

《PostgreSQL如何查询表结构和索引信息》文章介绍了在PostgreSQL中查询表结构和索引信息的几种方法,包括使用`d`元命令、系统数据字典查询以及使用可视化工具DBeaver... 目录前言使用\d元命令查看表字段信息和索引信息通过系统数据字典查询表结构通过系统数据字典查询索引信息查询所有的表名可

变量与命名

引言         在前两个课时中,我们已经了解了 Python 程序的基本结构,学习了如何正确地使用缩进来组织代码,并且知道了注释的重要性。现在我们将进一步深入到 Python 编程的核心——变量与命名。变量是我们存储数据的主要方式,而合理的命名则有助于提高代码的可读性和可维护性。 变量的概念与使用         在 Python 中,变量是一种用来存储数据值的标识符。创建变量很简单,

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s