string是不是就存放不了\0?还是说存放了,但是无法拿出来放到char*中?

看来我真有有些新手了,嗯 好吧。我承认我刚入门不久!

其实想要把string转换到char*的方式有3种:
1.使用c_str(),返回一个const char*
2.使用copy(),返回到char*空间中
3.使用data(),返回char*空间中

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//

#define _SCL_SECURE_NO_WARNINGS

#include "iostream"
#include "string"
using namespace std;


void TestCSTR()
{
string str = "zengraoli";
char *test = new char[str.length() + 1];
strcpy(test, str.c_str());
cout << "test length : " << strlen(test) << endl;
puts(test);

if (test)
{
delete[] test;
test = NULL;
}
}


void TestData()
{
string str = "zengraoli";
char *test = new char[str.length() + 1];
strcpy(test, str.data());
cout << "test length : " << strlen(test) << endl;
puts(test);

if (test)
{
delete[] test;
test = NULL;
}
}


void TestCopy()
{
string str = "zengraoli";int i = str.length();
char *test = new char[str.length() + 2];
size_t copy_length = str.copy(test, str.length(), 0);
test[copy_length] = '\0';
cout << "test length : " << strlen(test) << endl;
puts(test);

if (test)
{
delete[] test;
test = NULL;
}
}


int main()
{
// TestCSTR();

// TestData();

// TestCopy();


return 0;
}


但是主题来了,假如我这个string中间有\0怎么办?比如zeng\0raoli


是不是使用strcpy造成的?换成memcpy了试试:

void TestCSTR()
{
string str = "zeng\0raoli";int i = str.length();
char *test = new char[str.length() + 1];
memset(test, 0, str.length());
memcpy(test, str.c_str(), str.length());
test[str.length()] = '\0';
cout << "test length : " << strlen(test) << endl;
puts(test);

if (test)
{
delete[] test;
test = NULL;
}
}


结果照样是4,会被截断
其实不必测试,也都知道string.leng是根据\0来判断字符串的结束的,所以……

再来修改一下代码,假设已经提前知道了字符串的长度为11:

void TestCSTR()
{
string str = "zeng\0raoli";int i = str.length();
char *test = new char[11];
memset(test, 0, 11);
memcpy(test, str.c_str(), 10);
test[10] = '\0';
cout << "test length : " << strlen(test) << endl;
puts(test);

if (test)
{
delete[] test;
test = NULL;
}
}


还是同样的结果。

那么是不是字符串已经拷贝进去了呢?但是由于puts和strlen因为遇到\0结束,而造成没有输出后面的、没有统计\0后面字符串的长度呢?再来验证一下:

void TestCSTR()
{
string str = "zeng\0raoli";int i = str.length();
char *test = new char[11];
memset(test, 0, 11);
memcpy(test, str.c_str(), 10);
test[10] = '\0';
// cout << "test length : " << strlen(test) << endl;
// puts(test);
for (int index = 0; index < 11; index++)
{
cout << test[index];
}
cout << "\n";

if (test)
{
delete[] test;
test = NULL;
}
}


还是没有成功……
但是我们发现了一个问题,还有一个函数memcpy没修改,是不是他也是通过\0来判断?再来修改验证一下我们的想法:

void TestCSTR()
{
string str = "zeng\0raoli";int i = str.length();
char *test = new char[11];
memset(test, 0, 11);
// memcpy(test, str.c_str(), 10);

for (int index = 0; index < 11; index++)
{
test[index] = *(str.c_str() + index);
}

test[10] = '\0';
// cout << "test length : " << strlen(test) << endl;
// puts(test);
for (int index = 0; index < 11; index++)
{
cout << test[index];
}
cout << "\n";

if (test)
{
delete[] test;
test = NULL;
}
}


也不是,看来只能是出在string身上了。


问题:是不是这个string就不能存放\0的呢?
...全文
426 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
turing-complete 2014-02-23
  • 打赏
  • 举报
回复
说来说去,存放二进制数据,还是std::string更方便。
引用 6 楼 vanxining 的回复:
protobuf之所以用string,我猜是不必要再引入一个vector头文件了。 string有许多成员函数,很多人认为它们与<algorithm>头文件的功能重复了。
  • 打赏
  • 举报
回复
引用 4 楼 mougaidong 的回复:
兄台此言差矣。 我认为在标准C++中,存放二进制数据没有比std::string更合适的数据结构了,理由如下: 1. 较数组灵活,可变长;较动态数组安全,不用自己管理内存。 2. std::vector<char> 这个符号用起来,相比std::string而言,显然有些冗长了。 3. 编译器对std::string这么常用的数据结构做的特殊考虑和设计,肯定是不少的。 比较出色的库 protobuf 和 thrift 都是用std::string来存放二进制数据的。 [quote=引用 1 楼 baichi4141 的回复:] 我还是那句话,请分清“字符串”和“以字节为单位的二进制数据” 虽然都用char*操作,但两者完全不同 std::string不应该用来存放二进制数据,就像strlen不应该用来计算二进制数据长度一样,每次看到初学者写这种代码,我都想问一句“你是不是不知道什么叫字符串”?
[/quote] 还是不明白,如果单纯是二进制0和1为何不用bitset?我看他里面也有to_string

Bitset
A bitset stores bits (elements with only two possible values: 0 or 1, true or false, ...).

The class emulates an array of bool elements, but optimized for space allocation: generally, each element occupies only one bit (which, on most systems, is eight times less than the smallest elemental type: char).

Each bit position can be accessed individually: for example, for a given bitset named foo, the expression foo[3] accesses its fourth bit, just like a regular array accesses its elements. But because no elemental type is a single bit in most C++ environments, the individual elements are accessed as special references type (see bitset::reference).

Bitsets have the feature of being able to be constructed from and converted to both integer values and binary strings (see its constructor and members to_ulong and to_string). They can also be directly inserted and extracted from streams in binary format (see applicable operators).

The size of a bitset is fixed at compile-time (determined by its template parameter). For a class that also optimizes for space allocation and allows for dynamic resizing, see the bool specialization of vector (vector<bool>).
  • 打赏
  • 举报
回复
引用 1 楼 baichi4141 的回复:
我还是那句话,请分清“字符串”和“以字节为单位的二进制数据” 虽然都用char*操作,但两者完全不同 std::string不应该用来存放二进制数据,就像strlen不应该用来计算二进制数据长度一样,每次看到初学者写这种代码,我都想问一句“你是不是不知道什么叫字符串”?
别激动。确实才学不久,正在努力入门当中。 我只是想知道string怎么样存放\0。 结合上面的来看,我要是直接std::string str("zeng\0raoli", 11); 里面也是可以存放\0的

// -------------------------------------------------------------------- //
// --- string class --------------------------------------------------- //
// -------------------------------------------------------------------- //

// dynamic string class with thread-safe ref-counted buffer

struct _strrec 
{
    int refcount;
    int length;
};
可以看到string本来就是有默认的length,如果不给他注明长度,他自己会计算你给他赋值的字符串的长度,其实也是用的strlen:

inline int hstrlen(const char* p) // some Unix systems do not accept NULL
    { return p == nil ? 0 : (int)strlen(p); }
strlen其实也是这样的行为:

size_t __cdecl strlen (
        const char * str
        )
{
        const char *eos = str;

        while( *eos++ ) ;

        return( eos - str - 1 );
}
只要运用得当,string也还是能够存放二进制数据的,重点就是在上面的计算length的长度上面
  • 打赏
  • 举报
回复
引用 7 楼 mougaidong 的回复:
说来说去,存放二进制数据,还是std::string更方便。 [quote=引用 6 楼 vanxining 的回复:] protobuf之所以用string,我猜是不必要再引入一个vector头文件了。 string有许多成员函数,很多人认为它们与<algorithm>头文件的功能重复了。
[/quote] 是,我也这么觉得,我之前看别人封装的curl,也是把文件的二进制存放到了string中,很容易就追加上去了。
vanxining 2014-02-23
  • 打赏
  • 举报
回复
bitset: ** The class emulates an array of bool elements ** 实际上是C++ 11之前的vector<bool>。 一般而言,二进制数据处理的最小单位是字节(byte),而不是比特(bit)。
vanxining 2014-02-22
  • 打赏
  • 举报
回复
protobuf之所以用string,我猜是不必要再引入一个vector头文件了。 string有许多成员函数,很多人认为它们与<algorithm>头文件的功能重复了。
vanxining 2014-02-22
  • 打赏
  • 举报
回复
引用 4 楼 mougaidong 的回复:
兄台此言差矣。 我认为在标准C++中,存放二进制数据没有比std::string更合适的数据结构了,理由如下: 1. 较数组灵活,可变长;较动态数组安全,不用自己管理内存。 2. std::vector<char> 这个符号用起来,相比std::string而言,显然有些冗长了。 3. 编译器对std::string这么常用的数据结构做的特殊考虑和设计,肯定是不少的。 比较出色的库 protobuf 和 thrift 都是用std::string来存放二进制数据的。
其实这三点对std::vector也成立... 第二点:typedef std::vector<char> Bytes;
turing-complete 2014-02-22
  • 打赏
  • 举报
回复
兄台此言差矣。
我认为在标准C++中,存放二进制数据没有比std::string更合适的数据结构了,理由如下:
1. 较数组灵活,可变长;较动态数组安全,不用自己管理内存。
2. std::vector<char> 这个符号用起来,相比std::string而言,显然有些冗长了。
3. 编译器对std::string这么常用的数据结构做的特殊考虑和设计,肯定是不少的。

比较出色的库 protobuf 和 thrift 都是用std::string来存放二进制数据的。


引用 1 楼 baichi4141 的回复:
我还是那句话,请分清“字符串”和“以字节为单位的二进制数据”
虽然都用char*操作,但两者完全不同
std::string不应该用来存放二进制数据,就像strlen不应该用来计算二进制数据长度一样,每次看到初学者写这种代码,我都想问一句“你是不是不知道什么叫字符串”?
vanxining 2014-02-22
  • 打赏
  • 举报
回复
std::string即使可以存放,这种行为也很奇怪。 正确的方法是用std::vector。 string::data()应该会区分const与否的情况。 貌似大家学的都是C++ 11了啊。
turing-complete 2014-02-22
  • 打赏
  • 举报
回复
请楼主将测试代码中的赋值语句
string str = "zeng\0raoli";
都换成
 std::string str("zeng\0raoli", 11);
再试试
baichi4141 2014-02-22
  • 打赏
  • 举报
回复
我还是那句话,请分清“字符串”和“以字节为单位的二进制数据” 虽然都用char*操作,但两者完全不同 std::string不应该用来存放二进制数据,就像strlen不应该用来计算二进制数据长度一样,每次看到初学者写这种代码,我都想问一句“你是不是不知道什么叫字符串”?

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧