7

一个非常基本的问题.. 但理解概念非常重要.. 在 c++ 或 c 语言中,我们通常不使用指针变量来存储值.. 即值简单地存储在:

int a=10;

但是在ios sdk中,在objective c中,我们使用的大多数对象都是通过用它们表示一个指针来初始化的,如下所示:

NSArray *myArray=[NSArray array];

所以,我的脑海中出现了一个问题,那就是,使用指针对象有什么好处需要(这就是我们在这里所说的,如果不正确,请告诉我)。我有时也会感到困惑使用指针对象进行分配时的内存分配基础。我可以在任何地方寻找好的解释吗?

4

5 回答 5

15

在 c++ 或 c 语言中,我们通常不使用指针变量来存储值

我会把那个“或C”部分去掉。C++ 程序员确实不赞成使用原始指针,但 C 程序员不会。C 程序员喜欢指针,并认为它们是解决所有问题的必经之路。(不,不是,但指针在 C 中仍然非常频繁地使用。)

但是在ios sdk中,在objective c中,我们使用的大多数对象都是通过用它们表示一个指针来初始化的

哦,仔细看:

大多数对象

更接近:

对象

所以你在谈论Objective-C对象,amirite?(忽略 C 标准本质上将所有值和变量描述为“对象”的微妙之处。)

在 Objective-C 中,实际上只是 Objective-C 对象始终是指针。由于 Objective-C 是 C 的严格超集,所有 C 习语和编程技术在编写 iOS 应用程序(或 OS X 应用程序,或任何其他基于 Objective-C 的程序)时仍然适用。这是毫无意义的,多余的,浪费的,因此,编写类似的东西甚至被认为是错误的

int *i = malloc(sizeof(int));
for (*i = 0; *i < 10; ++*i)

仅仅因为我们在 Objective-C 领域。基元(或更准确地说是使用 C++ 术语的“普通旧数据类型”)仍然遵循“如果不需要,不要使用指针”规则。

使用指针对象有什么好处和需要

那么,为什么它们是必要的:

Objective-C 是一种面向对象的动态语言。语言的这两个密切相关的属性使程序员可以利用多态性鸭子类型动态绑定等技术(是的,这些是超链接,单击它们)。

这些特性的实现方式使得所有对象都必须由指向它们的指针来表示。让我们看一个例子。

编写移动应用程序时的一项常见任务是从服务器检索一些数据。现代基于 Web 的 API 使用 JSON 数据交换格式来序列化数据。这是一种简单的文本格式,可以解析(例如,使用NSJSONSerialization类)为各种类型的数据结构及其对应的集合类,例如 anNSArray或 an NSDictionary。这意味着 JSON 解析器类/方法/函数必须返回一些通用的东西,可以代表数组和字典的东西。

那么现在怎么办?我们不能返回非指针NSArrayNSDictionary结构(Objective-C 对象实际上只是在我知道 Objective-C 工作的所有平台上的普通旧 C 结构),因为它们具有不同的大小,它们具有不同的内存布局等。编译器无法理解代码。这就是为什么我们返回一个指向通用 Objective-C 对象的指针,类型为id.

C 标准要求指向structs(以及指向对象)的指针具有相同的表示和对齐要求(C99 6.2.5.27),即指向任何结构的指针可以安全地转换为指向任何其他结构的指针。因此,这种方法是正确的,我们现在可以返回任何对象。使用运行时自省,还可以动态确定对象的确切类型(类),然后相应地使用它。

以及为什么它们比非指针更方便或更好(在某些方面) :

使用指针,无需传递同一对象的多个副本。创建大量副本(例如,每次将对象分配给或传递给函数时)可能会很慢并导致性能问题 - 一个中等复杂的对象,例如视图或视图控制器,可能有几十个实例变量,因此单个实​​例实际上可以测量数百个字节。如果一个采用对象类型的函数调用在一个紧密的循环中被调用数千或数百万次,那么重新分配和复制它是非常痛苦的(无论如何对于 CPU 来说),并且只传递一个更容易和更直接指向对象的指针(它的大小更小,因此复制速度更快)。此外,作为一种参考计数语言,Objective-C 甚至有点“不鼓励”过度复制。

此外,在使用指针对象进行分配时,我有时会对内存分配基础知识感到困惑

那么即使没有指针,您也很可能会感到困惑。不要将其归咎于指针,这是程序员的错误;-)

所以这里...

玩得开心!:-)

于 2013-08-01T13:05:58.797 回答
3

即使在 C 中,任何比 int 或 char 或类似内容更复杂的东西通常都作为指针传递。在 C 中,您当然可以在函数之间传递数据结构,但这很少见。

考虑以下代码:

struct some_struct {
    int an_int;
    char a_char[1234];
};

void function1(void)
{
    struct some_struct s;
    function2(s);
}

void function2(struct some_struct s)
{
    //do something with some_struct s
}

some_struct data 将被放入 function1 的堆栈中。调用 function2 时,数据将被复制并放入堆栈以供 function2 使用。它要求数据在堆栈上的两倍以及要复制的数据。这不是很有效。另外,请注意,更改 function2 中结构的值不会影响 function1 中的结构,它们是内存中的不同数据。

而是考虑以下代码:

struct some_struct {
    int an_int;
    char a_char[1234];
};

void function1(void)
{
    struct some_struct *s = malloc(sizeof(struct some_struct));
    function2(s);
    free(s);
}

void function2(struct some_struct *s)
{
    //do something with some_struct s
}

some_struct 数据将放在堆上而不是堆栈上。只有一个指向该数据的指针将被放入 function1 的堆栈中,在对 function2 的调用中复制另一个指针放入 function2 的堆栈中。这比前面的例子效率高很多。另外,请注意,function2 对结构中数据的任何更改现在都会影响 function1 中的结构,它们是内存中的相同数据。

这基本上是构建诸如 Objective-C 等高级编程语言的基础以及构建这些语言的好处。

于 2013-08-01T12:04:54.423 回答
1

指针的好处和需要是它的行为就像一面镜子。它反映了它所指向的内容。点可能非常有用的一个主要地方是在函数或方法之间共享数据。局部变量不能保证在每次函数返回时都保持其值,并且它们仅在它们自己的函数中可见。但是您仍然可能希望在函数或方法之间共享数据。您可以使用 return,但这仅适用于单个值。您也可以使用全局变量,但不能存储您的完整数据,您很快就会一团糟。所以我们需要一些可以在函数或方法之间共享数据的变量。有一些指向我们的补救措施。您可以只创建数据并传递指向该数据的内存地址(唯一 ID)。使用此指针,可以在任何函数或方法中访问和更改数据。就编写模块化代码而言,这是指针最重要的用途——在程序的许多不同位置共享数据。

于 2013-08-01T11:14:10.483 回答
0

在这方面,C 和 Objective-C 的主要区别在于 Objective-C 中的数组通常被实现为对象。(在 Java、BTW 和 C++ 中,数组总是作为对象实现的,并且 C++ 有几个类似于 NSArray 的通用类。)

仔细考虑过这个问题的任何人都明白,“裸”类 C 数组是有问题的——处理起来很尴尬,而且经常是错误和混乱的根源。(“一个数组‘衰减’到一个指针”——这应该是什么意思,无论如何,除了以反手的方式承认“是的,它令人困惑”??)

Objective-C 中的分配在很大程度上有点令人困惑,因为它处于转换中。旧的手动引用计数方案很容易理解(如果在实现中不那么容易处理的话),但是 ARC 虽然更容易处理,但要真正理解要困难得多,同时理解两者就更难了。但是两者都比 C 更容易处理,因为缺少引用计数,“僵尸指针”几乎是给定的。(C 可能看起来更简单,但这只是因为你做的事情不像你用 Objective-C 做的那样复杂,因为很难控制它。)

于 2013-08-01T11:31:53.603 回答
0

在引用堆上的东西时总是使用指针,有时,但通常在引用堆栈上的东西时不使用。

由于 Objective-C 对象总是在堆上分配(块除外,但这与本次讨论是正交的),你总是使用指向 Objective-C 对象的指针。id 和 Class 类型都是真正的指针。

您不使用指针的地方是某些原始类型和简单结构。NSPoint、NSRange、int、NSUInteger 等...通常都通过堆栈访问,通常您不使用指针。

于 2013-08-01T12:26:52.973 回答