尝试理解C++中的*和&符号

5

我有几个问题,这不是作业,我只是想更好地理解。

如果我有

int * b = &k;

  1. 那么k必须是一个整数,而b是指向k在内存中位置的指针,对吗?

  2. b的底层“数据类型”是什么?当我输出它时,它返回诸如0x22fe4c之类的东西,我假设这是十六进制表示内存位置2293324,对吗?

  3. 内存位置'2293324'确切地在哪里?“堆”中?我怎样才能输出例如内存位置012等处的值?

  4. 如果我输出*b,这与直接输出k相同,因为*以某种方式意味着b指向的值。但这似乎与b的声明不同,其声明为int * b = k,因此如果*的含义是“值”,那么这不意味着“声明b为值k”吗?我知道它不是,但我仍然想准确理解这种语言。

  5. 如果我输出&b,这实际上返回指针本身的地址,与k无关,对吗?

  6. 我还可以这样做:int & a = k;,这似乎与int a = k;相同。通常不需要以这种方式使用&吗?


@intboolstring 这不是重复问题,因为那个链接中并未解答我的一些问题。 - Sean Hill
1
好的,你应该把那些没有被提及的放在那里。 - intboolstring
根据那个链接中的评论,一些信息是不准确的。我不想学习可能是错误的东西。 - Sean Hill
1
@SeanHill:“那个链接中没有回答我的一些问题。” 那么你应该提出一个具体的问题,而不是随意列出一堆东西。 - Nicol Bolas
4个回答

4

1- 是的。

2- 没有“底层数据类型”。它是指向int的指针。这是它的本质。对于c/c++来说,它就像“int”或“char”一样是数据类型。

3- 你甚至不应该尝试输出未被你分配的内存的值。那是一个段错误。你可以尝试通过执行b--(这使得“b”指向其实际位置之前的“int”。至少,在你的程序认为它是一个int的位置上)来尝试。

4- *与指针是一个运算符。对于任何数据类型,它都是另一种数据类型。就像=符号一样。当你放置==时,它有一种意义,当你放置=时,它有另一种意义。符号不一定与它的含义相一致。

5- &b是b的地址。它与b指向k有关。例如,如果你执行(**(&b)),你正在使指向b的地址所指向的值。也就是k。当然,如果你没有更改它。

6- int & a = k表示将a的地址设置为k的地址。对于所有目的,a将是k。如果你执行a=1,k将变成1。它们都是指向同一物体的引用。

当然,欢迎纠正。这是我理解的方式。


((&b))和*b是一样的吗?在这种情况下,我该如何解释 - Sean Hill
是的,它们是相同的。** 意味着两个 * 运算符。也就是说,它们需要在后面加上一个“指向指针”的符号才能工作。并且它们返回所指向的值所指向的值。有点混乱,但你可以理解为 *(*(&b)) - Desaroll
它能无限深入吗?*******&b? - Sean Hill
试一下,看看如果你这样做会发生什么。 - Peter
@SeanHill 如果你的意思是 int****** b;,那就取决于编译器了,但请参考 http://c2.com/cgi/wiki?ThreeStarProgrammer。另外,你刚才写的会导致错误,因为 **&b 是 k 的值,所以再加一个 * 将尝试对 k(一个 int)进行解引用。即使它以某种方式成功了,它也会崩溃你的程序,因为你尝试访问可能受保护的内存位置。 - David Szalai
@M.M - 已删除先前的评论。稍后也会删除此评论。 - rcgldr

2

回答您的问题:

  1. 是的,b 是指向 k 的指针:它包含了堆中 k 的地址,但不包含 k 的值本身。

  2. b 的“数据类型”是 int:基本上,这告诉我们 b 指向的地址是一个 int 的地址,但这与 b 本身无关: b 只是一个变量的地址。

  3. 不要尝试手动分配内存给特定的地址:内存是根据对象初始化后的大小分配的,因此内存地址会留出空间,以便在内存中为对象分配相邻的位置,因此手动更改这个地址是一个坏主意。

  4. * 在这种情况下是对 b 进行解引用。正如我所说,b 是一个内存地址,但 *b 是在 b 地址处的内容。在这种情况下,它是 k,因此操纵 *b 就像操纵 k 一样。

  5. 正确,&b 是指针的地址,它与 kb 本身不同。

  6. 使用 int & a = k 创建了对 k 的引用,可以像使用 k 一样使用它。虽然这种情况很简单,但是引用非常适合需要修改函数外部变量值的函数。

例如:

void addThree(int& a) {
   a += 3;
}

int main() {
    int a = 3; //'a' has a value of 3
    addThree(a); //adds three to 'a'
    a += 2; //'a' now has a value of 8

    return 0;
}

在上面的例子中,addThree 接受了一个对 a 的引用,这意味着函数直接操作了 main() 中的 int a 值。
这也可以使用指针来实现:
void addThree(int* a) { //Takes a pointer to an integer
   *a += 3; //Adds 3 to the int found at the pointer's address
}

int main() {
    int a = 3; //'a' has a value of 3
    addThree(&a); //Passes the address of 'a' to the addThree function
    a += 2; //'a' now has a value of 8

    return 0;
}

但是不能使用复制构造函数的参数:

void addThree(int a) {
   a += 3; //A new variable 'a' now a has value of 6.
}

int main() {
    int a = 3; //'a' has a value of 3
    addThree(a); //'a' still has a value of 3: The function won't change it
    a += 2; //a now has a value of 5

    return 0;
}

1

3- 如果k是一个局部变量,它存在于堆栈中。如果k是一个静态变量,它存在于程序的数据段中。对于任何变量,包括b,都适用相同的规则。如果使用new、malloc()、calloc()等函数,则指针将指向堆上的某个位置。如果使用alloca()(或_alloca()),则指针将指向堆栈(alloca()类似于使用局部变量长度数组)。

涉及数组的示例:

int array_of_5_integers[5];
int *ptr_to_int;
int (*ptr_to_array_of_5_integers)[5];

    ptr_to_int = array_of_5_integers;
    ptr_to_array_of_5_integers = &array_of_5_integers;

1
彼此之间有赞美。 * 要么声明指针,要么对其进行解引用。 & 要么声明(左值)引用,要么获取对象或内置类型的地址。 因此,在许多情况下,它们一起工作。 要使对象的指针,您需要其地址。 要将指针用作值,必须对其进行解引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接