【问题标题】:Understanding C++ pointers (when they point to a pointer)理解 C++ 指针(当它们指向指针时)
【发布时间】:2011-02-18 08:40:19
【问题描述】:

我认为我非常了解引用和指针。以下是我(认为我)知道的:

int i = 5; //i is a primitive type, the value is 5, i do not know the address.
int *ptr;  //a pointer to an int. i have no way if knowing the value yet.
ptr = &i;  //now i have an address for the value of i (called ptr)
*ptr = 10; //Go to the value in ptr, use it to find a location and store 10 there

请随时评论或更正这些陈述。

现在我正在尝试跳转到指针数组。以下是我不知道的:

char **char_ptrs = new char *[50];
Node **node_ptrs = new Node *[50];

我的理解是我有 2 个指针数组,一组指向字符的指针和一组指向节点的指针。因此,如果我想设置这些值,我会这样做:

char_ptrs[0] = new char[20];
node_ptrs[0] = new Node;

现在我有一个指针,在我的数组的 0 位置,在每个相应的数组中。同样,如果我感到困惑,请随时在此处发表评论。

那么,** 运算符是做什么的?同样,将单个 * 放在实例化旁边做什么 (*[50])? (具体叫什么,实例化?)

【问题讨论】:

  • *ptr = 10 不是“获取存储在 ptr 中的值并将其更改为 10”。它应该是“转到 ptr 中的值,用它来找出另一个位置,并将 10 存储在那里”。这就是取消引用指针的意义。
  • @Uri 很好。编辑和更新。
  • 我应该注意到,这本书对于学习 C 中的指针非常有帮助:Richard Reese 的理解和使用 C 指针。我会向任何学习 C 或 C++ 的人推荐这个,因为其中的概念非常宝贵。

标签: c++ memory pointers


【解决方案1】:

几个cmets:

*ptr = 10; // Doesn't need to "go get" the value. Just overwrites it.

还有:

char **char_ptrs = new char *[50];
Node **node_ptrs = new Node *[50];

更容易认为你有两个数组。但是,从技术上讲(就编译器而言),您拥有的是两个 指针。一个是指向a的指针(pointer to a char),另一个是指向a的指针(pointer to a node)。

这很容易从变量的声明中看出,顺便说一句,从右到左最容易阅读:

char **char_ptrs

从右到左阅读:char_ptrs 是指向char 的指针

在指针旁边放一个 * 被恰当地称为取消引用该指针。由于数组在技术上不存在,因此数组上的运算符 [] 也是一种取消引用操作:arr[i] 是*(arr + i) 的另一种写法。要正确理解这一点,您需要熟悉pointer arithmetic。

多个连续的 *s:每个 *s 都会取消引用它所操作的表达式的结果。所以写的时候:

char c = **char_ptrs;

会发生什么:

char_ptrs 是一个指向 char 的指针。取消引用一次(对于最右边的 *)可以获得它的值,它是一个指向 char 的指针。取消引用该值(对于最左边的 *)依次为您提供自己的值,即一个字符。最后,c 包含存储在内存中 char_ptrs 指向的指针(换句话说,数组中的第一个指针)指向的位置的 char 的值。

相反,如果您写**char_ptrs = 'a';,那么您将更改该内存位置中的值。

【讨论】:

  • 我认为 Jon 在这里获得了认可。感谢 Ignacio,因为您的回答直截了当。
  • 谢谢。你的问题非常适合教育目的,所以我也 +1。
  • 我认为我还应该推广我提到的 RTL 阅读技巧,因为它具有广泛的用途:const char* 和 char* const 之间有什么区别? :-)
【解决方案2】:

** 只是* 的两次,所以是指向指针的指针。

当放在一个类型旁边时,* 绑定左侧,而不是右侧。说new char *[50] 实际上是new char* [50] 并实例化一个包含50 个char* 的数组。

【讨论】:

    【解决方案3】:

    如果您发现 * 符号难以阅读,请使用 typedef 来帮助您的代码易于阅读。

    typedef char*      CharPtr;
    typedef CharPtr*   CharPtrPtr;
    // Alternative to the line above
    // typedef char**     CharPtrPtr;
    
    // When you call new. You get a ptr to the type you are newing.
    // new int returns an intPtr. new char returns a charPtr
    CharPtrPtr char_ptrs = new CharPtr[50];
    
    // So new CharPtr returns a CharPtrPtr
    // In this case we return a pointer to contigious
    // chunk of memory large enough to hold 50 CharPtr objects.
    

    【讨论】:

    • 不,不要。隐藏某物是指针的事实是非常糟糕的风格,恕我直言。
    • 我同意尼尔的一般情况。但是 Ptr 很好,因为你没有隐藏它(恕我直言)。但由于这是一个学习练习,只是为了习惯使用指针,它是有效的。当你像我一样变老和懒惰时,* 就像尼尔一样容易阅读和更快地输入:-)
    【解决方案4】:

    您的第一个代码块中的陈述都是正确的。

    char **char_ptrs = new char *[50];
    

    ...表示您有一个包含 50 个char *s 的数组。

    你对

    的评价
    char_ptrs[0] = new char[20];
    node_ptrs[0] = new Node;
    

    也是正确的。

    ** 仅表示“指向指针的指针”。它不是运算符。

    当你写作时

    new char *[50];
    

    ...您说的是“为 50 char *s 分配存储空间”。

    【讨论】:

    • 有时语法令人困惑。我更喜欢:“char** char_ptrs = new char* [50];”明确地说,但这也有其缺点。
    【解决方案5】:

    澄清第一部分:

    int i = 5; // i is a primitive type, the value is 5, the address is retrieved via &i.
    int *ptr;  // an unassigned pointer to an int
    ptr = &i;  // ptr now point to the address of variable i
    *ptr = 10; // access (dereference) the value through ptr and change it to 10 (same as i=10)
    

    没有 ** 运算符,只有 * 运算符。就像其他人所说的那样,** 声明了一个指向指针的指针。因为您正在声明指针数组,并且指针是使用 * 运算符声明的,所以在使用 new 为它们分配内存时需要这样声明它们。因此,您有:

    char **char_ptrs = new char *[50]; // allocates memory for 50 contiguous char* (pointers)
    Node **node_ptrs = new Node *[50]; // allocates memory for 50 contiguous Node* (pointers)
    

    指向指针的指针不一定要声明数组。您也可以让另一个指针指向一个常规指针,如下所示:

    char i = 'p';
    char *myptr = &i;
    char **mysecondptr = &myptr;
    

    【讨论】:

      猜你喜欢
      • 2021-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-14
      • 2011-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多