你能帮我理解一下指针吗?

我知道以前曾经问过这个问题,但其他一些问题没有触及的原因为什么

请允许我解释一下。 我刚刚完成了一个输出整数和指针的教程,向您展示如何做到这一点。

int anInteger = 50; int *anIntPointer = &anInteger; 

因此,要设置指针,我会正常分配变量值,然后将该变量赋值给指针。 我理解这一点,但正如我已经说过的,这就是原因

如果我想返回值50我可以只使用NSLog anInteger那么为什么我需要一个指针。 为什么我需要NSLog *anIntPointer如果我可以只使用NSLog anInteger完全相同的东西?

好吧,我知道这是非常微不足道的,并且可能有完美的情况使用指针,但到目前为止,没有我读过或看过的教程会给我一个完美的情况。 他们都处理如何处理

请帮我找到原因

指针有很多用途。 一个显而易见的是你想要调用一个函数并让它修改你的一个变量:

 void f(int *i) { *i = 42; } int g() { int i; f(&i); return i; } 

另一种方法是返回一个没有大量复制的大型结构:

 struct big_struct *f() { big_struct *bs = malloc(sizeof(big_struct)); // Populate the big_struct; return bs; } 

另一个是管理在编译时你不知道的大小的数组:

 struct item *fetch_items(int n) { item *i = malloc(n*sizeof(item)); load_items(i, n); return i; } 

还有一种是递归数据类型,例如链表:

 struct node { int value; struct node *next; }; 

这只是一个抽样。 指针就像钉木匠一样。 它们几乎可以解决任何非平凡的编程问题。

我们使用指针(在C和C派生语言中)的主要原因是:

  • 模仿传递引用语义
  • 跟踪动态分配的内存
  • 创建自引用和动态数据结构
  • 因为有时语言迫使你

模仿传递引用语义:在C中,所有函数参数都按值传递。 forms参数和实际参数是内存中的不同对象,因此写入形参数对实际参数没有影响。 例如,给定代码

 void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(void) { int x = 2, y = 3; printf("before swap: x = %d, y = %d\n", x, y); swap(x, y); printf("after swap: x = %d, y = %d\n", x, y); return 0; } 

ax是物理上不同的对象; 写入a不会影响x ,反之亦然。 因此,上述程序中的前后输出将是相同的。 为了使swap能够修改xy的内容,我们必须将指针传递给那些对象并取消引用函数中的指针:

 void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } int main(void) { int x = 2, y = 3; printf("before swap: x = %d, y = %d\n", x, y); swap(&x, &y); printf("after swap: x = %d, y = %d\n", x, y); return 0; } 

ax仍然是内存中的不同对象,但表达式 *a指的是与表达式x相同的内存; 因此,写入*a更新x的内容,反之亦然。 现在swap函数将交换xy的内容。

请注意,C ++引入了引用的概念,它类似于指针,但不需要显式的解引用:

 void swap(int &a, int &b) { int tmp = a; a = b; b = tmp; } int main(void) { int x = 2, y = 3; std::cout << "before swap: x = " << x << ", y = " << y << std::endl; swap(x, y); std::cout << "after swap: x = " << x << ", y = " << y << std::endl; return 0; } 

在这种情况下,表达式ax确实指的是相同的内存位置; 写一个确实影响另一个。 不过,这是一个C ++主义。

我对Obj-C不太熟悉,知道他们是否有类似的机制。

跟踪动态分配的内存: C内存分配函数malloccallocrealloc ,以及C ++运算符new all返回指向动态分配内存的指针。 如果必须动态分配内存,则必须使用指针来引用它。 同样,我对Obj-C不太熟悉,知道他们是否使用不同的内存分配机制。

创建自引用和动态数据结构:诸如structunion类型之类的聚合类型不能包含它们自己的实例; 例如,你不能做类似的事情

 struct node { int value; struct node next; }; 

创建链表节点。 struct node在结束}之前不是完整的类型,并且您不能声明不完整类型的对象。 但是,struct可以包含指向其自身实例的指针

 struct node { int value; struct node *next; }; 

您可以声明指向不完整类型的指针,因此这有效。 列表中的每个节点都可以引用紧随其后的节点。 既然你正在处理指针,你可以合理地轻松地从列表中添加或删除节点; 你只需更新指针值,而不是物理移动数据。

我几乎可以保证Obj-C中的任何容器类型都使用指针操作。

因为有时语言强迫您:在C和C ++中,在大多数情况下,数组类型的表达式将隐式转换为指针类型。 数组下标是根据指针算法完成的; 表达式a[i]被评估为好像它被写成*(a + i) 。 IOW,你找到了第i个元素的地址并取消引用它。

指针并非特定于Objective-C,实际上它们在C中使用[通常不是那么多C ++]。 基本上,它是通过引用传递对象的方式。

 void thisFunctionModifiesItsArgs(int *x, int *y, int *z) { *x = 4; *y = *z; *z = 100; } int main() { int a = 0; int b = 1; int c = 2; thisFunctionModifiesItsArgs(&a, &b, &c); // now, a = 4, b = 2, and c = 100 } 

最明显的原因:

1)您希望指向的对象超出其使用范围,因此您创建了一个分配。 访问超出其范围的int的地址是在寻找麻烦 – 该地址很可能被其他东西使用。 如果你为它创建一个独特的内存位置,那么问题就解决了(或者……可能会被取代)。

2)你想通过引用/指针/地址传递它。 这对于变异对象很有用,或者在类型很大时用作优化。

3)支持多态和/或不透明类型

4)指向实现的指针(抽象,依赖性减少)

并且…(我不希望你在这个阶段了解所有这些案件)

所以,你展示的例子是如此微不足道,它不代表(任何)这些情况 – 它只是试图引入语法。

有很多情况,并且由于许多不同的原因,它们经常在现实世界的C,C ++,ObjC等程序中使用。

一个简单的答案:因为有些变量比简单的整数更复杂。 本教程为您提供了一个非常简单的案例来解释这个概念,但他们描述的简单案例几乎从未使用过。

Justin的答案就是你要问的问题。 如果您需要一个好的教程,那么我推荐“ 开始Mac编程 ”的第5章,它解释了内存寻址的工作原理以及如何使用指针,以及原因。

计算机科学001

计算机(计算机芯片)只能做三件事,但他们每秒可以完成数百万甚至数十亿次。

他们可以将信息(一个数字)存储到内存中。 他们可以对这些数字做关节炎。 他们可以根据关节模型进行简单的判断,就像a = b然后转到地址X.

而已。

我用来解释汇编程序编程初学者指针的一个非常简单的类比就是把内存想象成一排邮箱。 第一个邮箱的地址为0,下一个邮箱的地址为加号,依此类推。

当计算机启动时,它会被告知转到邮箱0并获取内容。

内容可以是信息或命令,邮箱0始终保存命令。 该命令可能是转到邮箱1并获取其内容。

邮箱的内容只能容纳如此多的信息,就像真正的邮箱只能容纳如此多的信息一样。 例如,如果邮递员需要提供包裹,他会在邮箱中发出通知去邮局领取邮件。 通知就像一个指针。 指针不保存信息,真实信息位于指针所在的位置,在这种情况下是邮局。

你甚至可以到邮局找出除了指向另一个位置的另一个指针之外什么都没有。 我们称之为“句柄”或指向指针的指针。

如果要将字节序列从一个位置复制到另一个位置(自然),您必须知道源和目标地址。 要在语言的抽象级别表达它,您可以使用指示内存位置的指针。 除了笔记之外,在较低级别中,经常使用指针。 一个非常简单的例子:写入80×25屏幕。 例如,屏幕的基地址是0xb8000,其中存储了屏幕的第一个字符。 您可以使用指针,您可以将字符写入屏幕中的适当位置。 例如: unsigned short* sc = (unsigned short*)0xb8000; *sc = 'A' | (attr) << 8; unsigned short* sc = (unsigned short*)0xb8000; *sc = 'A' | (attr) << 8; 。 等等...

注意:指针体现了间接性,有可能,你可以拥有“多个”指针:**(想象一下C主函数签名,以及它中的char **!)。 或者,例如,您希望在单独的函数中使用malloc创建列表结构。 然后你可以传递一个结构列表**或者你有什么参数,在函数中你可以为列表分配一个值(一个内存地址),这意味着你已经在内存中创建了列表。