简体   繁体   中英

What is the difference between pointer to array and pointer to pointer?

I'm new in programming and learning about pointers in array. I'm a bit confused right now. Have a look at the program below:

#include <stdio.h>
int fun();
int main()
{
    int num[3][3]={23,32,478,55,0,56,25,13, 80};
    printf("%d\n",*(*(num+0)+1));
    fun(num);
    printf("%d\n", *(*(num+0)+1));
    *(*(num+0)+0)=23;
    printf("%d\n",*(*(num+0)));
    return 0;
}
int fun(*p)  // Compilation error
{
    *(p+0)=0;
    return 0;
}

This was the program written in my teacher's notes. Here in the main() function, in the printf() function dereference operator is being used two times because num is pointer to array so first time dereference operator will give pointer to int and then second one will give the value at which the pointer is pointing to.

My question is that when I'm passing the array name as argument to the function fun() then why *p is used; why not **p as num is a pointer to array?

Second thing why *(p+0) is used to change the value of zeroth element of the array; why not *(*(p+0)+0)=0 as in the main() function *(*(num+0)+0) is used to change the value of zeroth element?

The whole thing is very confusing for me but I have to understand it anyway. I have searched about this and found that there is a difference between pointer to array and pointer to pointer but I couldn't understand much.

The trick is the array-pointer- decay : When you mention the name of an array, it will decay into a pointer to its first element in almost all contexts. That is num is simply an array of three arrays of three integers (type = int [3][3] ).

Lets analyse the expression *(*(num + 1) + 2) .

When you mention num in the expression *(num + 1) , it decays into a pointer to its first element which is an array of three integers (type = int (*)[3] ). On this pointer pointer arithmetic is performed, and the size of whatever the pointer points to is added to the value of the pointer. In this case it is the size of an array of three integers (that's 12 bytes on many machines). After dereferencing the pointer, you are left with a type of int [3] .

However, this dereferencing only concerns the type, because right after the dereferencing operation, we see expression *(/*expression of type int[3]*/ + 2) , so the inner expression decays back into a pointer to the first array element. This pointer contains the same address as the pointer that results from num + 1 , but it has a different type: int* . Consequently, the pointer arithmetic on this pointer advances the pointer by two integers (8 bytes). So the expression *(*(num + 1) + 2) yields the integer element at an offset of 12 + 8 = 20 bytes, which is the sixth integer in the array.


Regarding your question about the call of fun() , that call is actually broken, and only works because your teacher did not include the arguments in the forward declaration of fun() . The code

int fun(int* arg);

int main() {
    int num[3][3] = ...;
    ...
    fun(num);
}

would have generated a compile time error due to the wrong pointer type. The code of your teacher "works", because the pointer to the first array in num is the same as the pointer to the first element of the first array in num , ie his code is equivalent to

int fun(int* arg);

int main() {
    int num[3][3] = ...;
    ...
    //both calls are equivalent
    fun(num[0]);
    fun(&num[0][0]);
}

which would compile without error.

This example shows a matrix, pointers to the first integers of arrays, and pointer to pointer

#include<stdio.h>
int fun(int (*p)[3]);  /* p is pointer to array of 3 ints */
int main()
{
    /* matrix */
    int num[3][3]={{23,32,478},{55,0,56},{25,13, 80}};
    /* three pointers to first integer of array */
    int *pnum[3] = {num[0], num[1], num[2]};
    /* pointer to pointer */
    int **ppnum = pnum;
    printf("%d\n", *(*(num+1)+2));
    fun(num);
    printf("%d\n", *(*(num+1)+2));
    pnum[1][2] = 2;
    printf("%d\n", *(*(num+1)+2));
    ppnum[1][2] = 3;
    printf("%d\n", *(*(num+1)+2));
    return 0;
}
int fun(int (*p)[3])
{
    p[1][2]=1;
    return 0;
}

You do not actually need any pointers to print anything here.

Your int num[3][3] is actually an array of three elements, each of which is an array of three integers. Thus num[0][0] = 23 , num[1][1] = 0 , and so on. Thus you can say printf("%d", num[0][0]) to print the first element of the array.

Pointer to variable:

Pointer is variable which stores the address( of a variable ). Every one know that.


Pointer to Array:

An array is a variable which has the starting point(address) of group of same objects.

And the pointer is a variable which stores the starting point(address) of an Array.

For example:

int iArray[3];

iArray is a variable which has an address value of three integers and the memory is allocated statically. And the below syntax is provided in a typical programming languages.

// iArray[0] = *(iArray+0);
// iArray[1] = *(iArray+1);
// iArray[2] = *(iArray+2);

In the above the iArray is a variable through which we can access the three integer variables, using any of the syntax mentioned above.

*(iArray+0); // Here iArray+0 is the address of the first object. and * is to dereference *(iArray+1); // Here iArray+1 is the address of the second object. and * is to dereference

So simple, what is there to confuse.


The below lines are for your understanding

int iArray1[3];
int iArray2[3][3];

int *ipArray = 0;

ipArray = iArray1;        // correct
ipArray = iArray2[0];     // correct
ipArray = iArray2[2];     // correct
int **ippArray = iArray2; // wrong

As per the above last line, compiler will not take it as a valid assignment. So **p is not used.

Pointer arthmatic cannot be applied on double arrays because of the way memory is allocated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM