《白话C++》第10章 Page50 10.3 字符串处理 转换为C风格字符串 复制子串(可能有问题)

11.转换为C风格字符串

有三个函数可以将std::string的内容,转换为C风格的字符串或字符数组。

(1)c_str()

 const char* c_str() const;

在数据后面故意添加上 '\0' 结束符(但不影响std::string维护的字符串数),然后返回数据的指针。

如果所包含的字符中,原来已经夹有 '\0' , 则调用者将只得到被截断的字符串:

std::string s1("abc\0efg", 7);

cout << "s1.length = " << s1.length() << endl; //7
cout << "s1.c_str is " << s1.c_str() << endl; //abc

c_str()返回的是const char*,所以调用者不能通过它修改std::string的字符内容。

(2)data()

在C++11中,data()和c_str()干一模一样的活,同样返回补上 '\0'  的C风格的

常量字符(const char  *);在C++ 11之前,data()不会自动添加 '\0',因此处理起来一定要小心。

【危险】:std::string的c_str()与data()返回值的有效期

c_str()或data()都返回一个const char * 的指针,这个指向的内存并不是一直有效,比如:

std::string s = "I am a programmer.";
char const * pstr = s.c_str();
s.clear(); //清除掉
cout << pstr << endl; //危险

一般这么认为:s.clear()只是将内存清掉,那之前的pstr就变成指向一个空字符串,最后一行代码大不了屏幕什么也没有输出而已。但事实上pstr所指向的内容有可能是空,也有可能是远洋,也有可能已经错乱了。

无论是c_str()还是data(),在原string对象调用了非常量的成员操作之后,就失效了。

实际项目中,推荐更严格而易于排查的规定:只在同一个语句中使用

//比如需要给C函数atoi传递一个C风格的字符串,请写成
int a = atoi(s.c_str());

//而不要写成:
char const* pstr = s.c_str();
...
int a = atoi(pstr);

因为,现在“...”的位置,可能是空行,但以后说不定就有哪位不听话的家伙,在那里插入一堆代码(不知不觉地毁掉pstr指针)。

12. 复制子串

c_str()data()没有复制内存的行为存在,所以高效是必然的,

缺点:

一,是前面提到的危险

二,是它返回的const char *,所以不允许修改内容,这就有了std::string的copy成员函数:

size_t copy(char* s, size_t n, size_t pos = 0) const;

或许copy应该取名为copy_to,其功能体现能更直观点,它就是将内容(不添加 '\0'),复制到入参的char * s中n则指定最多要复制多少个字符pos则表示从当前串哪个位置开始复制返回值是实际复制了几个字符(因为源串的长度可能小于n)。

std::string s("0123456");
char buf[10];
size_t count = s.copy(buf, string::npos, 1);
//别忘了手工添加结束符,因为下一行要输出
buf[count] = '\0'; 

cout << buf << endl;

可能有问题 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值