search

Home  >  Q&A  >  body text

objective-c - 关于C语言指针的问题

C语言指针问题 下面代码为什么第二个数字是5呢?

int a[5] = {1,2,3,4,5};
int *p = (int *)(&a+1);
NSLog(@"%d,%d", *(a+1), *(p-1));
黄舟黄舟2769 days ago430

reply all(3)I'll reply

  • 阿神

    阿神2017-04-21 11:19:34

    &a yields a pointer to the array, so &a+1 actually moves based on the length of the array. If you just want to get the second element of the array, then use *(&a[0]+1), because the data type of &a[0] is int*. Draw a picture first:

    Suppose we have the following array

    int a[5] = {1,2,3,4,5};
    int *x = &a+1;
    

    Although the above program can be compiled and passed, the compiler will issue a warning because the types of x and a do not match. There are two ways to remove the warning

    1. Through forced type conversion

    int *x = (int *)(&a+1); 
    print("%d\n",*(x-1));
    

    2. Find a suitable type for it. The type of &a is int (*)[5]

    int (*x)[5] = &a+1;
    printf("%d\n",**(x-1));
    

    This involves how to write appropriate data types, which is very important in assignment and parameter passing!

    So, first I have to summarize the data types of a, &a and &a[0]

    1. a is the name of the array, which is the pointer to the first element of the array. There is no doubt that here, the data type of the first element of the array is int, so the data type of a is int*.

    2. &a takes the address of a one-dimensional array, and the result is a pointer to the array (in this case, pointer to array of int), which is int(*)[5].

    3. &a[0] is very simple. First, a[0] gets an integer int, and then takes the address of it, so its data type is int*.

    Now that you know the data type, pointer arithmetic becomes much clearer!

    Let’s first look at the part of the code that passes the forced type conversion. What number will it output?

    The answer is 5! From the summary of data types just now, we can know that the data type of &a is int (*)[5], so &a+1 has actually been moved by 5*sizeof(int) bytes Now the pointer points to the element after the last element of the array (Figure 1), that is to say, it has crossed the boundary! But because the data type of x is actually int * So for x-1, it is actually moved 1*sizeof(int) bytes to the left, which means it points to the last element, so *(x-1) is obtained The value is the last element of the array: 5

    Okay, now let’s look at the second part. What numbers will it output? Let’s not talk about the answer first. I just said it here. The data type of Sizeof(int)*5 bytes are moved in units, so x-1 is actually moved to the left by sizeof(int)*5 bytes. It is moved on my machine. 20 bytes, which means returning to the first element of the array, so the answer is: 1 The above is a one-dimensional array. Now I want to talk about the situation of a two-dimensional array. There is the following code:

    int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
    /*
    ?? = a; // int (*b)[3] = a;
    ?? = a[0]; // int *c = a[0];
    ?? = a[0][0] // int d = a[0][0];
    ?? = &a; // int (*e)[3][3] = &a;
    ?? &a[0]; // int (*f)[3] = &a[0]
    ?? &a[0][0]; // int *g = &a[0][0]
    */
    

    Let’s take a look at the data types of a, a[0], &a, &a[0], &a[0][0] first:

    Pay attention to the bold text above, the array name is a pointer to the first element of the array!

      What is the data type of
    1. a? ? int *? No, the core of this bold text is the five words the first element, Isn't the first element of a just a[0][0]? Strictly speaking, no, the first element of a is actually a[0], so what is the data type of a[0]? a[0] is an array containing three int elements, so the type of a[0] is the same as the type of t in int t[3], which is int*. Since the data type of the first element is int*, if this two-dimensional array is regarded as a one-dimensional array, it is actually an array containing three int* elements. An array is an array of pointers, so the data type of a is int (*)[3]

    2. Let’s look at &a again. As mentioned when talking about one-dimensional arrays, the address obtained from an array name is a pointer to the array, so the data type of &a is int (*)[3][3]

    3. &a[0] This seems a bit painful, but as mentioned in the previous paragraph, a[0] is an array containing three int elements, and int t[3] The data type of t is the same, which is int*. Naturally, the data type of &a[0] is the same as the data type of &t, which is int (*)[3]

    At this point, we have almost written about the data type in the two-dimensional array. Now that we know the data type, we can accurately know where the pointer will move after calculation!

    Look at the code below:

    int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
    int (*x)[3] = a;
    int *k = a[0];
    int (*y)[3][3] = &a;
    int (*q)[3] = &a[0];
    int *z = &a[0][0];
    
    printf("%d\n",(*(x+1))[0]);
    printf("%d\n",*(k+1));
    printf("%d\n",(*(*(y+1)))[0]);
    printf("%d\n",(*(q+1))[0]);
    printf("%d\n",*(z+1));
    
    int *p = (int *)(y+1);
    printf("%d\n",*(p-1));
    
      The data type of
    • x is int (*)[3], so x+1 is actually moved by 3*sizeof(int) bytes, as shown in the figure:

    • The data type of
    • k is int *, so k+1 is actually moved by sizeof(int) bytes.

    • The data type of
    • y is int (*)[3][3], so y+1 is actually moved by 3*3*sizeof(int) bytes, which is to the last one in the array The element after the element. as the picture shows:

    • The data type of
    • q is int (*)[3], so q+1 is actually moved by 3*sizeof(int) bytes.

    • The data type of
    • z is int *, so z+1 is actually moved by sizeof(int) bytes.

    So when adding and subtracting array pointers, the most important thing is to know its step size, and the step size is determined by the data type!

    reply
    0
  • PHP中文网

    PHP中文网2017-04-21 11:19:34

    The answerer on the first floor wrote very well, please expand it

    The value of the pointer is the address of an array
    int (* pa)[5];
    pa++;pa moves back 20 bytes (5*4)

    Contrast, the elements in the array are pointers (int*)
    int *pa[5];
    pa++;pa moves back 4 bytes

    reply
    0
  • 高洛峰

    高洛峰2017-04-21 11:19:34

    Sorry to repost an old post. I saw this accidentally, because in the past when I was doing embedded programming, arrays and pointers were often used, including directly assigning a memory address to the pointer variable (this is generally not used in normal applications), and I had never found &arr before. What is the difference with arr. I checked specifically today and found out that this depends on the compiler. Some compilers treat arrays and pointers separately. The meaning of taking an address for an array name is for the entire array memory. Some compilers regard the array as a specific form of a pointer. In this case, the pointer jumps by one to be an array element. memory, but there is no such thing as the entire array memory.

    reply
    0
  • Cancelreply