【问题标题】:What does having two asterisk ** in Objective-C mean?Objective-C 中有两个星号 ** 是什么意思?
【发布时间】:2010-10-24 09:41:19
【问题描述】:

我知道有一个星号 * 是一个指针,有两个 ** 是什么意思?

我从文档中偶然发现了这一点:

- (NSAppleEventDescriptor *)executeAndReturnError:(NSDictionary **)errorInfo

【问题讨论】:

  • 疯狂猜测:指向指针的指针? :)
  • 是的,我也猜到了,但我找不到谷歌的任何确认。 :)

标签: objective-c pointers


【解决方案1】:

它是一个指向指针的指针,就像在 C 中一样(尽管它有奇怪的方括号语法,但 Objective-C 是基于它的):

char c;
char *pc = &c;
char **ppc = &pc;
char ***pppc = &ppc;

以此类推,无限循环(或者直到你用完可变空间)。

它通常用于将指针传递给必须能够更改指针本身的函数(例如为可变大小的对象重新分配内存)。

=====

根据您对演示如何使用它的示例的请求,这里是我为另一篇文章编写的一些代码来说明它。这是一个appendStr() 函数,它管理自己的分配(您仍然需要释放最终版本)。最初,您将字符串 (char *) 设置为 NULL,函数本身将根据需要分配空间。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void appendToStr (int *sz, char **str, char *app) {
    char *newstr;
    int reqsz;

    /* If no string yet, create it with a bit of space. */

    if (*str == NULL) {
        *sz = strlen (app) + 10;
        if ((*str = malloc (*sz)) == NULL) {
            *sz = 0;
            return;
        }
        strcpy (*str, app);
        return;
    }

 

    /* If not enough room in string, expand it. We could use realloc
       but I've kept it as malloc/cpy/free to ensure the address
       changes (for the program output). */

    reqsz = strlen (*str) + strlen (app) + 1;
    if (reqsz > *sz) {
        *sz = reqsz + 10;
        if ((newstr = malloc (*sz)) == NULL) {
            free (*str);
            *str = NULL;
            *sz = 0;
            return;
        }
        strcpy (newstr, *str);
        free (*str);
        *str = newstr;
    }

    /* Append the desired string to the (now) long-enough buffer. */

    strcat (*str, app);
}

 

static void dump(int sz, char *x) {
    if (x == NULL)
        printf ("%8p   [%2d]   %3d   [%s]\n", x, sz, 0, "");
    else
        printf ("%8p   [%2d]   %3d   [%s]\n", x, sz, strlen (x), x);
}

static char *arr[] = {"Hello.", " My", " name", " is", " Pax",
                      " and"," I", " am", " old."};

int main (void) {
    int i;
    char *x = NULL;
    int sz = 0;

    printf (" Pointer   Size   Len   Value\n");
    printf (" -------   ----   ---   -----\n");
    dump (sz, x);
    for (i = 0; i < sizeof (arr) / sizeof (arr[0]); i++) {
        appendToStr (&sz, &x, arr[i]);
        dump (sz, x);
    }
}

代码输出以下内容。您可以看到当当前分配的内存用完扩展字符串的空间时指针如何变化(在 cmets 处):

 Pointer   Size   Len   Value
 -------   ----   ---   -----
# NULL pointer here since we've not yet put anything in.
     0x0   [ 0]     0   []

# The first time we put in something, we allocate space (+10 chars).
0x6701b8   [16]     6   [Hello.]
0x6701b8   [16]     9   [Hello. My]
0x6701b8   [16]    14   [Hello. My name]

# Adding " is" takes length to 17 so we need more space.
0x6701d0   [28]    17   [Hello. My name is]
0x6701d0   [28]    21   [Hello. My name is Pax]
0x6701d0   [28]    25   [Hello. My name is Pax and]
0x6701d0   [28]    27   [Hello. My name is Pax and I]

# Ditto for adding " am".
0x6701f0   [41]    30   [Hello. My name is Pax and I am]
0x6701f0   [41]    35   [Hello. My name is Pax and I am old.]

在这种情况下,您传入**str,因为您需要能够更改*str 的值。

=====

或者下面的,它对不在数组中的字符串进行展开的冒泡排序(哦,真可惜!)。它通过直接交换字符串的地址来做到这一点。

#include <stdio.h>

static void sort (char **s1, char **s2, char **s3, char **s4, char **s5) {
    char *t;

    if (strcmp (*s1, *s2) > 0) { t = *s1; *s1 = *s2; *s2 = t; }
    if (strcmp (*s2, *s3) > 0) { t = *s2; *s2 = *s3; *s3 = t; }
    if (strcmp (*s3, *s4) > 0) { t = *s3; *s3 = *s4; *s4 = t; }
    if (strcmp (*s4, *s5) > 0) { t = *s4; *s4 = *s5; *s5 = t; }

    if (strcmp (*s1, *s2) > 0) { t = *s1; *s1 = *s2; *s2 = t; }
    if (strcmp (*s2, *s3) > 0) { t = *s2; *s2 = *s3; *s3 = t; }
    if (strcmp (*s3, *s4) > 0) { t = *s3; *s3 = *s4; *s4 = t; }

    if (strcmp (*s1, *s2) > 0) { t = *s1; *s1 = *s2; *s2 = t; }
    if (strcmp (*s2, *s3) > 0) { t = *s2; *s2 = *s3; *s3 = t; }

    if (strcmp (*s1, *s2) > 0) { t = *s1; *s1 = *s2; *s2 = t; }
}

int main (int argCount, char *argVar[]) {
    char *a = "77";
    char *b = "55";
    char *c = "99";
    char *d = "88";
    char *e = "66";

    printf ("Unsorted: [%s] [%s] [%s] [%s] [%s]\n", a, b, c, d, e);
    sort (&a,&b,&c,&d,&e);
    printf ("  Sorted: [%s] [%s] [%s] [%s] [%s]\n", a, b, c, d, e);
    return 0;
}

产生:

Unsorted: [77] [55] [99] [88] [66]
  Sorted: [55] [66] [77] [88] [99]

不要介意排序的实现,只需注意变量以char ** 传递,以便它们可以轻松交换。任何真正的排序都可能作用于真正的数据数组而不是单个变量,但这不是示例的重点。

【讨论】:

  • 您能详细说明您将如何在代码中使用它吗?这仍然让我不知道如何使用它。
  • 您可以在 appendToStr() 中使用 realloc() 代替 malloc()+strcpy()+free()。此外,没有理由为冒泡排序 5 个元素感到羞耻:冒泡排序/插入排序/选择排序对于非常小的数据集来说绝对是最快的算法——大多数高阶排序函数在除法期间切换到其中一个作为基本情况- 并征服。
  • @Adam,malloc/copy/free 是确保指针更改的一个杂项,否则我的调试输出可能不那么明显 :-) 而且我不是真的 对冒泡排序感到羞耻,我实际上将它(稍微优化和双向修改)用于大多数排序的数据集(例如,我的业务的 OOo 电子表格,其中事务按日期排序,您在其中添加少量新的结束,但它们可能出现故障)并且在这种情况下它比许多其他人效果更好。
  • 但大多数排序的数据集、非常小的数据集和家庭作业可能是我唯一会使用它的三个地方。
  • 感谢您的精彩解释。空间不足是我们可能需要更改指针的唯一原因吗?还有什么定义了当前分配的内存?所有对象是否具有相同的初始分配内存大小,还是因类型或其他因素而异?
【解决方案2】:

指向指针的指针

“指针”的定义说它是一个特殊的变量,它存储另一个变量的地址(不是值)。那个其他变量很可能是一个指针。这意味着一个指针指向另一个指针是完全合法的。

假设我们有一个指针p1,它指向另一个指针p2,它指向一个字符c。在内存中,这三个变量可以可视化为:

所以我们可以看到,在内存中,指针p1 保存着指针p2 的地址。指针p2持有字符c的地址。

所以p2 是指向字符c 的指针,而p1 是指向p2 的指针。或者我们也可以说p2是一个指向字符c的指针。

现在,在代码中p2 可以声明为:

char *p2 = &c;

p1 被声明为:

char **p1 = &p2;

所以我们看到p1 是一个双指针(即指向一个字符的指针),因此声明中有两个 *。

现在,

  • p1p2的地址,即5000
  • *p1p2 持有的值,即 8000
  • **p1 是 8000 处的值,即 c 我认为这应该非常清楚这个概念,让我们举一个小例子:

来源:http://www.thegeekstuff.com/2012/01/advanced-c-pointers/

对于它的一些用例:

这通常用于将指针传递给必须能够更改指针本身的函数,它的一些用例是:

  • 例如处理错误,它允许接收方法控制指针所引用的内容。见this问题
  • 用于创建不透明的结构,即其他人无法分配空间。见this问题
  • 如果此问题的其他答案中提到了内存扩展。

在我学习的过程中可以随意编辑/改进这个答案:]

【讨论】:

    【解决方案3】:

    指向指针的指针。

    【讨论】:

      【解决方案4】:

      在 C 中,指针和数组可以被同等对待,例如char* 是一个字符串(字符数组)。如果你想将一个数组数组(例如许多字符串)传递给一个函数,你可以使用 char**。

      【讨论】:

      • 有一个区别: sizeof (char[]) != sizeof (char*) :很多人都被这个咬过。
      【解决方案5】:

      (参考:更多iOS 6开发)

      在 Objective-C 方法中,参数,包括对象指针,是 按值传递,这意味着被调用的方法得到自己的副本 传入的指针。所以如果被调用的方法想要 更改指针,而不是指针指向的数据,您 需要另一个级别的间接性。于是,指针指向了指针。

      【讨论】:

        猜你喜欢
        • 2010-10-09
        • 1970-01-01
        • 1970-01-01
        • 2011-05-18
        • 2018-11-21
        • 2011-09-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多