C++ 为什么要使用指针?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/162941/
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
Why use pointers?
提问by
I know this is a really basic question, but I've just started with some basic C++ programming after coding a few projects with high-level languages.
我知道这是一个非常基本的问题,但是在使用高级语言编写了一些项目之后,我才刚刚开始进行一些基本的 C++ 编程。
Basically I have three questions:
基本上我有三个问题:
- Why use pointers over normal variables?
- When and where should I use pointers?
- How do you use pointers with arrays?
- 为什么在普通变量上使用指针?
- 我应该何时何地使用指针?
- 如何在数组中使用指针?
回答by Tooony
- Why use pointers over normal variables?
- 为什么在普通变量上使用指针?
Short answer is: Don't. ;-) Pointers are to be used where you can't use anything else. It is either because the lack of appropriate functionality, missing data types or for pure perfomance. More below...
简短的回答是:不要。;-) 指针将用于您不能使用其他任何东西的地方。要么是因为缺乏适当的功能、缺少数据类型,要么是纯粹的性能。下面更多...
- When and where should I use pointers?
- 我应该何时何地使用指针?
Short answer here is: Where you cannot use anything else. In C you don't have any support for complex datatypes such as a string. There are also no way of passing a variable "by reference" to a function. That's where you have to use pointers. Also you can have them to point at virtually anything, linked lists, members of structs and so on. But let's not go into that here.
这里的简短回答是:您不能使用其他任何东西的地方。在 C 中,您不支持复杂的数据类型,例如字符串。也没有办法“通过引用”将变量传递给函数。这就是你必须使用指针的地方。你也可以让它们指向几乎任何东西,链表,结构成员等等。但我们不要在这里讨论。
- How do you use pointers with arrays?
- 如何在数组中使用指针?
With little effort and much confusion. ;-) If we talk about simple data types such as int and char there is little difference between an array and a pointer.
These declarations are very similar (but not the same - e.g., sizeof
will return different values):
用很少的努力和很多混乱。;-) 如果我们谈论诸如 int 和 char 之类的简单数据类型,则数组和指针之间几乎没有区别。这些声明非常相似(但不一样——例如,sizeof
将返回不同的值):
char* a = "Hello";
char a[] = "Hello";
You can reach any element in the array like this
您可以像这样到达数组中的任何元素
printf("Second char is: %c", a[1]);
Index 1 since the array starts with element 0. :-)
索引 1,因为数组从元素 0 开始。:-)
Or you could equally do this
或者你同样可以这样做
printf("Second char is: %c", *(a+1));
The pointer operator (the *) is needed since we are telling printf that we want to print a character. Without the *, the character representation of the memory address itself would be printed. Now we are using the character itself instead. If we had used %s instead of %c, we would have asked printf to print the content of the memory address pointed to by 'a' plus one (in this example above), and we wouldn't have had to put the * in front:
指针运算符(*)是必需的,因为我们告诉 printf 我们要打印一个字符。如果没有 *,将打印内存地址本身的字符表示。现在我们改为使用角色本身。如果我们使用 %s 而不是 %c,我们会要求 printf 打印 'a' 指向的内存地址的内容加一(在上面的这个例子中),我们就不必把 *在前:
printf("Second char is: %s", (a+1)); /* WRONG */
But this would not have just printed the second character, but instead all characters in the next memory addresses, until a null character (\0) were found. And this is where things start to get dangerous. What if you accidentally try and print a variable of the type integer instead of a char pointer with the %s formatter?
但这不会只打印第二个字符,而是打印下一个内存地址中的所有字符,直到找到空字符 (\0)。这就是事情开始变得危险的地方。如果您不小心尝试使用 %s 格式化程序打印整数类型的变量而不是字符指针怎么办?
char* a = "Hello";
int b = 120;
printf("Second char is: %s", b);
This would print whatever is found on memory address 120 and go on printing until a null character was found. It is wrong and illegal to perform this printf statement, but it would probably work anyway, since a pointer actually is of the type int in many environments. Imagine the problems you might cause if you were to use sprintf() instead and assign this way too long "char array" to another variable, that only got a certain limited space allocated. You would most likely end up writing over something else in the memory and cause your program to crash (if you are lucky).
这将打印在内存地址 120 上找到的任何内容,并继续打印直到找到一个空字符。执行这个 printf 语句是错误和非法的,但无论如何它可能会起作用,因为在许多环境中指针实际上是 int 类型。想象一下,如果您改用 sprintf() 并以这种方式将太长的“char 数组”分配给另一个变量,而该变量只分配了一定的有限空间,则可能会导致问题。您很可能最终会覆盖内存中的其他内容并导致您的程序崩溃(如果幸运的话)。
Oh, and if you don't assign a string value to the char array / pointer when you declare it, you MUST allocate sufficient amount of memory to it before giving it a value. Using malloc, calloc or similar. This since you only declared one element in your array / one single memory address to point at. So here's a few examples:
哦,如果您在声明 char 数组/指针时没有为其分配字符串值,则必须在为其分配值之前为其分配足够的内存量。使用 malloc、calloc 或类似的。这是因为您只声明了数组中的一个元素/一个指向的内存地址。所以这里有几个例子:
char* x;
/* Allocate 6 bytes of memory for me and point x to the first of them. */
x = (char*) malloc(6);
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = 'public void doSomething()
{
int i = 10;
doSomethingElse(i); // passes i by references since doSomethingElse() receives it
// by reference, but the syntax makes it appear as if i is passed
// by value
}
public void doSomethingElse(int& i) // receives i as a reference
{
cout << i << endl;
}
';
printf("String \"%s\" at address: %d\n", x, x);
/* Delete the allocation (reservation) of the memory. */
/* The char pointer x is still pointing to this address in memory though! */
free(x);
/* Same as malloc but here the allocated space is filled with null characters!*/
x = (char *) calloc(6, sizeof(x));
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = 'public void doSomething()
{
int i = 10;
doSomethingElse(&i);
}
public void doSomethingElse(int* i)
{
cout << *i << endl;
}
';
printf("String \"%s\" at address: %d\n", x, x);
/* And delete the allocation again... */
free(x);
/* We can set the size at declaration time as well */
char xx[6];
xx[0] = 'H';
xx[1] = 'e';
xx[2] = 'l';
xx[3] = 'l';
xx[4] = 'o';
xx[5] = 'char hello[] = "hello";
char *p = hello;
while (*p)
{
*p += 1; // increase the character by one
p += 1; // move to the next spot
}
printf(hello);
';
printf("String \"%s\" at address: %d\n", xx, xx);
Do note that you can still use the variable x after you have performed a free() of the allocated memory, but you do not know what is in there. Also do notice that the two printf() might give you different addresses, since there is no guarantee that the second allocation of memory is performed in the same space as the first one.
请注意,在对分配的内存执行 free() 后,您仍然可以使用变量 x,但您不知道那里有什么。还要注意,两个 printf() 可能会给你不同的地址,因为不能保证第二次内存分配与第一个内存分配在相同的空间中执行。
回答by trshiv
One reason to use pointers is so that a variable or an object can be modified in a called function.
使用指针的一个原因是可以在被调用的函数中修改变量或对象。
In C++ it is a better practice to use references than pointers. Though references are essentially pointers, C++ to some extent hides the fact and makes it seem as if you are passing by value. This makes it easy to change the way the calling function receives the value without having to modify the semantics of passing it.
在 C++ 中,使用引用比使用指针更好。尽管引用本质上是指针,但 C++ 在某种程度上隐藏了这一事实,并使其看起来好像是按值传递。这使得更改调用函数接收值的方式变得容易,而无需修改传递它的语义。
Consider the following examples:
考虑以下示例:
Using references:
使用参考:
ifmmp
Using pointers:
使用指针:
MyType a; //let's ignore what MyType actually is right now.
a = modify(a);
回答by Kyle Cronin
- Pointers allow you to refer to the same space in memory from multiple locations. This means that you can update memory in one location and the change can be seen from another location in your program. You will also save space by being able to share components in your data structures.
- You should use pointers any place where you need to obtain and pass around the address to a specific spot in memory. You can also use pointers to navigate arrays:
- An array is a block of contiguous memory that has been allocated with a specific type. The name of the array contains the value of the starting spot of the array. When you add 1, that takes you to the second spot. This allows you to write loops that increment a pointer that slides down the array without having an explicit counter for use in accessing the array.
- 指针允许您从多个位置引用内存中的相同空间。这意味着您可以在一个位置更新内存,并且可以从程序中的另一个位置看到更改。您还可以通过共享数据结构中的组件来节省空间。
- 您应该在任何需要获取地址的地方使用指针,并将地址传递到内存中的特定位置。您还可以使用指针来导航数组:
- 数组是一块已分配有特定类型的连续内存。数组的名称包含数组起始点的值。当您加 1 时,这会将您带到第二个位置。这允许您编写循环来增加一个向下滑动数组的指针,而无需在访问数组时使用显式计数器。
Here is an example in C:
下面是一个 C 语言的例子:
MyType *p = NULL; //empty pointer
if(p)
{
//we never reach here, because the pointer points to nothing
}
//now, let's allocate some memory
p = new MyType[50000];
if(p) //if the memory was allocated, this test will pass
{
//we can do something with our allocated array
for(size_t i=0; i!=50000; i++)
{
MyType &v = *(p+i); //get a reference to the ith object
//do something with it
//...
}
delete[] p; //we're done. de-allocate the memory
}
prints
印刷
unsigned char *pVideoMemory = (unsigned char *)0xA0000000;
because it takes the value for each character and increments it by one.
因为它获取每个字符的值并将其加一。
回答by Bill the Lizard
Pointers are one way of getting an indirect reference to another variable. Instead of holding the valueof a variable, they tell you its address. This is particularly useful when dealing with arrays, since using a pointer to the first element in an array (its address) you can quickly find the next element by incrementing the pointer (to the next address location).
指针是获得对另一个变量的间接引用的一种方式。它们不是保存变量的值,而是告诉您它的地址。这在处理数组时特别有用,因为使用指向数组中第一个元素(其地址)的指针,您可以通过增加指针(指向下一个地址位置)来快速找到下一个元素。
The best explanation of pointers and pointer arithmetic that I've read is in K & R's The C Programming Language. A good book for beginning learning C++ is C++ Primer.
我读过的关于指针和指针算术的最佳解释是在 K & R 的The C Programming Language 中。一本开始学习 C++ 的好书是C++ Primer。
回答by Carl
Let me try and answer this too.
让我也试着回答这个问题。
Pointers are similar to references. In other words, they're not copies, but rather a way to refer to the original value.
指针类似于引用。换句话说,它们不是副本,而是引用原始值的一种方式。
Before anything else, one place where you will typically have to use pointersa lot is when you're dealing with embedded hardware. Maybe you need to toggle the state of a digital IO pin. Maybe you're processing an interrupt and need to store a value at a specific location. You get the picture. However, if you're not dealing with hardware directly and are just wondering about which types to use, read on.
首先,您通常必须大量使用指针的地方是处理嵌入式硬件时。也许您需要切换数字 IO 引脚的状态。也许您正在处理一个中断并需要在特定位置存储一个值。你得到了图片。但是,如果您不直接处理硬件并且只是想知道要使用哪种类型,请继续阅读。
Why use pointers as opposed to normal variables? The answer becomes clearer when you're dealing with complex types, like classes, structures and arrays. If you were to use a normal variable, you might end up making a copy (compilers are smart enough to prevent this in some situations and C++11 helps too, but we'll stay away from that discussion for now).
为什么使用指针而不是普通变量?当您处理复杂类型(如类、结构和数组)时,答案会变得更加清晰。如果您要使用普通变量,您最终可能会创建一个副本(编译器足够聪明,可以在某些情况下防止这种情况发生,C++11 也有帮助,但我们现在将远离该讨论)。
Now what happens if you want to modify the original value? You could use something like this:
现在如果你想修改原始值会发生什么?你可以使用这样的东西:
##代码##That will work just fine and if you don't know exactly why you're using pointers, you shouldn't use them. Beware of the "they're probably faster" reason. Run your own tests and if they actually are faster, then use them.
这将工作得很好,如果您不确切知道为什么要使用指针,则不应使用它们。当心“他们可能更快”的原因。运行您自己的测试,如果它们确实更快,则使用它们。
However, let's say you're solving a problem where you need to allocate memory. When you allocate memory, you need to deallocate it. The memory allocation may or may not be successful. This is where pointerscome in useful - they allow you to test for the existence of the objectyou've allocated and they allow you to access the object the memory was allocated for by de-referencing the pointer.
但是,假设您正在解决需要分配内存的问题。当你分配内存时,你需要释放它。内存分配可能成功也可能不成功。这就是指针有用的地方——它们允许您测试您分配的对象是否存在,并且它们允许您通过取消引用指针来访问分配内存的对象。
##代码##This is the key to why you would use pointers - references assume the element you're referencing exists already. A pointer does not.
这就是为什么要使用指针的关键——引用假定您引用的元素已经存在。指针没有。
The other reason why you would use pointers (or at least end up having to deal with them) is because they're a data type that existed before references. Therefore, if you end up using libraries to do the things that you know they're better at, you will find that a lot of these libraries use pointers all over the place, simply because of how long they've been around (a lot of them were written before C++).
使用指针(或至少最终不得不处理它们)的另一个原因是因为它们是在引用之前存在的数据类型。因此,如果你最终使用库来做你知道它们更擅长的事情,你会发现很多这些库到处都使用指针,仅仅是因为它们已经存在了多长时间(很多其中一些是在 C++ 之前编写的)。
If you didn't use any libraries, you could design your code in such a way that you could stay away from pointers, but given that pointers are one of the basic types of the language, the faster you get comfortable using them, the more portable your C++ skills would be.
如果你不使用任何库,你可以以一种远离指针的方式设计你的代码,但鉴于指针是语言的基本类型之一,你越快使用它们就越舒服您的 C++ 技能将是可移植的。
From a maintainability point of view, I should also mention that when you do use pointers, you either have to test for their validity and handle the case when they're not valid, or, just assume they are valid and accept the fact that your program will crash or worse WHEN that assumption is broken. Put another way, your choice with pointers is to either introduce code complexity or more maintenance effort when something breaksand you're trying to track down a bug that belongs to a whole class of errors that pointers introduce, like memory corruption.
从可维护性的角度来看,我还应该提到,当您确实使用指针时,您要么必须测试它们的有效性并在它们无效时处理这种情况,要么假设它们有效并接受以下事实:当这个假设被打破时,程序将崩溃或更糟。换句话说,您对指针的选择是在出现问题时引入代码复杂性或更多的维护工作,并且您试图追踪属于指针引入的整类错误的错误,例如内存损坏。
So if you control all of your code, stay away from pointers and instead use references, keeping them const when you can. This will force you to think about the life times of your objects and will end up keeping your code easier to understand.
因此,如果您控制所有代码,请远离指针并使用引用,尽可能保持它们的常量。这将迫使您考虑对象的生命周期,并最终使您的代码更易于理解。
Just remember this difference: A reference is essentially a valid pointer. A pointer is not always valid.
请记住这个区别:引用本质上是一个有效的指针。指针并不总是有效的。
So am I saying that its impossible to create an invalid reference? No. Its totally possible, because C++ lets you do almost anything. It's just harder to do unintentionally and you will be amazed at how many bugs are unintentional :)
那么我是说不可能创建无效的引用吗?不。它完全有可能,因为 C++ 几乎可以让您做任何事情。无意中更难做到,你会惊讶于有多少错误是无意的:)
回答by Dan Lenski
Here's a slightly different, but insightful take on why many features of C make sense: http://steve.yegge.googlepages.com/tour-de-babel#C
对于 C 的许多特性为何有意义,这里有一个稍微不同但有见地的看法:http: //steve.yegge.googlepages.com/tour-de-babel#C
Basically, the standard CPU architecture is a Von Neumann architecture, and it's tremendously useful to be able to refer to the location of a data item in memory, and do arithmetic with it, on such a machine. If you know any variant of assembly language, you will quickly see how crucial this is at the low level.
基本上,标准的 CPU 架构是冯诺依曼架构,能够在这样的机器上引用数据项在内存中的位置并对其进行算术运算是非常有用的。如果您了解汇编语言的任何变体,您将很快看到这在低级别是多么重要。
C++ makes pointers a bit confusing, since it sometimes manages them for you and hides their effect in the form of "references." If you use straight C, the need for pointers is much more obvious: there's no other way to do call-by-reference, it's the best way to store a string, it's the best way to iterate through an array, etc.
C++ 使指针有点混乱,因为它有时会为您管理它们并以“引用”的形式隐藏它们的效果。如果您使用直接的 C,则对指针的需求更加明显:没有其他方法可以进行按引用调用,这是存储字符串的最佳方式,它是遍历数组的最佳方式,等等。
回答by MrZebra
One use of pointers (I won't mention things already covered in other people's posts) is to access memory that you haven't allocated. This isn't useful much for PC programming, but it's used in embedded programming to access memory mapped hardware devices.
指针的一种用途(我不会提及其他人的帖子中已经涵盖的内容)是访问您尚未分配的内存。这对 PC 编程没有多大用处,但它用于嵌入式编程以访问内存映射的硬件设备。
Back in the old days of DOS, you used to be able to access the video card's video memory directly by declaring a pointer to:
回到过去的 DOS 时代,您曾经可以通过声明一个指向以下内容的指针来直接访问视频卡的视频内存:
##代码##Many embedded devices still use this technique.
许多嵌入式设备仍然使用这种技术。
回答by warren
In large part, pointers are arrays (in C/C++) - they are addresses in memory, and can be accessed like an array if desired (in "normal" cases).
在很大程度上,指针是数组(在 C/C++ 中)——它们是内存中的地址,如果需要(在“正常”情况下)可以像数组一样访问。
Since they're the address of an item, they're small: they take up only the space of an address. Since they're small, sending them to a function is cheap. And then they allow that function to work on the actual item rather than a copy.
因为它们是一个项目的地址,所以它们很小:它们只占用一个地址的空间。由于它们很小,将它们发送到函数很便宜。然后他们允许该功能处理实际项目而不是副本。
If you want to do dynamic storage allocation (such as for a linked-list), you must use pointers, because they're the only way to grab memory from the heap.
如果要进行动态存储分配(例如对于链表),则必须使用指针,因为它们是从堆中获取内存的唯一方法。
回答by Ash
Pointers are important in many data structures whose design requires the ability to link or chain one "node" to another efficiently. You would not "choose" a pointer over say a normal data type like float, they simply have different purposes.
指针在许多数据结构中很重要,其设计要求能够有效地将一个“节点”链接或链接到另一个“节点”。你不会“选择”一个指针而不是像 float 这样的普通数据类型,它们只是有不同的目的。
Pointers are useful where you require high performance and/or compact memory footprint.
当您需要高性能和/或紧凑的内存占用时,指针非常有用。
The address of the first element in your array can be assigned to a pointer. This then allows you to access the underlying allocated bytes directly. The whole point of an array is to avoid you needing to do this though.
数组中第一个元素的地址可以分配给一个指针。这允许您直接访问底层分配的字节。数组的全部意义在于避免您需要这样做。
回答by Jason
One way to use pointers over variables is to eliminate duplicate memory required. For example, if you have some large complex object, you can use a pointer to point to that variable for each reference you make. With a variable, you need to duplicate the memory for each copy.
在变量上使用指针的一种方法是消除所需的重复内存。例如,如果您有一些大型复杂对象,您可以使用一个指针来指向您所做的每个引用的该变量。对于变量,您需要为每个副本复制内存。