第十九课、QString、string、char *、char[] 之间的转换方法

问题描述:详细介绍 QString、string、char *、char[] 之间的转换方法

目录

[一、 QString 与 string 之间的转换](#一、 QString 与 string 之间的转换)

[QString 转换为 string](#QString 转换为 string)

[string 转换为 QString](#string 转换为 QString)

[二、QString 与 char * 之间的转换](#二、QString 与 char * 之间的转换)

[QString 转换为 char *](#QString 转换为 char *)

[QString 转换为 const char *](#QString 转换为 const char *)

[char * 转换为 QString](#char * 转换为 QString)

[三、QString 与 char[] 之间的转换](#三、QString 与 char[] 之间的转换)

[QString 转换为 char[]](#QString 转换为 char[])

[char[] 转换为 QString](#char[] 转换为 QString)

[四、 string 与 char * 之间的转换](#四、 string 与 char * 之间的转换)

[string 转换为 char *](#string 转换为 char *)

[char * 转换为 string](#char * 转换为 string)

[五、 string 与 char[] 之间的转换](#五、 string 与 char[] 之间的转换)

[string 转换为 char[]](#string 转换为 char[])

[char[] 转换为 string](#char[] 转换为 string)

[六、 char * 与 char[] 之间的转换](#六、 char * 与 char[] 之间的转换)

[char * 转换为 char[]](#char * 转换为 char[])

[char[] 转换为 char *](#char[] 转换为 char *)


一、 QString 与 string 之间的转换

QString 转换为 string

  • toStdString()

此转换方法对中英文均适用

cpp 复制代码
QString qstr = "您好world";
string str;

// 从 QString 到 std::string
str = qstr.toStdString();

qDebug() << str.data();        // 输出:您好world
  • memcpy(char* dst, char* src, unsigned int maxCount);

采用内存拷贝的方法也可以实现 QString 到 string 的转换,dst 为 string 的地址,src 为 QString 字符串的地址,maxCount 为 QString 字符串的字节大小

dst 为 string 的地址,可以调用 string 的 .data() 或者 .c_str() 方法

src 为 QString 字符串的地址,可以调用 QString 的 .toLocal8Bit().data() 或者 .toUtf8().data() 或者 .toLatin1().data() 方法

maxCount 为 QString 字符串的字节大小,可以调用 QString 的 .toLocal8Bit().size()(或者 .count() 或者 .length())或者 .toUtf8().size()(或者 .count() 或者 .length())或者 .toLatin1().size()(或者 .count() 或者 .length())方法

由此产生多种组合方式:

  • memcpy((char*)str.data(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().size());
  • memcpy((char*)str.data(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().count());
  • memcpy((char*)str.data(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().length());
  • memcpy((char*)str.c_str(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().size());
  • memcpy((char*)str.c_str(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().count());
  • memcpy((char*)str.c_str(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().length());

只要源文件的编码与程序内部使用的字符编码保持一致,那么采用 toLocal8Bit() 方法的 memcpy() 转换方法对中英文均适用(中文编码问题请参考《第十课:Qt 字符编码和中文乱码相关问题》)

cpp 复制代码
QString qstr = "您好world";
string str;
str.resize(qstr.toLocal8Bit().size());    // 或者 .count() 或者 .length()

// 从 QString 到 std::string
memcpy((char*)str.data(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().size());
//    memcpy((char*)str.data(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().count());
//    memcpy((char*)str.data(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().length());
//    memcpy((char*)str.c_str(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().size());
//    memcpy((char*)str.c_str(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().count());
//    memcpy((char*)str.c_str(), qstr.toLocal8Bit().data(), qstr.toLocal8Bit().length());

qDebug() << str.data();    // 输出:您好world

注意:在 memcpy 给 string 变量之前,一定要设置 string 的字节大小,否则只是浅拷贝(即string 指针指向字符串地址,string 并未开辟内存,string 字符串为空),只有设置了 string 的字节大小,才能实现字符串的深拷贝

  • memcpy((char*)str.data(), qstr.toUtf8().data(), qstr.toUtf8().size());
  • memcpy((char*)str.data(), qstr.toUtf8().data(), qstr.toUtf8().count());
  • memcpy((char*)str.data(), qstr.toUtf8().data(), qstr.toUtf8().length());
  • memcpy((char*)str.c_str(), qstr.toUtf8().data(), qstr.toUtf8().size());
  • memcpy((char*)str.c_str(), qstr.toUtf8().data(), qstr.toUtf8().count());
  • memcpy((char*)str.c_str(), qstr.toUtf8().data(), qstr.toUtf8().length());

采用 toUtf8() 方法的 memcpy() 转换方法对中英文均适用

cpp 复制代码
QString qstr = "您好world";
string str;
str.resize(qstr.toUtf8().size());    // 或者 .count() 或者 .length()

// 从 QString 到 std::string
memcpy((char*)str.data(), qstr.toUtf8().data(), qstr.toUtf8().size());
//    memcpy((char*)str.data(), qstr.toUtf8().data(), qstr.toUtf8().count());
//    memcpy((char*)str.data(), qstr.toUtf8().data(), qstr.toUtf8().length());
//    memcpy((char*)str.c_str(), qstr.toUtf8().data(), qstr.toUtf8().size());
//    memcpy((char*)str.c_str(), qstr.toUtf8().data(), qstr.toUtf8().count());
//    memcpy((char*)str.c_str(), qstr.toUtf8().data(), qstr.toUtf8().length());

qDebug() << str.data();    // 输出:您好world

注意:在 memcpy 给 string 变量之前,一定要设置 string 的字节大小,否则只是浅拷贝(即string 指针指向字符串地址,string 并未开辟内存,string 字符串为空),只有设置了 string 的字节大小,才能实现字符串的深拷贝

  • memcpy((char*)str.data(), qstr.toLatin1().data(), qstr.toLatin1().size());
  • memcpy((char*)str.data(), qstr.toLatin1().data(), qstr.toLatin1().count());
  • memcpy((char*)str.data(), qstr.toLatin1().data(), qstr.toLatin1().length());
  • memcpy((char*)str.c_str(), qstr.toLatin1().data(), qstr.toLatin1().size());
  • memcpy((char*)str.c_str(), qstr.toLatin1().data(), qstr.toLatin1().count());
  • memcpy((char*)str.c_str(), qstr.toLatin1().data(), qstr.toLatin1().length());

由于 Latin1 代表 ASCII,无法表示中文。因此,采用 toLatin1() 方法的 memcpy() 转换方法对英文适用,对中文则会出现乱码(中文字符以 '?' 显示)

cpp 复制代码
QString qstr1 = "您好";
QString qstr2 = "world";
string str1, str2;
str1.resize(qstr1.toLatin1().size());    // 或者 .count() 或者 .length()
str2.resize(qstr2.toLatin1().size());    // 或者 .count() 或者 .length()

// 从 QString 到 std::string
memcpy((char*)str1.data(), qstr1.toLatin1().data(), qstr1.toLatin1().size());
memcpy((char*)str2.data(), qstr2.toLatin1().data(), qstr2.toLatin1().size());
qDebug() << str1.data()  << str2.data();            // 输出:?? hello

//    memcpy((char*)str1.data(), qstr1.toLatin1().data(), qstr1.toLatin1().count());
//    memcpy((char*)str2.data(), qstr2.toLatin1().data(), qstr2.toLatin1().count());
//    qDebug() << str1.data()  << str2.data();            // 输出:?? hello

//    memcpy((char*)str1.data(), qstr1.toLatin1().data(), qstr1.toLatin1().length());
//    memcpy((char*)str2.data(), qstr2.toLatin1().data(), qstr2.toLatin1().length());
//    qDebug() << str1.data()  << str2.data();            // 输出:?? hello

//    memcpy((char*)str1.c_str(), qstr1.toLatin1().data(), qstr1.toLatin1().size());
//    memcpy((char*)str2.c_str(), qstr2.toLatin1().data(), qstr2.toLatin1().size());
//    qDebug() << str1.data()  << str2.data();            // 输出:?? hello

//    memcpy((char*)str1.c_str(), qstr1.toLatin1().data(), qstr1.toLatin1().count());
//    memcpy((char*)str2.c_str(), qstr2.toLatin1().data(), qstr2.toLatin1().count());
//    qDebug() << str1.data()  << str2.data();            // 输出:?? hello

//    memcpy((char*)str1.c_str(), qstr1.toLatin1().data(), qstr1.toLatin1().length());
//    memcpy((char*)str2.c_str(), qstr2.toLatin1().data(), qstr2.toLatin1().length());
//    qDebug() << str1.data()  << str2.data();            // 输出:?? hello

注意:在 memcpy 给 string 变量之前,一定要设置 string 的字节大小,否则只是浅拷贝(即string 指针指向字符串地址,string 并未开辟内存,string 字符串为空),只有设置了 string 的字节大小,才能实现字符串的深拷贝

string 转换为 QString

  • QString::fromStdString()

此转换方法对中英文均适用

cpp 复制代码
string str = "您好world";

// 从 std::string 到 QString
QString qstr = QString::fromStdString(str);

qDebug() << qstr;        // 输出:您好world
  • QString(const char *str)

采用 QString(const char *str) 的构造函数,传给它一个 char * 指针,由于 string 可通过 .data() 或者 .c_str() 获取其指针,因此有两种方法:

  • QString(str.data()) // 等价于 str.data()
  • QString(str.c_str()) // 等价于 str.c_str()

按照 C++ 的规则,直接将 char * 赋值给 QString,它会自动寻找 QString 最为相近的构造函数,即 QString(const char * str)。因此,QString 构造函数可以省略,直接将 char * 直接赋值给 QString

cpp 复制代码
string str = "您好world";

// 从 std::string 转换为 QString
QString qstr1 = str.data();       // 等价于 QString(str.data());
QString qstr2 = str.c_str();      // 等价于 QString(str.c_str());

qDebug() << qstr1;        // 输出:您好world
qDebug() << qstr2;        // 输出:您好world

此转换方法对中英文均适用,中文编码问题请参考 《第十课:Qt 字符编码和中文乱码相关问题

下面来讨论下能不能用 memcpy() 函数将 std::string 转换为 QString???

首先看下 memcpy 函数原型:memcpy(char* dst, char* src, unsigned int maxCount);

此处的 dst 应为 QString 的地址指针,我们发现 QString 的 .toLocal8Bit() 或者 .toUtf8() 或者 .toLatin1() 均为 QString 字符串的深拷贝,即字符串内容相同,在存储空间中的位置不同。因此,其对应的 .toLocal8Bit().data() 或者 .toUtf8().data() 或者 .toLatin1().data() 均指向拷贝字符串的存储地址,并不是指向 QString 字符串本身的存储地址。通过查阅资料发现,QString 的 .data() 函数返回 QString 存储数据的指针,即 QString 字符串的存储地址

现在我们深度分析下 QString 的赋值函数和 std::string 的赋值函数:

QString qstr = "您好"; // 2 个长度,占 4 个字节

QString qstr = "hello"; // 5 个长度,占 10 个字节

Qt 的文档中明确指出,QString 内部使用的是 Unicode 编码,具体实现方案是 utf16,一个长度占两个字节。在使用char * 构造 QString 实例的时候,QString 默认将 char * 当作是 utf8 编码去构造,即:QString s(char *) 等价于 QString s = QString::fromUtf8(char*)

cpp 复制代码
QString qstr = "您好world";
qDebug() << qstr.size();             // 7
qDebug() << qstr.length();           // 7
qDebug() << qstr.count();            // 7
qDebug() << sizeof(qstr);            // 4
qDebug() << sizeof(QString);         // 4

可以看出,QString 的 .size()、.length()、.count() 都是返回 QString 字符串的长度,7 个单位长度,存储共计 14 个字节

sizeof(qstr) 和 sizeof(QString) 是 QString 对象所占用的空间,而不是 QString 所存储的字符串的大小。不管 QString 字符串的内容如何变化,它的 sizeof() 都是固定的,字符串所占的空间是从堆中动态分配的,与 sizeof() 无关。QString 的实现在不同的编译器中可能有所不同,最典型的 sizeof(QString) = 4,不过也有 12、16、24、32等值。本机在 MinGW 5.3.0 编译器下测试得 sizeof(QString) = 4

string str = "世界"; // GBK 编码:4字节,utf-8编码:6字节

string str = "world"; // GBK 编码:5字节,utf-8编码:5字节

GBK 编码方式下,英文占 1 个字节,中文占 2 个字节;UTF-8 编码方式下,英文占 1 个字节,中文占 3 个字节

cpp 复制代码
string str = "您好world";
qDebug() << str.size();             // GBK:9, UTF-8:11
qDebug() << str.length();           // GBK:9, UTF-8:11
qDebug() << sizeof(str);            // 24
qDebug() << sizeof(string);         // 24

可以看出,string 的 .size()、.length() 都是返回 string 字符串的字节数,由于 GBK 编码和 UTF-8 编码的中文所占字节数不同,因此,GBK 编码方式下为 9 字节,UTF-8 编码方式下为 11 字节

sizeof(str) 和 sizeof(string) 是 string 对象所占用的空间,而不是 string 所存储的字符串的大小。不管 string 字符串的内容如何变化,它的 sizeof() 都是固定的,字符串所占的空间是从堆中动态分配的,与 sizeof() 无关。string 的实现在不同的编译器中可能有所不同,典型值有 4、12、16、24、32等。本机在 MinGW 5.3.0 编译器下测试得 sizeof(string) = 24

从以上分析可知,无法通过 memcpy 将 string 转换为 QString。原因总结如下:memcpy 是针对连续地址的拷贝,而 QString 是采用 2 个字节存储一个长度,无论英文还是中文,一个长度都是 2 个字节,std::string 存储 1 个英文占 1 个字节(不区分编码方式),GBK 编码方式下 1 个中文占 2 个字节,UTF-8 编码方式下 1 个中文占 3 个字节,因此无法按照 UTF-16 的(即 QString 的存储方式)的方式保存从 string 拷贝来的字符串

再谈论下为什么 memcpy() 函数适用于将 QString 转换为 std::string 呢???

QString 的 .toLocal8Bit() 或者 .toUtf8() 或者 .toLatin1() 都是将 QString 的字符串内容拷贝到一个 QByteArray 中,然后取 QByteArray 的地址和字节大小(即字符串的地址和字节大小)作为 memcpy() 的参数,不涉及原来 QString 的存储位置,因此不会出现问题

二、QString 与 char * 之间的转换

QString 转换为 char *

此处将 QString 转换为 char * 是指通过 QString 得到指向该字符串的指针,其实是指向了一个深拷贝字符串的地址,而不是 QString 本身的地址

  • .toLocal8Bit().data()

只要源文件的编码与程序内部使用的字符编码保持一致,此转换方法对中英文均适用(中文编码问题请参考《第十课:Qt 字符编码和中文乱码相关问题》)

cpp 复制代码
QString qstr = "您好world";

// 从 QString 到 char *
qDebug() << qstr.toLocal8Bit().data();        // 输出:您好world
  • .toUtf8().data()

此转换方法对中英文均适用

cpp 复制代码
QString qstr = "您好world";

// 从 QString 到 char *
qDebug() << qstr.toUtf8().data();        // 输出:您好world
  • .toLatin1().data()

由于 Latin1 代表 ASCII,无法表示中文。因此,此转换方法对英文适用,对中文则会出现乱码

cpp 复制代码
QString qstr1 = "您好";
QString qstr2 = "world";

// 从 QString 到 char *
qDebug() << qstr1.toLatin1().data();        // 输出:??
qDebug() << qstr2.toLatin1().data();        // 输出:world

以上三种方法的返回值均为 char *,可将这些指针赋值给其它的 char * 或者 const char * 指针,实际这个 char * 指针并不是指向原来 QString 的地址,而是指向一个 QString 深拷贝后字符串的地址,即 QByteArray 中存储字符串的地址

以上三种方法得到的是一个深拷贝字符串的地址,而不是 QString 本身的地址,那么 QString 本身的地址怎么获取?答案是:QString 的 .data() 函数

cpp 复制代码
QChar *QString::data()
Returns a pointer to the data stored in the QString. The pointer can be used to access and modify the characters that compose the string. For convenience, the data is '\0' terminated.

QString 的 .data() 函数的返回值为一个 QChar 指针,可以通过这个指针访问和修改该字符串

cpp 复制代码
QString str = "Hello world";
QChar * data = str.data();
while (!data->isNull()) 
{
      qDebug() << data->unicode() << (char)data->unicode();
      ++data;
}

QString 转换为 const char *

此处将 QString 转换为 const char * 是指通过 QString 得到指向该字符串的指针,其实是指向了一个深拷贝字符串的地址,而不是 QString 本身的地址

  • .toStdString().c_str()

返回值为 const char *,无法再赋值给其它指针,此转换方法对中英文均适用

cpp 复制代码
QString qstr = "您好world";

// 从 QString 到 const char *
qDebug() << qstr.toStdString().c_str();        // 输出:您好world
  • .toStdString().data()

返回值为 const char *,无法再赋值给其它指针,此转换方法对中英文均适用

cpp 复制代码
QString qstr = "您好world";

// 从 QString 到 const char *
qDebug() << qstr.toStdString().data();        // 输出:您好world
  • .toLocal8Bit().data()

函数重载,返回值为 const char *,此转换方法对中英文均适用

cpp 复制代码
QString qstr = "您好world";

// 从 QString 到 const char *
qDebug() << qstr.toLocal8Bit().data();        // 输出:您好world
  • .toUtf8().data()

函数重载,返回值为 const char *,此转换方法对中英文均适用

cpp 复制代码
QString qstr = "您好world";

// 从 QString 到 const char *
qDebug() << qstr.toUtf8().data();        // 输出:您好world
  • .toLatin1().data()

函数重载,返回值为 const char *,此转换方法对英文适用,对中文则会出现乱码

cpp 复制代码
QString qstr1 = "您好";
QString qstr2 = "world";

// 从 QString 到 char *
qDebug() << qstr1.toLatin1().data();        // 输出:??
qDebug() << qstr2.toLatin1().data();        // 输出:world
  • .toLocal8Bit().constData()

返回值为 const char *,无法再赋值给其它指针,此转换方法对中英文均适用

cpp 复制代码
QString qstr = "您好world";

// 从 QString 到 const char *
qDebug() << qstr.toLocal8Bit().constData();        // 输出:您好world
  • .toUtf8().constData()

返回值为 const char *,无法再赋值给其它指针,此转换方法对中英文均适用

cpp 复制代码
QString qstr = "您好world";

// 从 QString 到 const char *
qDebug() << qstr.toUtf8().constData();        // 输出:您好world
  • .toLatin1().constData()

返回值为 const char *,此转换方法对英文适用,对中文则会出现乱码

cpp 复制代码
QString qstr1 = "您好";
QString qstr2 = "world";

// 从 QString 到 char *
qDebug() << qstr1.toLatin1().constData();        // 输出:??
qDebug() << qstr2.toLatin1().constData();        // 输出:world

char * 转换为 QString

此处 char * 转换为 QString 是指通过一个指向字符串的指针创建一个 QString 字符串

  • QString(const char *str) // 等价于 char * str

可通过 QString 的构造函数,传入一个字符串的指针,创建 QString 字符串。按照 C++ 的规则,直接将 char * 赋值给 QString,它会自动寻找 QString 最为相近的构造函数,即 QString(const char * str)。因此,QString 构造函数可以省略,直接将 char * 赋值给 QString

cpp 复制代码
char * pstr = "您好world";
QString qstr = pstr;        // 等价于 QString qstr = QString(pstr); 
qDebug() << qstr;           // 输出:您好world        

三、QString 与 char[] 之间的转换

QString 转换为 char[]

QString 转换为 char[] 是指将 QString 字符串赋值给 char[](字符数组),字符数组的长度至少要比字符串的字节大小还要大 1(最后一位为'\0'),否则会导致异常

  • memcpy(char* dst, char* src, unsigned int maxCount);

采用内存拷贝的方法可以实现 QString 到 char[] 的转换,dst 为 char[] 的地址,即字符数组名,src 为 QString 字符串的地址,maxCount 为 QString 字符串的字节大小

dst 为 char[] 的地址,即字符数组名

src 为 QString 字符串的地址,可以调用 QString 的 .toLocal8Bit().data() 或者 .toUtf8().data() 或者 .toLatin1().data() 方法

maxCount 为 QString 字符串的字节大小,可以调用 QString 的 .toLocal8Bit().size()(或者 .count() 或者 .length())或者 .toUtf8().size()(或者 .count() 或者 .length())或者 .toLatin1().size()(或者 .count() 或者 .length()) 方法

由此产生多种组合方式:

  • memcpy(astr, qstr.toLocal8Bit().data(), qstr.toLocal8Bit().size());
  • memcpy(astr, qstr.toLocal8Bit().data(), qstr.toLocal8Bit().count());
  • memcpy(astr, qstr.toLocal8Bit().data(), qstr.toLocal8Bit().length());

只要源文件的编码与程序内部使用的字符编码保持一致,那么采用 .toLocal8Bit() 的 memcpy() 转换方法对中英文均适用(中文编码问题请参考《第十课:Qt 字符编码和中文乱码相关问题》)

cpp 复制代码
QString qstr = "您好world";
char astr[100];

// 从 QString 到 char[]
memcpy(astr, qstr.toLocal8Bit().data(), qstr.toLocal8Bit().size());
qDebug() << astr;                //输出:您好world

//    memcpy(astr, qstr.toLocal8Bit().data(), qstr.toLocal8Bit().count());
//    qDebug() << astr;          //输出:您好world 
     
//    memcpy(astr, qstr.toLocal8Bit().data(), qstr.toLocal8Bit().length());
//    qDebug() << astr;          //输出:您好world
  • memcpy(astr, qstr.toUtf8().data(), qstr.toUtf8().size());
  • memcpy(astr, qstr.toUtf8().data(), qstr.toUtf8().count());
  • memcpy(astr, qstr.toUtf8().data(), qstr.toUtf8().length());

采用 .toUtf8() 方法的 memcpy() 转换方法对中英文均适用

cpp 复制代码
QString qstr = "您好world";
char astr[100];

// 从 QString 到 char[]
memcpy(astr, qstr.toUtf8().data(), qstr.toUtf8().size());
qDebug() << astr;                //输出:您好world

//    memcpy(astr, qstr.toUtf8().data(), qstr.toUtf8().count());
//    qDebug() << astr;          //输出:您好world 
     
//    memcpy(astr, qstr.toUtf8().data(), qstr.toUtf8().length());
//    qDebug() << astr;          //输出:您好world
  • memcpy(astr, qstr.toLatin1().data(), qstr.toLatin1().size());
  • memcpy(astr, qstr.toLatin1().data(), qstr.toLatin1().count());
  • memcpy(astr, qstr.toLatin1().data(), qstr.toLatin1().length());

由于 Latin1 代表 ASCII,无法表示中文。因此,采用 .toLatin1() 方法的 memcpy() 转换方法对英文适用,对中文则会出现乱码

cpp 复制代码
QString qstr1 = "您好";
QString qstr2 = "world";
char astr1[100], astr2[100];    // 如果出现奇怪字符,则需初始化为空,char astr1[100] = {};

// 从 QString 到 char[]
memcpy(astr1, qstr1.toLatin1().data(), qstr1.toLatin1().size());
memcpy(astr2, qstr2.toLatin1().data(), qstr2.toLatin1().size());
qDebug() << astr1 << astr2;          //输出:?? world

//    memcpy(astr1, qstr1.toLatin1().data(), qstr1.toLatin1().count());
//    memcpy(astr2, qstr2.toLatin1().data(), qstr2.toLatin1().count());
//    qDebug() << astr1 << astr2;    //输出:?? world
     
//    memcpy(astr1, qstr1.toLatin1().data(), qstr1.toLatin1().length());
//    memcpy(astr2, qstr2.toLatin1().data(), qstr2.toLatin1().length());
//    qDebug() << astr1 << astr2;    //输出:?? world

char[] 转换为 QString

char[] 转换为 QString 是指通过 char[](字符数组)创建一个 QString 字符串,只需通过 QString 的构造函数即可完成 char[] 到 QString 的转换

char[] 逐个字符赋值到 QString 中,直到遇到 '\0' 字符停止赋值

cpp 复制代码
char astr[6] = {};        // 字符数组初始化为空,即每个字符均为 '\0'
astr[0] = 'h';
astr[1] = 'e';
astr[3] = 'l';
astr[4] = 'l';
astr[5] = 'o';
QString str = QString(astr);
qDebug() << str;         // 输出:he    astr[2]为'\0'
  • QString(const char *str) // 等价于 char *str

可通过 QString 的构造函数,传入一个字符串的指针(即字符数组名),创建 QString 字符串。按照 C++ 的规则,直接将 char * 赋值给 QString,它会自动寻找 QString 最为相近的构造函数,即 QString(const char * str)。因此,QString构造函数可以省略,直接将 char * (即字符数组名)赋值给 QString

cpp 复制代码
char astr[100] = "您好world";
QString qstr = astr;        // 等价于 QString qstr = QString(astr);
qDebug() << qstr;           // 输出:您好world

四、 string 与 char * 之间的转换

string 转换为 char *

string 转换为 char * 指的是获取 string 字符串的 char * 指针,可以通过调用 string 的 .data() 或者 .c_str() 方法获取

  • data()
cpp 复制代码
string str = "您好world";
qDebug() << str.data();            // 输出:您好world
  • c_str()
cpp 复制代码
string str = "您好world";
qDebug() << str.c_str();           // 输出:您好world

char * 转换为 string

char * 转换为 string 指的是通过 char * 指向的字符串构建 string 字符串,可以通过 string 的构造函数或者 memcpy() 来创建 string 字符串

  • string(const char * s) // 等价于 char * s

可通过 string 的构造函数,传入一个字符串的指针,创建 string 字符串。按照 C++ 的规则,直接将 char * 赋值给 string,它会自动寻找 string 最为相近的构造函数,即 string(const char * s)。因此,string 构造函数可以省略,直接将 char * 指针赋值给 string

cpp 复制代码
char * pstr = "您好world";
string str = pstr;         // 等价于 string str = string(pstr);
qDebug() << str.data();    // 输出:您好world
  • memcpy(char* dst, char* src, unsigned int maxCount);

采用内存拷贝的方法可以实现 char * 到 string 的转换,dst 为 string 的地址,src 为 char * 指向的字符串的地址,maxCount 为 char * 指向的字符串的字节大小

cpp 复制代码
char * pstr = "您好world";
int strSize = sizeof("您好world");    // UTF-8编码:strSize 为 12,一个汉字占 3 个字节,一个英文占 1 个字节,加上字符结束符 '\0',共计 12 个字节
string str;
str.resize(strSize);                        
memcpy((char*)str.data(),pstr,strSize);     
qDebug() << str.data();               // 输出:您好world                

注意:在 memcpy 给 string 变量之前,一定要设置 string 的字节大小,否则只是浅拷贝(即string 指针指向字符串地址,string 并未开辟内存,string 字符串为空),只有设置了 string 的字节大小,才能实现字符串的深拷贝

五、 string 与 char[] 之间的转换

string 转换为 char[]

string 转换为 char[] 指的是将 string 字符串赋值给字符数组(char[])

  • memcpy(char* dst, char* src, unsigned int maxCount);

采用内存拷贝的方法可以实现 string 到 char[] 的转换,dst 为字符数组 char[] 的地址(即字符数组名),src 为 string 字符串的地址,maxCount 为 string 字符串的字节大小

dst 为字符数组 char[] 的地址,即字符数组名

src 为 string 字符串的地址,可以调用 string 的 .data() 或者 .c_str() 方法

maxCount 为 string 字符串的字节大小,可以调用 string 的 .size() 或者 .length() 方法

由此产生多种组合方式:

memcpy(astr,str.data(),str.size())

memcpy(astr,str.data(),str.length())

memcpy(astr,str.c_str(),str.size())

memcpy(astr,str.c_str(),str.length())

cpp 复制代码
string str = "您好world";
char astr[20];

memcpy(astr,str.data(),str.size());
qDebug() << astr;        // 输出:您好world

//    memcpy(astr,str.data(),str.length());
//    qDebug() << astr;        // 输出:您好world

//    memcpy(astr,str.c_str(),str.size());
//    qDebug() << astr;        // 输出:您好world

//    memcpy(astr,str.c_str(),str.length());
//    qDebug() << astr;        // 输出:您好world

这里需要注意的是,字符数组(char[])的字节长度必须大于 string 字符串的字节长度,否则会出现字符数组溢出 。当数组溢出时,memcpy() 的数据会覆盖数组以外的数据,可能会导致发生不可预测的错误,建议字符数组的字节长度一定要大于字符串的字节长度

补充:如果数组溢出没有导致程序退出,则 qDebug() << astr 会将字符串中的所有字符都打印出来,因为直到遇到 '\0' 字符才会停止打印,但是 astr[] 中存储的只有前 20 个字符

  • 逐个字节赋值

采用逐个字节赋值的方法也可以将 string 字符串赋值给字符数组 char[],string 字符串的字节长度可以通过 string 的 .size() 或者 .length() 方法获取

cpp 复制代码
string str = "您好world";
char astr[20] = {};        // 初始化为空,所有字符均为 '\0'
for(int i=0; i<str.size(); i++)        // 或者 str.length()
{
    astr[i] = str[i];
}
qDebug() << astr;            // 输出:您好world

这里注意事项和上面情况一样,字符数组(char[])的字节长度必须大于 string 字符串的字节长度,否则会出现字符数组溢出 。当数组溢出时,字符串会覆盖数组以外的数据,可能会导致发生不可预测的错误,建议字符数组的字节长度一定要大于字符串的字节长度

补充:如果数组溢出没有导致程序退出,则 qDebug() << astr 会将字符串中的所有字符都打印出来,因为直到遇到 '\0' 字符才会停止打印,但是 astr[] 中存储的只有前 20 个字符

char[] 转换为 string

char[] 转换为 string 指的是通过 char[] 存储的字符串创建一个 string 字符串,字符数组(char[])的数组名其实就是其所指向字符串的地址,因此将 char[] 转换为 string 的方法与 char * 转化为 string 的方法相同,可以通过 string 的构造函数或者 memcpy() 来创建 string 字符串

  • string(const char * s) // 等价于 char * s

可通过 string 的构造函数,传入一个字符串的指针(即字符数组名),创建 string 字符串。按照 C++ 的规则,直接将 char * 赋值给 string,它会自动寻找 string 最为相近的构造函数,即 string(const char * s)。因此,string 构造函数可以省略,直接将 char * (即字符数组名)直接赋值给 string

cpp 复制代码
char astr[20] = "您好world";
string str = astr;         // 等价于 string str = string(astr);
qDebug() << str.data();    // 输出:您好world
  • memcpy(char* dst, char* src, unsigned int maxCount);

采用内存拷贝的方法可以实现 char[] 到 string 的转换,dst 为 string 的地址,src 为字符数组 char[] 存储的字符串的地址,maxCount 为字符数组 char[] 存储的字符串的字节大小

cpp 复制代码
char astr[20] = "您好world";
int strSize = sizeof("您好world");    // UTF-8编码:strSize 为 12,一个汉字占 3 个字节,一个英文占 1 个字节,加上字符结束符 '\0',共计 12 个字节
string str;
str.resize(strSize);                              
memcpy((char*)str.data(),astr,strSize);       
qDebug() << str.data();               // 输出:您好world                        

注意:在 memcpy 给 string 变量之前,一定要设置 string 的字节大小,否则只是浅拷贝(即string 指针指向字符串地址,string 并未开辟内存,string 字符串为空),只有设置了 string 的字节大小,才能实现字符串的深拷贝

与 char * 不同的是,char[] 可以存储单个字符,而非字符串,如 char a[10] = {'a','\0','c','e'}

cpp 复制代码
char astr1[10] = {'a','\0','c','e'};
char astr2[10] = {'a','b','c','e'};
string str1 = astr1;
string str2 = astr2;
qDebug() << str1.data() << str1.size() << QString::fromStdString(str1);        // a    1    a
qDebug() << str2.data() << str2.size() << QString::fromStdString(str2);        // abce    4     abce

string str3,str4;
str3.resize(4);
str4.resize(4);
memcpy((char*)str3.data(),astr1,4);
memcpy((char*)str4.data(),astr2,4);
qDebug() << str3.data() << str3.size() << QString::fromStdString(str3);        // a    4    a\u0000ce
qDebug() << str4.data() << str4.size() << QString::fromStdString(str4);        // abce    4     abce

经过上述测试可知,string(const char * s) 方法在逐个字符赋值时遇到 '\0' 则停止赋值,memcpy 方法拷贝的内容取决于对 string 设置的大小(即 resize()),其内容为从 char[] 地址开始,到 resize() 设置字节大小的所有内容,其实就是内存的拷贝,与字符串无关

六、 char * 与 char[] 之间的转换

char * 转换为 char[]

char * 转换为 char[] 指的是将 char * 指向的字符串赋值给 char[] 数组

  • memcpy(char* dst, char* src, unsigned int maxCount);

采用内存拷贝的方法可以实现 char * 到 char[] 的转换,dst 为字符数组 char[] 的地址(即字符数组名),src 为 char * 指向的字符串的地址,maxCount 为 char * 指向的字符串的字节大小

dst 为字符数组 char[] 的地址,即字符数组名

src 为 char * 指向的字符串的地址,即指针名称

maxCount 为 char * 指向的字符串的字节大小

cpp 复制代码
char * pstr = "您好world";
int strSize = sizeof("您好world");    // UTF-8编码:strSize 为 12,一个汉字占 3 个字节,一个英文占 1 个字节,加上字符结束符 '\0',共计 12 个字节
char astr[20];
memcpy(astr,pstr,strSize);
qDebug() << astr;        // 输出:您好world

需要注意的是,字符数组(char[])的字节长度必须大于 char * 指向的字符串的字节长度,否则会出现字符数组溢出 。当数组溢出时,memcpy() 的数据会覆盖数组以外的数据,可能会导致发生不可预测的错误,建议字符数组的字节长度一定要大于char * 指向的字符串的字节长度

char[] 转换为 char *

char[] 转换为 char * 有两种理解,一种是 char * 指向字符数组 char[] 的地址,另一种是将 char[] 存储的内容赋值给 char *(此时需要在堆上开辟内存)

  • char * 指向字符数组 char[] 的地址
cpp 复制代码
char astr[20] = "您好world";
char * pstr = astr;                // pstr 指向 astr 数组的地址
//    char * pstr = &astr[0];      // pstr 指向 astr 数组中第一个元素的地址

其实 astr 与 &astr[0] 是同一个值,只是表示的含义不同, astr 表示字符数组的地址,&astr[0] 表示字符数组第一个元素的地址,本质上是同一个位置

  • char[] 存储的内容赋值给 char *
cpp 复制代码
char astr[20] = "您好world";
char * pstr = new char[20];
memcpy(pstr,astr,20);
qDebug() << (long)astr << astr;        // 输出:6345660 您好world
qDebug() << (long)pstr << pstr;        // 输出:52557552 您好world

如果需要将 char[] 存储的内容赋值给 char *,则需要为 char * 指针开辟一个同样大小的内存,然后通过 memcpy() 将 char[] 存储的内容赋值给 char * 指向的内存块

通过输出结果可知,这两个地址确实不同(具体地址数值每次运行都是不同的),表明这两个指针是指向不同的内存块,而指针指向的内容是相同的

相关推荐
lxyzcm29 分钟前
深入理解C++23的Deducing this特性(上):基础概念与语法详解
开发语言·c++·spring boot·设计模式·c++23
过过过呀Glik1 小时前
在 Ubuntu 上安装 Muduo 网络库的详细指南
linux·c++·ubuntu·boost·muduo
蜀黍@猿2 小时前
【C++ 基础】从C到C++有哪些变化
c++
Am心若依旧4092 小时前
[c++11(二)]Lambda表达式和Function包装器及bind函数
开发语言·c++
zh路西法2 小时前
【C++决策和状态管理】从状态模式,有限状态机,行为树到决策树(一):从电梯出发的状态模式State Pattern
c++·决策树·状态模式
轩辰~3 小时前
网络协议入门
linux·服务器·开发语言·网络·arm开发·c++·网络协议
lxyzcm3 小时前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23
蜀黍@猿3 小时前
C/C++基础错题归纳
c++
雨中rain4 小时前
Linux -- 从抢票逻辑理解线程互斥
linux·运维·c++
ALISHENGYA5 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战项目二)
数据结构·c++·算法