我正在教自己C ++,我对指针有点困惑(特别是在以下源代码中)。但首先,我继续向您展示我所知道的内容(然后将代码与此对比,因为我觉得好像存在一些矛盾)。
我所知道的:
int Age = 30;
int* pointer = &Age;
cout << "The location of variable Age is: " << pointer << endl;
cout << "The value stored in this location is: " << *pointer << endl;
指针保存内存地址。使用间接(取消引用)运算符(*),可以访问存储在指针的内存位置的内容。在本书的代码中,我无法理解......
cout << "Enter your name: ";
string name;
getline(cin, name); //gets full line up to NULL terminating character
int CharsToAllocate = name.length() + 1; //calculates length of string input
//adds one onto it to adjust for NULL character
char* CopyOfName = new char[CharsToAllocate];
// pointer to char's called CopyOfName, is given the memory address of the
//beginning of a block
//of memory enough to fit CharsToAllocate. Why we added 1? Because char's need a
//NULL terminating character (\0)
strcpy(CopyOfName, name.c_str()); //copies the string name, into a pointer?
cout << "Dynamically allocated buffer contains: " << CopyOfName << endl;
delete[] CopyOfName; //always delete a pointer assigned by new to prevent memory leaks
输出:
Enter your name: Adam
Dynamically allocated buffer contains: Adam
以上代码中的评论是我的评论。我的问题始于strcpy
。为什么name.c_str()
被复制到指针CopyOfName
?这是否意味着所有字符串都是必不可少的指针?所以喜欢
string testing =“Hello world”;
实际上是指向存储“H”的存储位置的指针吗?
接下来,为什么在使用CopyOfName
而非*CopyOfName
的打印输出声明中?指针有内存地址吗?使用*CopyOfName
将打印出内存位置的内容。我在Code :: Blocks中尝试了这个,如果输入文本是“Hello World”。在打印输出语句中使用*CopyOfName
只会给出“H”。这是有道理的,因为当我声明我需要一个带有'new'的内存块时,这实际上会返回一个指向动态分配的内存块的第一部分的指针。
我可以协调这一点的唯一方法是,如果一个字符串实际上是一个指针。
string testing = "Confused";
cout << testing << endl;
会打印出“困惑”一词
但是,如果我尝试编译
string testing = "Confused";
cout << *testing;
我收到错误消息。
基本上,总结一下我的问题,我试图通过strcpy
和cout
语句来理解代码。
答案 0 :(得分:17)
看起来你理解C风格的字符串是什么,但总而言之,它们只是内存中的字符数组,按惯例以空字符\0
结尾。通常它们通过char*
引用,指向字符串中的第一个字母。打印时,通常从第一个字符开始打印字符串的字符,并在到达\0
终止符时停止打印(或复制等)。
std::string
是一个(通常)包装C风格字符串的类。这意味着std::string
对象(通常)具有用于实现其功能的私有C样式字符串。函数std::string::c_str()
返回指向这个底层C风格字符串的指针。
假设char *str;
指向C风格的字符串。如果您尝试运行cout << *str << endl;
,您会注意到只打印了第一个字符。那是因为C ++的函数重载。 *str
的数据类型为char
,因此调用char
cout
版本的*str
并忠实地打印单个字符cout
。为了与C风格的字符串兼容,以char*
为参数的cout
版本将指针视为用于打印目的的C风格字符串。例如,如果您int*
int
,则不会打印基础std::string
。
编辑:另一条评论:
您尝试取消引用std::string::c_str()
对象失败的原因是,它确实不是指针。您可以取消引用char
的返回值,然后返回字符串的第一个{{1}}。
答案 1 :(得分:3)
在C中,字符串只是字符数组。当用作函数的参数时,数组会衰减为指针。
在C ++中,std::string
是一个类。它包含一个C风格的字符数组,这就是c_str()
返回的内容。但是字符串本身不是指针,所以你不能取消引用它;你必须使用c_str()
方法来获取指向字符串内容的指针。
答案 2 :(得分:3)
那么像
string testing = "Hello world";
实际上是指向存储“H”的存储位置的指针吗?
不,上面你有一个叫string
的对象。 char* testing = "Hello World"
就是这样。如你所见,它甚至被声明为指针,它指向字符串中的第一个字符 - H。
接下来,为什么在
CopyOfName
不是*CopyOfName
的打印声明中?指针有内存地址吗?使用*CopyOfName
将打印出内存位置的内容。我在代码块中尝试了这个,如果输入文本是“Hello World”。在打印输出语句中使用*CopyOfName
只会给出“H”
cout将指针指向字符串的第一个字符,因此CopyOfName
是正确的。在这种情况下,它将打印从H开始的每个字符,直到找到\ 0(空字符)。像“你好”这样的字符串实际上有6个字符 - 'h''e''l''''''''0'
当您编写*CopyOfName
时,您正在取消引用此指针,*CopyOfName
实际上只有一个字符
答案 3 :(得分:3)
按顺序提出问题:
“为什么name.c_str()被复制到指针CopyOfName?这是不是意味着什么? 所有字符串都是必不可少的指针?所以像字符串测试= “你好,世界”;实际上是一个指向内存位置的指针 “H”存储在哪里?“
正如Yu Hao在他/她的评论中指出的那样,理解C ++风格的字符串和C风格的字符串之间的区别非常重要。在第一种情况下,您正在处理“不透明”对象,而在后一种情况下,您基本上处理的是“数组”字符。
使用C ++字符串对象,您可以使用c_str()
方法获取(指向一个)C样式字符数组。在C中,使用指向数组开头的指针表示数组,然后通过从该起始地址提供偏移量(索引到数组中)来实现引用。所以这个包中最后一个问题的答案是“是”,指向C风格字符串的指针是指向第一个字符'H'的指针。
“接下来,为什么在打印输出语句中没有CopyOfName * CopyOfName?指针有内存地址吗?“
因为运算符<<
被重载以处理C字符串。这个方法的实现“知道如何处理”指针。
答案 4 :(得分:3)
指针与数组不同。字符串文字是不可变的,当你有一个指向字符串文字的指针时,你可以检查它的内容,但修改它们是未定义的行为。使用此语法时:
char arr[] = "hi there";
将字符串文字复制到数组中。因为您没有指定大小,编译器会自动推导它。 NUL
终止符也会自动添加。如果指定大小,则必须确保缓冲区可以容纳NUL
终止符。因此:
char arr[5] = "hello";
是个错误。如果使用大括号初始值设定语法:
char arr[5] = { "h", "e", "l", "l", "o" };
这是一个错误,因为没有NUL
终止符。如果您使用strcpy
,则会为您添加NUL
终止符。
std::string
提供了两种返回指向其基础内容的指针的方法:data
和c_str
。在Pre-C ++ 11中,唯一的区别是data
不包含NUL
终结符。在C ++ 11中,它现在可以,所以它们的行为是相同的。因为指针很容易被无效,所以操纵那些指针是不安全的。执行char * ptr = str.c_str();
也不安全,因为c_str
返回的数组的生命周期在分号处死亡。您需要将其复制到缓冲区中。
答案 5 :(得分:2)
您提出正确的问题作为学习者。
数目:
string
是一个对象,c_str()
本质上返回指向第一个的对象
字符串的字符(C样式)string
对象时
cout
打印字符串。此外,C ++足够聪明,可以确定*testing
是非法的答案 6 :(得分:2)
为什么将name.c_str()复制到指针CopyOfName中?
“name”是一个STL字符串。这是一个与c字符串不同的对象。 c-string是一个内存集合,它包含字符,并具有空终止。因此,如果您正在使用STL字符串并希望将它们转换为c字符串,则可以使用.c_str()来获取c字符串。
CopyOfName包含足够的内存来保存名称,因为它被分配用来保存它。
cout有一些不同的东西,你可以使用&lt;&lt;。看起来它可能需要char *(它是c-strings)或STL字符串。看起来它不能指向STL字符串。
当你介绍“测试”时我有点困惑,但我认为你在c-strings(它们是char *)和STL字符串(它们是对象)之间感到困惑。不要心疼,否则就放弃。这个东西很棘手,需要一段时间才能搞定。
我建议尝试理解术语“c-string”,“char *”,“stl string”和“指向stl字符串的指针”之间的差异。
答案 7 :(得分:1)
在C中,C ++标准字符串不存在,char *就是所谓的“字符串”。如您所述,它是一个以NULL字符结尾的字符数组。几乎所有采用C风格字符串的标准库函数都会使用指向所述字符串的指针,原因有两个:
答案 8 :(得分:1)
我认为你在做什么,如果我错了,请其他人纠正我,是你将你的字符串复制到动态字符数组中。所以不,你没有把它复制到指针。指针涉及的原因是因为动态数组需要指针才能正确分配内存。