string::c_str()、string::c_data()及string与char *的正确转换

原文链接:http://www.cnblogs.com/ziwuge/archive/2011/08/30/2159878.html

string::c_str的介绍:

      c_str函数的返回值是const char*的,不能直接赋值给char*,所以就需要我们进行相应的操作转化,下面就是这一转化过程。
      c++语言提供了两种字符串实现,其中较原始的一种只是字符串的c语言实现。与C语言的其他部分一样,它在c++的所有实现中可用,我们将这种实现提供的字符串对象,归为c-串,每个c-串char*类型的。
  标准头文件<cstring>包含操作c-串的函数库。这些库函数表达了我们希望使用的几乎每种字符串操作。 当调用库函数,客户程序提供的是string类型参数,而库函数内部实现用的是c-串,因此需要将string对象,转化为char*对象,而c_str()提供了这样一种方法,它返回一个客户程序可读不可改的指向字符数组的指针。 例:

 1   #include <iostream>
2   #include <string>
3   usingnamespace std;
4   void main()
5   string add_to="hello!";
6   //std::cout<<add_to<<endl;
7   conststring add_on="baby";
8   constchar*cfirst = add_to.c_str();
9   constchar*csecond = add_on.c_str();
10   char*copy =newchar[strlen(cfirst) + strlen(csecond) +1];
11   strcpy( copy, cfirst);
12   std::cout<<copy<<endl;
13   //strcat( copy, csecond);
14   add_to = copy;
15   delete [] copy;
16   std::cout<<add_to<<std::endl;

  简单的例子:
  const char *c_str();

  c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同.
  这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。
  注意:一定要使用strcpy()函数 等来操作方法c_str()返回的指针
  比如:最好不要这样:  

1   char* c;
2   string s="1234";
3   c = s.c_str(); 
   
//c最后指向的内容是垃圾,因为s对象被析构,其内容被处理(纠正:s对象的析构是在对指针c完成赋值操作之后进行的,故此处并没有错误)

  应该这样用:

1   char c[20];
2   string s="1234";
3   strcpy(c,s.c_str());

  这样才不会出错,c_str()返回的是一个临时指针,不能对其进行操作
  再举个例子
  c_str() 以 char* 形式传回 string 内含字符串
  如果一个函数要求char*参数,可以使用c_str()方法:

1   string s ="Hello World!";
2   printf("%s", s.c_str()); //输出 "Hello World!"

  c_str在打开文件时的用处:
  当需要打开一个由用户自己输入文件名的文件时,可以这样写:ifstream in(st.c_str());。其中st是string类型,存放的即为用户输入的文件名。

 

string::c_str()、string::c_data()的区别:

 

const value_type *c_str( ) const;

const value_type *data( ) const;

 
data只是返回原始数据序列,没有保证会用traits::eos(),或者说'\0'来作字符串结束.   当然,可能多数实现都这样做了。   

c_str是标准的做法,返回的char*   一定指向一个合法的用'\0'终止的C兼容的字符串。   
所以,如果需要C兼容的字符串,c_str是标准的做法,data并不保证所有STL的实现的一致性。

 

你或许会问,c_str()的功能包含data(),那还需要data()函数干什么?看看源码:
const charT* c_str () const
{

   if  (length () == 0)

        return "";

   terminate ();

   return data ();

}
原来c_str()的流程是:先调用terminate(),然后在返回data()。因此如果你对效率要求比较高,而且你的处理又不一定需要以\0的方式结束,你最好选择data()。但是对于一般的C函数中,需要以const char*为输入参数,你就要使用c_str()函数。
对于c_str() data()函数,返回的数组都是由string本身拥有,千万不可修改其内容。其原因是许多string实现的时候采用了引用机制,也就是说,有可能几个string使用同一个字符存储空间。而且你不能使用sizeof(string)来查看其大小。详细的解释和实现查看Effective STL的条款15:小心string实现的多样性。
另外在你的程序中,只在需要时才使用c_str()或者data()得到字符串,每调用一次,下次再使用就会失效,如:
string strinfo("this is Winter");
...
//最好的方式是:
foo(strinfo.c_str());
//也可以这么用:
const char* pstr=strinfo.c_str();
foo(pstr);
//不要再使用了pstr了, 下面的操作已经使pstr无效了。
strinfo += " Hello!";
foo(pstr);//错误!
会遇到什么错误?当你幸运的时候pstr可能只是指向"this is Winter Hello!"的字符串,如果不幸运,就会导致程序出现其他问题,总会有一些不可遇见的错误。总之不会是你预期的那个结果。


补充:string是C++类,所以尽量用C++的函数操作string类。对应的是标准C和char *.


【参考资料 感谢作者】
http://baike.baidu.com/view/1600698.htm
http://www.cnblogs.com/lancidie/archive/2011/03/17/1987130.html 

转载于:https://www.cnblogs.com/ziwuge/archive/2011/08/30/2159878.html

展开阅读全文
博主设置当前文章不允许评论。

c++ stringc_str() 疑惑

08-18

环境:rnCentOS release 6.5 (Final)rnLinux bogon 2.6.32-431.el6.x86_64rngcc 版本 4.7.4 (GCC)rnrnrn问题描述:rn如果用一个const char *p 指向string ss.c_str()的返回地址,rn改变了ss的值之后, *p的值也会相应改变,rnbut, 9test.cpp的情况下就没改变,求解惑。rnrnrn备注:rn虽然实际上这么干的情况很少,需要用到c_str()的时候都是直接strcpy走了之后再使用,rn但这种情况实在不解。rnrnrn代码1:rnrn9test.cpp:rnrn#include rn#include rnusing namespace std;rnrnint main()rnrn string ss("abcdefghigklmnopq");rnrn const char *tmp = ss.c_str();rn cout << "ss.c_str() 1 = " << tmp << endl;rn cout << "ss.c_str() 1 , addr = " << static_cast (const_cast (tmp)) << endl;rnrn ss = "bacdbefghigkgilfgimnopq";rnrn cout << "ss.c_str() 2 = " << tmp << endl;rn cout << "ss.c_str() 2 , addr = " << static_cast (const_cast (tmp)) << endl;rnrn return 0;rnrnrnrn代码2:rnrn10test.cpprnrn#include rn#include rnusing namespace std;rnrnint main()rnrn string ss("abcdefghigklmnopq");rnrn const char *tmp = ss.c_str();rn cout << "ss.c_str() 1 = " << tmp << endl;rn cout << "ss.c_str() 1 , addr = " << static_cast (const_cast (tmp)) << endl;rnrn ss = "1234";rnrn cout << "ss.c_str() 2 = " << tmp << endl;rn cout << "ss.c_str() 2 , addr = " << static_cast (const_cast (tmp)) << endl;rnrn return 0;rnrnrnrn输出结果1:rnrn[bnms@bogon test]$ g++ 9test.cpprn[bnms@bogon test]$ ./a.outrnss.c_str() 1 = abcdefghigklmnopqrnss.c_str() 1 , addr = 0x1b89028rnss.c_str() 2 = abcdefghigklmnopqrnss.c_str() 2 , addr = 0x1b89028rnrnrn输出结果2:rn[bnms@bogon test]$ g++ 10test.cpp rn[bnms@bogon test]$ ./a.outrnss.c_str() 1 = abcdefghigklmnopqrnss.c_str() 1 , addr = 0x2252028rnss.c_str() 2 = 1234rnss.c_str() 2 , addr = 0x2252028rnrnrn 论坛

stringc_str导致的问题

10-03

string的c_str()会返回一个C兼容的字符串,也就是所谓的其内容以null终止的字符指针,这儿的关键问题是这个指针的生命周期如何?更精致的也就是说:它什么时候销毁?它只想的内容什么时候失效?我想来想去,觉得这儿很难处理,似乎除了引入一个微型的GC以外,没有什么别的可能。rnrn由于有好多人只希望看代码,我就举点代码作为例子:rnrnstring content = "Hello, world!";rnrnmbstowcs(wideContentBufferPointer, wideContentBufferLength, content.c_str(), content.length());rnrn上面的content.c_str()会返回一个char*,也就是一个字符指针,指向一个内存区域,那个内存区域的长度为content.length() + 1,内容content这个字符串的内容后跟一个null。首先,主要的问题是:这个内存区域是不是就是content这个字符串类中包含的那个内容所占据的区域呢?我们可以理智的推断,不是。因为,一、那个区域比这个区域的大小小一。二、content类中内容未必在一个内存区域中。那么,这个内存区域就是c_str分配的了。可是,它在什么时候释放呢?不知道。没有办法知道这个char*会在什么时候释放。真是可怕啊。它不会被释放?这是一个内存泄漏吗?不……,好多人都会疯狂的,应该或许大概编译器会在适当的地方插入释放内存的指令吧。可是这是不可能的,这儿只有在运行时才能知道是不是可以释放了。这儿有GC吗?,应该没有。可是究竟怎么才能完成这个魔幻般的动作呢?有人会猜测,会不会实在string类的析构中释放?我觉得这仍然不可取,看看下面的代码:rnrnchar cons* f()rnrn string r;rn //....rn return r.c_str();rnrnrn这段代码会不会出现问题?应该不会吧。rnrn如果会出现问题,那么,我们再看看这样:rnrn//...rnstring* s = new string();rn//...rnchar* data = 0;rnif (condition)rn data = s->c_str();rnelsern data = (char*)malloc(length + 1)rn//...a lot of code use datarnif (condition)rn ; //do nothingrnelsernrn free(data);rn data = 0;rnrn这儿会有双份的内存泄漏吗?rnrn有人说了,c_str不会分配内存的,你上面的那些分析都不对了。可是问题是:如果c_str()不分配内存,它怎么能给内容最后缀上0?或许它内部就有结尾0?可是如果是这样,我们的string显然不能不是连续的,可是,标准上明确地写着它可以是不连续的。rnrn我没有想到什么?谁给我解答一下。 论坛

没有更多推荐了,返回首页