指针和字符串C ++

时间:2013-12-27 04:38:27

标签: c++ pointers

我正在教自己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; 

我收到错误消息。

基本上,总结一下我的问题,我试图通过strcpycout语句来理解代码。

9 个答案:

答案 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}}。

相关:How is std::string implemented?

答案 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提供了两种返回指向其基础内容的指针的方法:datac_str。在Pre-C ++ 11中,唯一的区别是data不包含NUL终结符。在C ++ 11中,它现在可以,所以它们的行为是相同的。因为指针很容易被无效,所以操纵那些指针是不安全的。执行char * ptr = str.c_str();也不安全,因为c_str返回的数组的生命周期在分号处死亡。您需要将其复制到缓冲区中。

答案 5 :(得分:2)

您提出正确的问题作为学习者。

数目:

  1. 在C ++中,string是一个对象,c_str()本质上返回指向第一个的对象 字符串的字符(C样式)
  2. 你对C中的字符串是正确的,变量实际上指的是第一个字符 字符串
  3. 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风格字符串的标准库函数都会使用指向所述字符串的指针,原因有两个:

  1. 与其他数组不同,将C样式字符串视为一个整体而不是一堆字符更容易,因此使用指针可以保持这种想法
  2. 这是将数组作为函数参数来获取指向第一个元素的指针的最简单方法,尤其是在C字符串的情况下,它们只能被读取为NULL字符。

答案 8 :(得分:1)

我认为你在做什么,如果我错了,请其他人纠正我,是你将你的字符串复制到动态字符数组中。所以不,你没有把它复制到指针。指针涉及的原因是因为动态数组需要指针才能正确分配内存。