将字符数组缓冲区转换为字符串的好方法是什么?

14

我相对比较新学C++。最近的作业要求我将许多char缓冲区(来自结构体/套接字等)转换为字符串。我一直在使用以下变化,但它们似乎很笨拙。有没有更好的方法来做这种事情?

#include <iostream>
#include <string>

using std::string;
using std::cout;
using std::endl;


char* bufferToCString(char *buff, int buffSize, char *str)
{
    memset(str, '\0', buffSize + 1);
    return(strncpy(str, buff, buffSize));
}


string& bufferToString(char* buffer, int bufflen, string& str)
{
    char temp[bufflen];

    memset(temp, '\0', bufflen + 1);
    strncpy(temp, buffer, bufflen);

    return(str.assign(temp));
}



int main(int argc, char *argv[])
{
   char buff[4] = {'a', 'b', 'c', 'd'};

   char str[5];
   string str2;

   cout << bufferToCString(buff, sizeof(buff), str) << endl;

   cout << bufferToString(buff, sizeof(buff), str2) << endl;

}
7个回答

28

如果你的输入字符串不以空字符结尾,就不应该使用str...函数。你也不能使用通常使用的std::string构造函数。但是,你可以使用这个构造函数:

std::string str(buffer, buflen):它接受一个char*和一个长度。(实际上是const char*和长度)

我建议避免使用C字符串版本。这将给出:

std::string bufferToString(char* buffer, int bufflen)
{
    std::string ret(buffer, bufflen);

    return ret;
}

如果您真的必须使用C字符串版本,可以在bufflen位置放置一个0(如果可以),或者创建一个bufflen+1大小的缓冲区,然后将缓冲区memcpy到它里面,并在末尾(bufflen位置)添加一个0


4
针对Newton Falls:请注意,std::string(Ch* p, size_type n)在缓冲区中存在空字符时不会停止,所有的n个字符都将被复制到字符串中。 - outis
如果可能的话,我完全同意避免使用C字符串版本。现在处理原始C字符串只会让你陷入麻烦。您的bufferToCString中有几个错误,包括使用bufsize + 1覆盖未知内存,并假定输出缓冲区'str'是输入缓冲区的bufsize + 1。这些错误将以微妙的方式暴露出来,并给您带来大量的调试痛苦。如果可以,请使用std :: string。 - Nick Haddad
Outis说得很好。我刚刚测试了一下,在数组中间放了一个null,它打印出了字符串长度之前的所有内容。我本来以为它会在null处停止。感谢你的洞察力。 - Newton Falls
谢谢Nick。我也注意到了。这是我的第一篇帖子,我不确定是否应该粘贴代码,所以我手动输入并犯了错误。但你的观点很正确,我尽可能地试图远离C级别。 - Newton Falls
那个名字从哪里来的,我不确定你的意思。返回指向堆栈变量的指针/引用是不好的,因为底层数据会消失,但返回堆栈变量是可以的,因为它将被复制。对于POD类型,返回堆栈变量几乎是普遍的。 - Simon Parker
显示剩余3条评论

5
如果数据缓存中可能含有 null ('\0') 字符,那么就不要使用以 null 结尾的操作。
你可以使用接受 char* 和 length 参数的构造函数。
char buff[4] = {'a', 'b', 'c', 'd'};
cout << std::string(&buff[0], 4);

或者,您可以使用接受范围的构造函数:

cout << std::string(&buff[0], &buff[4]); // end is last plus one

不要使用std::string(buff)构造函数与上面的buff []数组一起使用,因为它没有以null结尾。

1
谢谢David。这是一个不错的选择,可以替代Simon的答案。 - Newton Falls

1

将std::string转换为const char*:

  my_str.c_str();

char* to std::string:

  string my_str1 ("test");
  char test[] = "test";
  string my_str2 (test);

或者甚至更好

  string my_str3 = "test";

问题在于缓冲区没有终止空字符。 - Newton Falls
当你使用常量字符串初始化一个char数组时,它会得到一个终止null字符。当你使用string::c_str()时,也会得到一个终止null字符。我不理解你的抱怨是什么。 - Mark Ransom
答案中的代码是正确的,但与问题不同。"char buff[4] = {'a','b','c','d'};"不能给您一个以空字符结尾的字符串。 - markh44
如果它不以零结尾,那么它就不是真正的字符串。您确定在这种情况下使用std::string来表示数据是最好的方法吗? - Dan Olson

1

该方法需要知道字符串的大小。您必须:

  1. 对于char *的情况,将长度传递给该方法
  2. 对于指向以null结尾的字符数组的char *,您可以使用直到null字符为止的所有内容
  3. 对于char [],您可以使用模板来确定char []的大小

1)示例 - 用于传递bufflen的情况:

std::string bufferToString(char* buffer, int bufflen)
{
    return std::string(buffer, bufflen);
}

2) 例如 - 当缓冲区指向以空字符结尾的字符数组时:

std::string bufferToString(char* buffer)
{
    return std::string(buffer);
}

3)示例 - 用于传递char[]的情况:

template <typename T, size_t N>
std::string tostr(T (&array)[N])
{
    return std::string(array, N);
}


Usage:
char tstr[] = "Test String";
std::string res = tostr(tstr);
std::cout << res << std::endl;

对于前两种情况,您实际上不必创建新方法:

 std::string(buffer, bufflen);
 std::string(buffer);

0
std::string buf2str(const char* buffer)
{
    return std::string(buffer);
}

或者只是

std::string mystring(buffer);

我正在寻找一种更简洁的方法来添加一个终止空字符,以便像这样的东西可以正确地工作。 - Newton Falls

0
使用接受大小参数的字符串构造函数:
string ( const char * s, size_t n );

Content is initialized to a copy of the string formed by the first n characters in the array of characters pointed by s.

cout << std::string(buff, sizeof(buff)) << endl;

http://www.cplusplus.com/reference/string/string/string/

非空结尾的缓冲区转换为C字符串:

memcpy(str, buff, buffSize);
str[bufSize] = 0; // not buffSize+1, because C indexes are 0-based.

-1

string value(reinterpret_cast(buffer),length);


请解释你的答案。 - JayIsTooCommon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接