我刚刚完成了a common newbie mistake:
首先我们阅读one of many tutorials,如下所示:
#include <fstream>
int main() {
using namespace std;
ifstream inf("file.txt");
// (...)
}
其次,我们尝试在代码中使用类似的东西,如下所示:
#include <fstream>
int main() {
using namespace std;
std::string file = "file.txt"; // Or get the name of the file
// from a function that returns std::string.
ifstream inf(file);
// (...)
}
第三,新手开发人员对一些神秘的编译器错误消息感到困惑。
问题是ifstream将const * char
作为构造函数参数。
solution是convert std::string to const * char。
现在,真正的问题是,对于新手来说,几乎所有教程中给出的“file.txt”或类似示例看起来都像std :: string。
那么,“我的文本”是std :: string,c-string还是* char,还是取决于上下文?
您能否根据具体情况提供有关“我的文本”的解释方式的示例?
[编辑:我认为上面的例子会让它显而易见,但我应该更明确一点:我的意思是双引号中包含的任何字符串的类型,即“myfilename.txt”,而不是意思“string”这个词。]
感谢。
答案 0 :(得分:10)
那么,“string”是std :: string,c-string还是* char,还是取决于上下文?
const char *
(或者说const char []
)。 “C string”通常是指这个,特别是带有null终止符的字符数组。std::string
是一个将原始字符串包装到对象中的便捷类。通过使用它,您可以避免必须自己执行(杂乱)指针算法和内存重新分配。char *
(或const char *
)个参数。char *
隐式转换为std::string
,因为后者有一个构造函数来执行此操作。std::string
方法将const char *
明确转换为c_str()
。感谢Clark Gaebel指出const
ness,以及jalf和GMan提到它实际上是一个阵列。
答案 1 :(得分:7)
"myString"
是字符串文字,类型为const char[9]
,数组为9常量char
。请注意,它有足够的空间用于null终止符。因此"Hi"
是const char[3]
,依此类推。
这几乎总是正确的,没有歧义。但是,必要时,const char[9]
会衰减为指向其第一个元素的const char*
。 std::string
有一个隐式构造函数,它接受const char*
。因此,虽然它始终以char数组的形式开始,但如果需要它,它可以成为其他类型。
请注意,字符串文字具有const char[N]
也可以衰减为char*
的唯一属性,但不推荐使用此行为。如果您尝试以这种方式修改基础字符串,则最终会出现未定义的行为。这不是一个好主意。
答案 2 :(得分:3)
std::string file = "file.txt";
=
的右侧包含一个(原始)字符串文字(即一个以空字符结尾的字节字符串)。其有效类型为array of const char
。
=
在这里是一个棘手的小马:没有任务分配。 std::string
类有一个构造函数,它将一个指向char的指针作为参数,并调用它来创建一个临时std::string
,这用于复制构造(使用{{1}的副本ctor })std::string
类型的对象file
。
编译器可以自由地删除copy ctor并直接实例化文件。
但请注意,std::string
与C样式的以null结尾的字符串不同。它甚至不需要以空终止。
std:string
ifstream inf("file.txt");
类有一个ctor,它接受std::ifstream
并且传递给它的字符串文字衰减到指向字符串第一个元素的指针。
要记住的是:const char *
提供(几乎无缝)C风格字符串的转换。你必须查找函数的签名,看看你是在传递std::string
还是const char *
(后者是因为隐式转换)。
答案 3 :(得分:2)
那么,“string”是
std::string
,c-string还是char*
,还是取决于上下文?
完全取决于具体情况。 :-)欢迎使用C ++。
C字符串是以空字符结尾的字符串,几乎总是与char*
相同。
根据您使用的平台和框架,“string”一词的含义可能更多(例如,它也用于引用Qt中的QString
或CString
中的{{1}} MFC)。
答案 4 :(得分:1)
C ++标准库提供了一个std :: string类来管理和表示字符序列。它封装了内存管理,大部分时间都是作为C字符串实现的;但这是一个实施细节。它还为常见任务提供操作例程。
std :: string类型总是那样(例如,它没有char *的转换运算符,这就是为什么你有c_str()方法),但它可以被C初始化或赋值给它-string(char *)。
另一方面,如果你有一个带std :: string或const std :: string&amp;的函数。作为参数,您可以将c-string(char *)传递给该函数,编译器将为您构建一个std :: string。根据你提出的背景,这将是一种不同的解释。
答案 5 :(得分:1)
C和C ++都没有内置的字符串数据类型。
当编译器在编译过程中发现隐式引用双引号字符串时(参见下面的代码),字符串本身存储在程序代码/文本中并生成代码以创建均匀的代码字符数组:
最后,你所拥有的是这个常量静态字符数组的 const char * 。
const char* v()
{
char* text = “Hello”;
return text;
// Above code can be reduced to:
// return “Hello”;
}
在程序运行期间,当控件找到左括号时,它会在堆栈中创建“text”,char *指针,并在静态中创建6个元素的常量数组(包括末尾的空终结符'\ 0')记忆区。当控件找到下一行(char * text =“Hello”;)时,6元素数组的起始地址被分配给“text”。在下一行(返回文本;)中,它返回“text”。使用右括号“text”将从堆栈中消失,但是数组仍然在静态存储区中。
您不需要返回类型const。但是如果你尝试使用非常量char *更改静态数组中的值,它仍会在运行时给出错误,因为数组是常量。因此,确保返回常量总是好的,它不能被非常量指针引用。
但是如果编译器发现双引号字符串被明确地称为数组,则编译器会假定程序员将(巧妙地)处理它。请参阅以下错误示例:
const char* v()
{
char text[] = “Hello”;
return text;
}
在编译期间,编译器检查,引用文本并将其保存在代码中,以便在欠幅时间内填充生成的数组。此外,它计算数组大小,在这种情况下再次为6。
在程序运行期间,使用open括号,在堆栈中创建具有6个元素的数组“text []”。但没有初始化。当代码找到(char text [] =“Hello”;)时,数组被初始化(使用编译代码中的文本)。所以数组现在在堆栈上。当编译器找到(return text;)时,它返回数组“text”的起始地址。当编译器找到结束括号时,数组将从堆栈中消失。因此无法通过返回指针引用它。
大多数标准库函数仍然只使用char *(或const char *)参数。
标准C ++库有一个强大的类,称为字符串,用于处理文本。字符串的内部数据结构是字符数组。标准C ++字符串类旨在处理(并隐藏)以前C程序员所需的字符数组的所有低级操作。请注意,std :: string是一个类:
答案 6 :(得分:0)
如果您使用的是提供此类内容的框架,则应尽可能频繁地std::string
(或wxString
,QString
等替代方案。有时您有没有真正的选择,只能使用NUL终止的字节序列,但您通常希望尽可能避免使用它。
归根结底,根本没有明确,明确的术语。这就是生活。
答案 7 :(得分:0)
使用正确的措辞(如C ++语言标准中所示) string 是第21.3节“字符串类”中std :: basic_string(包括std :: string)的变种之一(如在C ++ 0x N3092中),而ifstream的构造函数的参数是 NTBS (以空值终止的字节序列)
引用,C ++ 0x N3092 27.9.1.4/2。
basic_filebuf * open(const char * s,ios_base :: openmode mode);
...
如果可能,打开一个文件,其名称为NTBS s