关于指针和引用语法

时间:2009-12-22 19:06:02

标签: c++ c

令人尴尬虽然可能我知道我不是唯一有这个问题的人。

我多年来一直在使用C / C ++。我从来没有遇到过关于地址,指针,指针指针和引用的概念的问题。

但是,我确实经常发现自己在C语法中喋喋不休地表达它们。不是像声明或解除引用这样的基础知识,而是更常见的事情,比如获取指向指针的地址,或指向引用的指针等等。基本上任何超出规范的间接级别或两个级别。通常情况下,我会遇到各种运算符的半逻辑组合,直到我找到正确的运算符。

显然,沿着这条线的某个地方,我错过了一两条规则,简化并使其全部落实到位。所以我想我的问题是:你是否知道一个网站或参考文献清楚而深入地涵盖了这个问题?

5 个答案:

答案 0 :(得分:7)

我不知道任何网站,但我会尝试用非常简单的术语来解释它。您只需要理解三件事:

  1. variable将包含变量的内容。这意味着如果变量是指针,它将包含它指向的内存地址。
  2. *variable(仅对指针有效)将包含变量指向的内容。如果它指向的变量是另一个指针ptr2,那么*variableptr2将是同一个东西; **variable*ptr2也是一样的。
  3. &variable将包含变量的内存地址。如果它是一个指针,它将是指针本身的内存地址,而 NOT 指向的变量或指向的变量的内存地址。
  4. 现在,让我们看一个复杂的例子:

        void **list = (void **)*(void **)info.List;
    

    list是指向指针的指针。现在让我们从结尾开始检查作业的正确部分:(void **)info.List。这也是指向指针的指针。

    然后,您会看到*:*(void **)info.List。这意味着这是指针info.List指向的值。

    现在,整个事情:(void **)*(void **)info.List。这是指针info.List指向要转换为(void **)的值。

答案 1 :(得分:5)

我发现right-left-right rule很有用。它告诉您如何读取声明,以便按顺序获取所有指针和引用。例如:

int *foo();

使用右 - 右 - 右规则,您可以将其翻译为英语,因为“foo是一个返回指向整数的指针的函数”。

int *(*foo)();  // "foo is a pointer to a function returning a pointer to an int"
int (*foo[])();  // "foo is an array of pointers to functions returning ints"

右 - 右 - 右规则的大多数解释都是针对C而不是C ++编写的,因此它们往往会遗漏引用。在这种情况下,它们就像指针一样工作。

int &foo;  // "foo is a reference to an integer"

答案 2 :(得分:3)

当事情变得混乱时,Typedef可能是你的朋友。这是一个例子:

typedef const char * literal_string_pointer;
typedef literal_string_pointer * pointer_to_literal_string_pointer;
void GetPointerToString(pointer_to_literal_string_pointer out_param)
{
    *out_param = "hi there";
}

答案 3 :(得分:1)

我不确定你到底在找什么,但我发现记住operator precedence and associativity rules会很有帮助。也就是说,如果你感到困惑,你也可以投入更多的麻烦去消除歧义,即使这只是为了你的利益而不是编译器的。

编辑:我想我现在可能会更好地理解你的问题了。我喜欢把一堆指针想象成堆栈,底部的值。解除引用操作符(*)会弹出堆栈,您可以在最后找到值本身。引用运算符(&)允许您将另一级别的间接引入堆栈。请注意,移动另一个步骤总是合法的,但尝试取消引用该值类似于弹出空堆栈。

答案 4 :(得分:1)

您需要知道的是获取对象的地址会返回指向该对象的指针,并且取消引用对象会获取指针并将其转换为指向它的对象。

T x;
A a = &x; // A is T*
B b = *a; // B is T
C c = &a; // C is T**
D d = *c; // D is T*

基本上,&运算符需要T并为您提供T*,而*运算符需要T*并为您提供T这同样适用于更高级别的抽象,例如  在&上使用T*将为您提供T**

另一种思考方式是&运算符向类型添加*,而*只需要一个,这会导致&&*&**i == i之类的内容。