What does having two asterisk ** in Objective-C mean?

后端 未结 5 1030
梦如初夏
梦如初夏 2020-12-03 02:08

I understand having one asterisk * is a pointer, what does having two ** mean?

I stumble upon this from the documentation:

- (NSAppleEventDescriptor          


        
5条回答
  •  春和景丽
    2020-12-03 02:40

    It's a pointer to a pointer, just like in C (which, despite its strange square-bracket syntax, Objective-C is based on):

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

    and so on, ad infinitum (or until you run out of variable space).

    It's often used to pass a pointer to a function that must be able to change the pointer itself (such as re-allocating memory for a variable-sized object).

    =====

    Following your request for a sample that shows how to use it, here's some code I wrote for another post which illustrates it. It's an appendStr() function which manages its own allocations (you still have to free the final version). Initially you set the string (char *) to NULL and the function itself will allocate space as needed.

    #include 
    #include 
    #include 
    
    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);
        }
    }
    

    The code outputs the following. You can see how the pointer changes when the currently allocated memory runs out of space for the expanded string (at the comments):

     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.]
    

    In that case, you pass in **str since you need to be able to change the *str value.

    =====

    Or the following, which does an unrolled bubble sort (oh, the shame!) on strings that aren't in an array. It does this by directly exchanging the addresses of the strings.

    #include 
    
    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;
    }
    

    which produces:

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

    Never mind the implementation of sort, just notice that the variables are passed as char ** so that they can be swapped easily. Any real sort would probably be acting on a true array of data rather than individual variables but that's not the point of the example.

提交回复
热议问题