首页 > C++ 和C 语言混合代码导致的问题

C++ 和C 语言混合代码导致的问题

C语言中操作字符串用C运行时函数:strtok, strcmp, strcpy等等,直接操作内存。在c++引入的字符串操作类std:string ,string类中必有一个私有成员,其是一个char*,用户记录从堆上分配内存的地址,其在构造时分配内存,在析构时释放内存。因为是从堆上分配内存,所以string类在维护这块内存上是格外小心的,string类在返回这块内存地址时,只返回const char*,也就是只读的,如果你要写,你只能通过string提供的方法进行数据的改写

看如下代码:

  1 #include

  2 #include

  3 #include

  4

  5 using namespace std;

  6

  7 int main(int argc, char*argv[])

  8 {

  9     string g_str = "Wj Cy Beijing";

 10     string tmp = g_str;

 11

 12     char *p_str = (char *)tmp.c_str();

 13     char *saveptr = NULL;

 14     int id = 0;

 15     bool bCheck = true;

 16

 17     cout << "g_str: " <

 18     cout << "tmp:   " << tmp << endl;

 19     cout << "****************"<< endl;

 20

 21     char *p = strtok_r(p_str, " ",&saveptr);

 22     cout << "g_str: " <

 23     cout << "tmp:   " << tmp << endl;

 24     cout << "****************"<< endl;

 25

 26     strtok_r(NULL, " ",&saveptr);

 27     cout << "g_str: " <

 28     cout << "tmp:   " << tmp << endl;

 29

 30     return 1;

 31 }

这段代码中是string和strtok_r混合代码,我们期望的运行结果是:

g_str: Wj Cy Beijing

tmp:   Wj Cy Beijing

****************

g_str: Wj Cy Beijing

tmp:   WjCy Beijing

****************

g_str: Wj Cy Beijing

tmp:   WjCyBeijing

即:g_str的结果保持不变,始终是”Wj Cy Beijing

 

但实际运行结果却是:

g_str: Wj Cy Beijing

tmp:   Wj Cy Beijing

****************

g_str: WjCy Beijing

tmp:   WjCy Beijing

****************

g_str: WjCyBeijing

tmp:   WjCyBeijing

结果中g_str的结果发生了变化,且同tmp的值保持一样,就像是tmp和g_str string 中的char *指的是同一个地址。用gdb 进行调试,发现:

(gdb) p g_str.c_str()

$1 = 0x603028 "Wj Cy Beijing"

(gdb) p tmp.c_str()

$2 = 0x603028 "Wj Cy Beijing"

两者确实指向同一个地址0x603028。

 

查询资料发现,string类有copy-on-write特性,即:用时才分配内存,看如下代码:

main()

{

       string str1 ="hello world";

       string str2 = str1;

    

       printf ("Sharingthe memory:/n");

       printf ("/tstr1's address:%x/n", str1.c_str() );

       printf ("/tstr2'saddress: %x/n", str2.c_str() );

     

       str1[1]='q';

       str2[1]='w';

 

       printf ("AfterCopy-On-Write:/n");

       printf ("/tstr1'saddress: %x/n", str1.c_str() );

       printf ("/tstr2'saddress: %x/n", str2.c_str() );

 

       return 0;

}

运行结果如下:

Sharing the memory:

        str1's address:343be9

        str2's address:343be9

After Copy-On-Write:

        str1's address:3407a9

        str2's address:343be9

可见在str2第一次被赋值时,并没有为其char*分配内存,而是和str1共享内存(0x343be9), 直到给其赋值时,才分配内存0x343be9.

 

现在回过头来看一下我们开始时所写的代码片段:

  9     string g_str = "Wj Cy Beijing";

 10     string tmp = g_str;       //此时tmp g_str 存放字符串的内存char *为同一块

 11

 12     char *p_str = (char *)tmp.c_str();  //p_str其实指向的就是g_str存放字符串的内存块

 13     char *saveptr = NULL;

 14     int id = 0;

 15     bool bCheck = true;

 

原因找到了,这也就不能理解string接口函数c_str()返回类型是const char* 了,返回const就是不想让人修改string中类型的值。想修改的话,最好通过string提供的接口函数进行修改。当然,如果你非要通过c函数修改的话,可以这样来声明tmp:

string g_str = "Wj Cy Beijing";

string tmp(“”);

tmp.append(g_str);

 

最好不要写c++和c混合的代码,因为你不可能都知道c++封装的类内部做了些什么。

 

 

更多相关:

  • 工作中多次遇到Python版本的签名算法,需要用Go版本再实现一遍,这就需要牵扯到Python 2.7中的urllib中的quote,quote_plus和Go中net/url包中的url.QueryEscape的关系。 下面直接给出它们的关系: urllib.quote_plus(str)等同于url.QueryEscape(s...

  • 思路 大体思路:数据结构选用栈,读到左括号时入栈,读到右括号时判断是否匹配,匹配则左括号出栈,非括号字符则继续往下读 代码 #include #include #include using namespace std;bool is_match_parentheses(co...

  • 方法1: Controller

  • str = Regex.Replace(str, @"]*?>.*?", "", RegexOptions.IgnoreCase); //str为需要校验的字符 str = Regex.Replace(str, @"[~`@#$%^&*()_+{}|<>/\[]]", "", Re...

  • importjava.security.SecureRandom;importjavax.crypto.Cipher;importjavax.crypto.SecretKey;importjavax.crypto.SecretKeyFactory;importjavax.crypto.spec.DESKeySpec;//结果与DES算...

  • 题目:替换空格 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。 输入:s = "We are happy." 输出:"We%20are%20happy." 限制: 0 <= s 的长度 <= 10000 解题: 时间复杂度:O(n) 空间复杂度:O(n) class Solution { public:s...

  • 在C++11标准库中,string.h已经添加了to_string方法,方便从其他类型(如整形)快速转换成字面值。 例如: for (size_t i = 0; i < texArrSize; i++)RTX_Shader.SetInt(string("TexArr[") + to_string(i) + "]", 7 + i);...

  • Ubuntu 14.04安装并升级之后,变成楷体字体非常难看,我昨天搞了一晚上,终于理了个头绪,这里整理一下。 经过网上调研,大家的一致看法是,使用开源字体库文泉驿的微黑字体效果比较理想,甚至效果不输windows平台的雅黑字体。下面我打算微黑来美化Ubuntu 14.04. 1.安装文泉驿微黑字体库 sudo aptitude...

  • 使用string时发现了一些坑。 我们知道stl 容器并不是线程安全的,所以在使用它们的过程中往往需要一些同步机制来保证并发场景下的同步更新。 应该踩的坑还是一个不拉的踩了进去,所以还是记录一下吧。 string作为一个容器,随着我们的append 或者 针对string的+ 操作都会让string内部的数据域动态增加,而动态增加的...

  • 使用内部存储结构为栈的方法实现一个队列,要求实现该队列的如下方法: 1.push(x) : 将元素x压入队列中 2.pop() : 弹出(移除)队列头部元素 3.peek() : 返回队列头部元素(即为front) 4.empty() : 判断队列是否是空 栈的数据结构为先入后出,队列的数据结构为先入先出 使用栈来实现队列,同样想要...