为什么在C ++中使用指针?

时间:2013-12-16 19:08:34

标签: c++ pointers dereference

我从游戏开发的角度来学习C ++来自于C#的长期开发与游戏无关,但是我很难掌握指针和解引用的概念/用法。我已经阅读了目前课程教科书中的两章,实际上已经阅读了3次,甚至用Google搜索了与它们相关的不同页面,但它似乎并没有很好地融合在一起。

我想我得到了这个部分:

#include <iostream>

int main()
{
    int myValue   = 5;
    int* myPointer = nullptr;

    std::cout << "My value: " << myValue << std::endl; // Returns value of 5.
    std::cout << "My Pointer: " << &myValue << std::endl; // Returns some hex address.

    myPointer  = &myValue; // This would set it to the address of memory.
    *myPointer = 10; // Essentially sets myValue to 10.

    std::cout << "My value: " << myValue << std::endl; // Returns value of 10.
    std::cout << "My Pointer: " << &myValue << std::endl; // Returns same hex address.
}

我认为我没有得到的是,为什么?为什么不说myValue = 5,那么myValue = 10?为另一个变量或指针添加图层的目的是什么?任何有用的输入,现实生活中使用或链接到一些有助于理解这一点的阅读将非常感激!

11 个答案:

答案 0 :(得分:14)

指针的目的是你在第一次真正需要它们之前不会完全意识到的。您提供的示例是不需要指针但可以使用的情况。这只是为了展示它们的工作原理。指针是记住内存的一种方式,无需复制它所指向的所有内容。阅读本教程,因为它可能会为您提供与课本不同的视图:

http://www.cplusplus.com/doc/tutorial/pointers/

示例:如果您有一组定义如下的游戏实体:

std::vector<Entity*> entities;

你有一个可以“跟踪”特定实体的Camera类:

class Camera
{
private:
   Entity *mTarget;  //Entity to track

public:
   void setTarget(Entity *target) { mTarget = target; }
}

在这种情况下,Camera引用实体的唯一方法是使用指针。

entities.push_back(new Entity());
Camera camera;
camera.setTarget(entities.front());

答案 1 :(得分:1)

例如,某些对象没有名称。它可以是已分配的内存或从函数返回的地址,也可以是迭代器。 在您的简单示例中,当然不需要声明指针。但是在许多情况下,例如当您处理C字符串函数时,您需要使用指针。一个简单的例子

char s[] = "It is pointer?";

if ( char *p = std::strchr( s, '?' ) ) *p = '!';  

答案 2 :(得分:1)

举例说明你有一个指向类的指针。

struct A
{
    int thing;
    double other;
    A() {
        thing = 4;
        other = 7.2;
    }
};

假设我们有一个采用'A'的方法:

void otherMethod()
{
    int num = 12;
    A mine;
    doMethod(num, mine);
    std::cout << "doobie " << mine.thing;
}

void doMethod(int num, A foo)
{
    for(int i = 0; i < num; ++i)
        std::cout << "blargh " << foo.other;
    foo.thing--;
}

调用doMethod时,A对象按值传递。这意味着创建了一个新的A对象(作为副本)。 foo.thing--行根本不会修改mine对象,因为它们是两个独立的对象。

您需要做的是传入指向原始对象的指针。传入指针时,foo.thing--将修改原始对象,而不是将旧对象的副本创建为新对象。

答案 3 :(得分:1)

我们主要在需要动态分配内存时使用指针。例如,要实现一些数据结构,如链接列表,树等等。

答案 4 :(得分:1)

如果按值传递int,则无法更改调用者值。但是如果你将指针传递给int,你可以改变它。这就是C改变参数的方式。 C ++可以通过引用传递值,因此这不太有用。

f(int i)
{
  i= 10;
  std::cout << "f value: " << i << std::endl;
}
f2(int *pi)
{
    *pi = 10;
    std::cout << "f2 value: " << pi << std::endl;
}

main()
{
    i = 5
    f(i)
    std::cout << "main f value: " << i << std::endl;
    f2(&i)
    std::cout << "main f2 value: " << i << std::endl;
}

在main中,第一个打印应该仍然是5.第二个打印应该是10.

答案 5 :(得分:1)

从C#的观点来看,指针与C#中的对象引用完全相同 - 它只是存储器中存储实际数据的地址,通过解引用它可以处理这些数据。

在您的示例中,第一个非指针数据(如int)在堆栈上分配。这意味着它超出了范围,它使用的内存将被释放。另一方面,使用operator new分配的数据将被放置在堆中(就像你在C#中创建任何Object一样),导致这些数据不会被释放,因为你松开了它的指针。因此,使用堆内存中的数据可以执行以下操作之一:

  • 稍后使用垃圾收集器删除数据(在C#中完成)
  • 手动释放内存,然后你不再需要它(用C ++方式 运营商删除)。

为什么需要它? 基本上有三种用例:

  1. 堆栈内存很快但有限,所以如果你需要存储大的 你必须使用堆数据
  2. 复制大数据是 昂贵。然后在堆栈上的函数之间传递简单值 它复制。然后你传递指针唯一复制的东西就是 它的地址(就像在C#中一样)。
  3. C ++中的一些对象可能是 由于其性质,不可复制,例如线程。

答案 6 :(得分:1)

TL; DR :当多个地方需要访问相同的信息时,指针很有用

在你的例子中,他们没有做太多,就像你说它只是展示如何使用它们。指针的一个用途是连接像树一样的节点。如果你有一个像这样的节点结构......

struct myNode
{
    myNode *next;
    int someData;
};

您可以创建多个节点并将每个节点链接到上一个myNode的next成员。你可以在没有指针的情况下做到这一点,但指针的巧妙之处在于它们都链接在一起,当你传递myNode列表时,你只需要传递第一个(根)节点。

关于指针的一个很酷的事情是,如果两个指针引用相同的内存地址,那么引用该内存地址的所有内容都会识别对内存地址的任何更改。所以,如果你这样做了:

int a = 5; // set a to 5
int *b = &a; // tell b to point to a
int *c = b; // tell c to point to b (which points to a)

*b = 3; // set the value at 'a' to 3
cout << c << endl; // this would print '3' because c points to the same place as b

这有一些实际用途。假设您有一个链接在一起的节点列表。每个节点中的数据定义了某些需要完成的任务,这些任务将由某个函数处理。当新任务添加到列表中时,它们会附加到末尾。由于该函数具有指向节点列表的指针,因此在添加任务时也会接收这些任务。另一方面,该函数还可以在完成任务时删除任务,然后将其反射回查看节点列表的任何其他指针。

指针也用于动态内存。假设您希望用户输入一系列数字,并告诉您他们想要使用多少个数字。您可以定义一个包含100个元素的数组,以允许最多100个数字,或者您可以使用动态内存。

int count = 0;

cout << "How many numbers do you want?\n> ";
cin >> count;

// Create a dynamic array with size 'count'
int *myArray = new int[count];

for(int i = 0; i < count; i++)
{
    // Ask for numbers here
}

// Make sure to delete it afterwars
delete[] myArray;

答案 7 :(得分:1)

  

为另一个变量或指针添加图层的目的是什么?

没有一个。这是一个刻意设计的例子,向您展示该机制的运作方式。

实际上,对象通常是存储在代码库的远端部分,或者是从代码库的远端部分访问,或者是动态分配的,否则就不能进行范围限制。在任何这些场景中,您可能会发现自己需要间接引用对象,这可以使用指针和/或引用来实现(根据您的需要)。

答案 8 :(得分:1)

指针(或引用)对于在C ++中使用动态多态性至关重要。它们是您使用类层次结构的方式。

Shape * myShape = new Circle();
myShape->Draw(); // this draws a circle
// in fact there is likely no implementation for Shape::Draw

尝试通过值(而不是指针或引用)将派生类用于基类通常会导致切片并丢失对象的派生数据部分。

答案 9 :(得分:0)

当您将指针传递给函数时,它会更有意义,请参阅此示例:

void setNumber(int *number, int value) {
    *number = value;
}

int aNumber = 5;
setNumber(&aNumber, 10);
// aNumber is now 10

我们在这里做的是设置*number的值,如果不使用指针就不可能这样做。

如果你这样定义它:

void setNumber(int number, int value) {
    number = value;
}

int aNumber = 5;
setNumber(aNumber, 10);
// aNumber is still 5 since you're only copying its value

它还提供了更好的性能,当您将对较大对象(例如类)的引用传递给函数时,您不会浪费太多内存,而不是传递整个对象。

答案 10 :(得分:0)

在编程中使用指针是一个很好的概念。并且为了动态分配内存,必须使用指针来存储我们保留的内存的第一个位置的地址,同样是释放内存的情况,我们需要指针。这是正确的,因为有人在上面的回答中说,在你需要它之​​前,你无法理解poinet的使用。一个例子是你可以使用指针和动态memoru分配来创建一个可变大小的数组。有一点很重要的是,使用指针我们可以改变位置的实际值,因为我们间接访问该位置。更重要的是,当我们需要通过引用传递我们的值时,有时引用不起作用所以我们需要指针。

你编写的代码是使用dereference运算符。正如我所说的那样,我们通过使用指针间接访问内存的存储,因此它改变了像引用对象一样的位置的实际值,这就是打印10的原因。