指针和字符串 C++
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20794832/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pointers and Strings C++
提问by DWade64
I'm teaching myself C++ and I'm a bit confused about pointers (specifically in the following source code). But first, I proceed with showing you what I know (and then contrasting the code against this because I feel as if there are some contradictions going on).
我正在自学 C++ 并且我对指针有点困惑(特别是在以下源代码中)。但首先,我继续向您展示我所知道的(然后将代码与此进行对比,因为我觉得好像存在一些矛盾)。
What I know:
我知道的:
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;
Pointers hold memory addresses. Using the indirection (dereference) operator (the *), you can access what is stored in memory location of the pointer. Onto the code in this book I'm having trouble understanding...
指针保存内存地址。使用间接(取消引用)运算符(*),您可以访问存储在指针内存位置中的内容。关于本书中的代码,我无法理解...
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 (Enter your name: Adam
Dynamically allocated buffer contains: Adam
)
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
Output:
输出:
string testing = "Confused";
cout << testing << endl;
The comments in the above code are my comments. My problem begins with strcpy
. Why is name.c_str()
copied into a pointer CopyOfName
? Does this mean that all strings are essential pointers? So like
string testing = "Hello world";
Is actually a pointer pointing to the memory location where "H" is stored?
上面代码中的注释是我的注释。我的问题始于strcpy
. 为什么会被name.c_str()
复制到指针中CopyOfName
?这是否意味着所有字符串都是必不可少的指针?所以像 string testing = "Hello world"; 实际上是指向存储“H”的内存位置的指针吗?
Next, why is it in the print out statement using CopyOfName
and not *CopyOfName
? Pointers hold memory addresses? Using *CopyOfName
would print out the contents of the memory location. I tried this in Code::Blocks and if the input text was "Hello World." Using *CopyOfName
in the print out statement would just give an "H". This makes sense since when I declared that I needed a memory block with the 'new' thing, this actually returns a pointer to the first part of the dynamically allocated memory block.
接下来,为什么它在打印输出语句中使用CopyOfName
而不是*CopyOfName
?指针保存内存地址?使用*CopyOfName
将打印出内存位置的内容。我在 Code::Blocks 中尝试过这个,如果输入文本是“Hello World”。*CopyOfName
在打印输出语句中使用只会给出一个“H”。这是有道理的,因为当我声明我需要一个带有“新”事物的内存块时,这实际上返回了一个指向动态分配的内存块的第一部分的指针。
The only way I can reconcile this is if a string is actually a pointer.
我可以调和的唯一方法是字符串是否实际上是一个指针。
string testing = "Confused";
cout << *testing;
would print out the word "Confused"
会打印出“Confused”这个词
However, if I try to compile
但是,如果我尝试编译
char arr[] = "hi there";
I get an error message.
我收到一条错误消息。
Basically, to summarize my question, I'm trying to understand the code with strcpy
and the cout
statement.
基本上,总结我的问题,我试图理解代码strcpy
和cout
语句。
回答by Andrey Mishchenko
It seems like you understand what C-style strings are, but to summarize, they are just arrays of characters in memory, by convention terminated by a nul character \0
. Usually they are referenced via a char*
pointing to the first letter in the string. When they are printed, typically the characters of the string are printed starting from the first, and printing (or copying, etc.) stops when the \0
terminator is reached.
似乎您了解什么是 C 风格的字符串,但总而言之,它们只是内存中的字符数组,按照约定以 nul 字符结尾\0
。通常通过char*
指向字符串中的第一个字母来引用它们。打印时,通常从第一个开始打印字符串的字符,并在到达\0
终止符时停止打印(或复制等)。
An std::string
is a class that (typically) wraps a C-style string. This means that a std::string
object (typically) has a private C-style string that is used to implement its functionality. The function std::string::c_str()
returns a pointer to this underlying C-style string.
Anstd::string
是(通常)包装 C 样式字符串的类。这意味着std::string
对象(通常)具有用于实现其功能的私有 C 样式字符串。该函数std::string::c_str()
返回一个指向此底层 C 样式字符串的指针。
Let's suppose that char *str;
points to a C-style string. If you attempt to run cout << *str << endl;
, you noticed that only the first character is printed. That is because of C++'s function overloading. The data type of *str
is char
, so the char
version of cout
is called and faithfully prints the single character *str
. For compatibility with C-style strings, the version of cout
that takes a char*
as an argument treats the pointer as a C-style string for printing purposes. If you cout
an int*
, for example, the underlying int
will not be printed.
让我们假设它char *str;
指向一个 C 风格的字符串。如果您尝试运行cout << *str << endl;
,您会注意到只打印了第一个字符。那是因为 C++ 的函数重载。的数据类型*str
是char
,因此char
版本cout
被调用并忠实地打印单个字符*str
。为了与 C 样式字符串兼容cout
,将 achar*
作为参数的版本将指针视为 C 样式字符串以进行打印。如果你cout
的int*
,例如,底层int
不会被打印出来。
Edit:Another comment:
编辑:另一条评论:
The reason that your attempt to dereference an std::string
object failed is that, indeed, it is not a pointer. You could dereference the return value of std::string::c_str()
, and you would get back the first char
of the string.
您尝试取消引用std::string
对象失败的原因是,实际上,它不是指针。您可以取消引用 的返回值std::string::c_str()
,然后您将返回char
字符串的第一个。
Related: How is std::string implemented?.
回答by Barmar
In C, strings are simply arrays of characters. And arrays decay to pointers when used as the argument to a function.
在 C 中,字符串只是字符数组。当用作函数的参数时,数组会衰减为指针。
In C++, std::string
is a class. It includes a C-style character array within it, and this is what c_str()
returns. But the string itself is not a pointer, so you can't dereference it; you have to use the c_str()
method to get a pointer to the string contents.
在 C++ 中,std::string
是一个类。它在其中包含一个 C 风格的字符数组,这就是c_str()
返回的内容。但是字符串本身不是指针,所以你不能解引用它;您必须使用该c_str()
方法来获取指向字符串内容的指针。
回答by Turix
Taking your questions in order:
按顺序回答你的问题:
"Why is name.c_str() copied into a pointer CopyOfName? Does this mean that all strings are essential pointers? So like string testing = "Hello world"; Is actually a pointer pointing to the memory location where "H" is stored?"
“为什么将name.c_str()复制到一个指针CopyOfName中?这是否意味着所有字符串都是必不可少的指针?所以像string testing = "Hello world";实际上是一个指向存储“H”的内存位置的指针吗? ”
As Yu Hao pointed out in his/her comment, it is important to understand the difference between C++-style strings and C-style strings. In the first case, you are dealing with an "opaque" object, whereas in the latter case you are basically dealing with an "array" of characters.
正如 Yu Hao 在他/她的评论中指出的那样,了解 C++ 样式字符串和 C 样式字符串之间的区别很重要。在第一种情况下,您正在处理“不透明”对象,而在后一种情况下,您基本上是在处理字符“数组”。
With C++ string objects, you can use the c_str()
method to get a (pointer to a) C-style array of characters. In C, an array is represented using the pointer to the beginning of the array and then references are achieved by supplying an offset (the index into the array) from that starting address. So the answer to the last question in this bundle is "yes", the pointer to the C-style string is the pointer to the first character, 'H'.
对于 C++ 字符串对象,您可以使用该c_str()
方法获取(指向)C 样式字符数组。在 C 中,使用指向数组开头的指针来表示数组,然后通过提供从该起始地址的偏移量(数组中的索引)来实现引用。所以这个包中最后一个问题的答案是“是”,指向 C 样式字符串的指针是指向第一个字符 'H' 的指针。
"Next, why is it in the print out statement that CopyOfName is not *CopyOfName? Pointers hold memory addresses?"
“接下来,为什么在打印输出语句中 CopyOfName 不是 *CopyOfName?指针保存内存地址?”
Because the operator <<
is overloaded to handle C-strings. The implementation of this method "knows what to do with" the pointer.
因为运算符<<
被重载以处理 C 字符串。此方法的实现“知道如何处理”指针。
回答by Turix
Pointers are not the same as arrays. String literals are immutable, and when you have a pointer to a string literal, you can inspect its contents, but modifying them are undefined behavior. When using this syntax:
指针与数组不同。字符串文字是不可变的,当你有一个指向字符串文字的指针时,你可以检查它的内容,但修改它们是未定义的行为。使用此语法时:
char arr[5] = "hello";
The string literal is copied into the array. Because you do not specify a size, the compiler automatically deduces it. The NUL
terminator is automatically added as well. If you specify a size, you must make sure that the buffer can hold the NUL
terminator. Therefore:
字符串文字被复制到数组中。因为您没有指定大小,编译器会自动推断出它。的NUL
终止子被自动添加。如果指定大小,则必须确保缓冲区可以容纳NUL
终止符。所以:
char arr[5] = { "h", "e", "l", "l", "o" };
is a mistake. If you use the brace initializer syntax:
是一个错误。如果您使用大括号初始值设定项语法:
##代码##This is a mistake because there is no NUL
terminator. If you use strcpy
, a NUL
terminator will be added for you.
这是一个错误,因为没有NUL
终止符。如果您使用strcpy
,NUL
则会为您添加一个终止符。
std::string
provides two methods of returning a pointer to its underlying contents: data
and c_str
. Pre-C++11, the only difference is data
does not include the NUL
terminator. In C++11, it now does, so their behavior is identical. Because the pointer can easily be invalidated, is not safe to manipulate those pointers. It is also not safe to do char * ptr = str.c_str();
because the lifetime of the array returned by c_str
dies at the semi-colon. You need to copy it into a buffer.
std::string
提供了两种返回指向其底层内容的指针的方法:data
和c_str
. Pre-C++11,唯一的区别是data
不包括NUL
终止符。在 C++11 中,现在是这样,所以它们的行为是相同的。因为指针很容易失效,所以操作这些指针是不安全的。这样做也不安全,char * ptr = str.c_str();
因为返回的数组的生命周期c_str
在分号处结束。您需要将其复制到缓冲区中。
回答by janepe
So like
string testing = "Hello world";
Is actually a pointer pointing to the memory location where "H" is stored?
所以就像
string testing = "Hello world";
实际上是一个指针指向存储“H”的内存位置?
No, above you are have object called string
. It would be true for char* testing = "Hello World"
. As you can see it is even declared as pointer and it points to first character in string - H.
不,上面你有一个叫做string
. 对于char* testing = "Hello World"
. 正如你所看到的,它甚至被声明为指针,它指向字符串中的第一个字符 - H。
Next, why is it in the print out statement that
CopyOfName
is not*CopyOfName
? Pointers hold memory addresses? Using*CopyOfName
would print out the contents of the memory location. I tried this in code blocks and if the input text was "Hello World." Using*CopyOfName
in the print out statement would just give an "H"
接下来,为什么在打印输出语句中
CopyOfName
不是*CopyOfName
?指针保存内存地址?使用*CopyOfName
将打印出内存位置的内容。我在代码块中尝试过这个,如果输入文本是“Hello World”。*CopyOfName
在打印输出语句中使用只会给出一个“H”
cout take pointer to first character of the string so CopyOfName
is right. In this case it will print every character starting from H until it finds \0 (null character). Strings like "hello" have actually 6 characters - 'h' 'e' 'l' 'l' 'o' '\0'
When you write *CopyOfName
you are dereferencing this pointer and *CopyOfName
is actually only one character
cout 将指针指向字符串的第一个字符,所以CopyOfName
是正确的。在这种情况下,它将打印从 H 开始的每个字符,直到找到 \0(空字符)。像 "hello" 这样的字符串实际上有 6 个字符 - 'h' 'e' 'l' 'l' 'o' '\0' 当你写的时候,*CopyOfName
你是在取消引用这个指针,*CopyOfName
实际上只有一个字符
回答by Sudhee
You are asking the right questions as a learner.
作为学习者,您提出了正确的问题。
Answers:
答案:
- In C++,
string
is an object, thec_str()
essentially returns a pointer to the first character of the string (C Style) - You are right about strings in C, the variable actually points to first character of the string
- C++ does lot of things based on the type of variable. When you pass a
string
objectcout
prints the string. Also, C++ is smart enough to determine*testing
is illegal
- 在 C++ 中,
string
是一个对象,c_str()
本质上返回一个指向字符串第一个字符的指针(C 风格) - 你是对的 C 中的字符串,变量实际上指向字符串的第一个字符
- C++ 根据变量的类型做了很多事情。当你传递一个
string
对象时cout
打印字符串。此外,C++ 足够聪明,可以确定*testing
是非法的
回答by Brian Stinar
Why is name.c_str() copied into a pointer CopyOfName?
为什么将 name.c_str() 复制到指针 CopyOfName 中?
"name" is an STL string. This is an object, which is different than a c-string. A c-string is a collection of memory, that holds characters, and has a null termination. So, if you're using STL strings and want to turn them into c-strings, you use .c_str() on it to get the c-string.
“名称”是一个 STL 字符串。这是一个对象,不同于 c 字符串。c-string 是一个内存集合,它包含字符,并且有一个空终止符。因此,如果您使用 STL 字符串并希望将它们转换为 c 字符串,则可以在其上使用 .c_str() 来获取 c 字符串。
CopyOfName contains enough memory to hold name, since it was allocated to hold it.
CopyOfName 包含足够的内存来保存 name,因为它被分配来保存它。
cout has a TON of different things you can use with <<. It looks like it can take char *'s (which are c-strings) or STL strings. It does not look like it can take pointers to STL strings.
cout 有很多不同的东西可以和 << 一起使用。看起来它可以使用 char *'s(它们是 c 字符串)或 STL 字符串。看起来它不能使用指向 STL 字符串的指针。
I got kind of confused when you introduced "testing" but I think that you are getting confused between c-strings (which are char *'s) and STL strings, which are objects. Don't feel bad, or give up. This stuff is tricky and takes a while to get.
当您介绍“测试”时,我有点困惑,但我认为您在 c 字符串(它们是 char * 的)和 STL 字符串(它们是对象)之间感到困惑。不要难过,也不要放弃。这个东西很棘手,需要一段时间才能得到。
I would reccomend to try and understand the different between the terms "c-string", "char *", "stl string" and maybe "pointer to stl string" too.
我建议尝试理解术语“c-string”、“char *”、“stl string”和“指向 stl string 的指针”之间的不同。
回答by IllusiveBrian
In C, where C++ standard strings didn't exist, char* was the so-called "string." As you noted, it is an array of characters ending in a NULL character. Just about any standard library function which takes a C-style string will take a pointer to said string, for two reasons:
在 C 中,C++ 标准字符串不存在,char* 就是所谓的“字符串”。正如您所指出的,它是一个以 NULL 字符结尾的字符数组。几乎任何采用 C 样式字符串的标准库函数都将采用指向所述字符串的指针,原因有二:
- It's easier to think of a C-Style string as a whole rather than a bunch of characters, unlike other arrays, so taking the pointer keeps that idea
- It's the easiest way to take an array as a function parameter to just get a pointer to the first element, especially in the case of C-strings where they can just be read up to the NULL character.
- 与其他数组不同,将 C 样式字符串视为一个整体而不是一堆字符更容易,因此采用指针可以保持这种想法
- 这是将数组作为函数参数以获取指向第一个元素的指针的最简单方法,尤其是在 C 字符串的情况下,它们只能被读取到 NULL 字符。
回答by jundl77
I think what you are doing, and others please correct me if I'm wrong, is that you're copying your string into a dynamic char array. So no you are not copying it into a pointer. The reason a pointer is involved there is because dynamic arrays require pointers to allocate their memory correctly if I am right.
我认为你在做什么,如果我错了,请其他人纠正我,是你将字符串复制到动态字符数组中。所以不,你没有将它复制到一个指针中。那里涉及指针的原因是因为如果我是对的,动态数组需要指针来正确分配它们的内存。