简体   繁体   中英

Need to understand some pointers in C

Well, i have this simple example that we must use in school but i dont understand why we must use pointers and what they exactly do in same cases.

   int **create(int lines, int columns)
   {
   int **p, i;
   p = (int **) malloc(lines * sizeof(int *));
   for(i = 0; i < lines; i++)
      p[i] = (int *) malloc(columns * sizeof(int));   
   return p; 
   } 

I google that ** is pointer to pointer. Simply pointer pointing to pointer that has stored address of variable. But WHY I should do that? And then these two lines of code looks to have totally random pointers

p = (int **) malloc(lines * sizeof(int *));
p[i] = (int *) malloc(columns * sizeof(int));

Basically I understand that pointer is pointing to address of variable or something but don't know what is happening here. Please if can somebody explain it to me. Thanks for your time.

A pointer can also be understood as an array. You allocate some space with malloc , and you can set items with the [] operator, just like as arrays.

int* arr = (int*)malloc(sizeof(int)*3);
arr[1] = 5;
printf("%d", arr[1]); //output is 5

Pointers to pointers can be understood as two-dimensional arrays: You allocate space for the pointers , then allocate each pointer as an array.

int** arr = (int**)malloc(sizeof(int*) * 3);
for (int i = 0; i < 3; i++) {
    arr[i] = (int*)malloc(sizeof(int) * 3); // each element is going to be an array of 3 integers
}
arr[2][2] = 4;
printf("%d", arr[2][2]); // 4

This function creates a matrix which is a two dimensional array.

An array is a sequence of elements stored contiguously in memory. With malloc we allocate a memory block that can be used as an array. We then hold a pointer to the block of elements. We can then use the notation a[i] to identify the ith element of the array whose address is stored in a .

The expression malloc(n * sizeof(int)); allocates a memory block with room for n integers. Note that it returns a pointer to an integer : int * .

When we create a two dimensional array, each row is an array allocated with the above instruction. n is replaced by the number of columns.

All the rows are then bundled together with an array of arrays. Remember that an array is of type int * . Thus an array of arrays has int * values as element. It's type is then int ** .

The first malloc in your code allocates the array that will hold all the rows array. This is why its type is int ** . Its byte size is lines time the byte size of an int * .

In the for loop, each row is instantiated and assigned to the corresponding element of the array p .

The pleasant thing of the returned two dimensional array is that you may then identify on of its elements by the expression a[i][j] .


Note that there is a mistake in this code.

The for loop is for(i = 0; i < riadky; i++) . riadky is an undefined variable. It's not the right variable name.

Now that you hopefully understand the code, could you find the correct variable name to put there ? You should be able to find it from my explanations.

Some pictures should help.

We start with the object p :

   int **
   +–––+
p: |   |
   +–––+

p has type int ** , meaning it can store the address of an object of type int * .

For simplicity's sake, we'll assume both lines and columns are 2 . So we start by dynamically allocating enough space for two objects of type int * , and store the address of the first of those objects into p :

   int **        int *
   +–––+         +–––+
p: |   | ––––––> |   |
   +–––+         +–––+
                 |   |
                 +–––+

The array subscript operation a[i] is defined as *(a + i) - given a starting address a , offset i elements ( not bytes ) from that address 1 and dereference the result 2 . So the expression p[0] refers to the first element and p[1] the second:

   int **        int *
   +–––+         +–––+
p: |   | ––––––> |   | p[0]
   +–––+         +–––+
                 |   | p[1]
                 +–––+

Now, for each p[i] , we allocate enough space for 2 int objects and assign the address of the first of each set into p[i] :

   int **        int *          int
   +–––+         +–––+          +–––+
p: |   | ––––––> |   | p[0]-––> |   | p[0][0]
   +–––+         +–––+          +–––+
                 |   | p[1]–+   |   | p[0][1]
                 +–––+      |   +–––+
                            |
                            |   +–––+
                            +-> |   | p[1][0]
                                +–––+
                                |   | p[1][1]
                                +–––+

As for why you need to use multiple levels of indirection ( ** , *** , etc.)...

For any object E of type T , the expression &E evaluates to the address of that object, and the type of that expression is T * (pointer to T ). If we repace T with a pointer type P * , then the type of &E is P ** . IOW, the type of an object that holds the address of another object must have one more level of indirection than the pointed-to object.


  1. Pointer arithmetic works in terms of objects, not bytes. If p has type int * and points to an int object, then p+1 points to the next int object immediately following, whether that object is 2, 4, or more bytes away.
  2. ”But everyone says arrays are not pointers, how is a an address?” Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type “N-element array of T ” will be converted (“decay”) to an expression of type “pointer to T ” and the value of the expression will be the address of the first element.

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