0

I am learning about pointers and how they work in general. I have found some example code online: https://overiq.com/c-programming-101/pointers-and-2-d-arrays/

#include<stdio.h>

int main()
{
    int *p; // pointer to int
    int (*parr)[5]; // pointer to an array of 5 integers
    int my_arr[5]; // an array of 5 integers

    p = my_arr; 
    parr = my_arr;

    printf("Address of p = %u\n", p );
    printf("Address of parr = %u\n", parr );

    p++;
    parr++;

    printf("\nAfter incrementing p and parr by 1 \n\n");
    printf("Address of p = %u\n", p );
    printf("Address of parr = %u\n", parr );

    printf("Address of parr = %u\n", *parr );

    // signal to operating system program ran fine
    return 0;
}

However, I am having an error when debugging this code:

Severity    Code    Description Project File    Line    Suppression State
Error   C2440   '=': cannot convert from 'int [5]' to 'int (*)[5]'  First_project_vs    C:\Users\Lukas\Desktop\VS_projects\First_project_vs\First_project_vs\First_project_vs.cpp   16  

Perhaps someone can help me understand what is the issue here? Is the example provided code wrong?

Also, I am learning from the following video: https://www.youtube.com/watch?v=zuegQmMdy8M&ab_channel=freeCodeCamp.org

If you go to 1:48:52, You will see, that he is suggesting a similar method of declaring a pointer which I am also having issues compiling.

Can someone shed some light to me about what is wrong here? Appreciate any help

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Lukas Petrikas
  • 65
  • 2
  • 11
  • 1
    `printf("Address of p = %u\n", p );` is Undefined Behavior. you need to use `%p` for pointers. (yes, online tutorial are sometimes/often wrong and this one has multiple errors.). – JHBonarius Apr 19 '21 at 09:37
  • Visual code suggests that the problem is with this line of code: ```parr = my_arr;``` error message:```a value of type int* cannot be assigned to an entity of type int(*)[5]``` – Lukas Petrikas Apr 19 '21 at 09:42
  • @LukasPetrikas. Look at this link : https://stackoverflow.com/a/3912959/7462275 – Stef1611 Apr 19 '21 at 11:14

3 Answers3

1

Except when it is the operand of the sizeof or unary & operators, or it 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, or "decay", to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.

In the statement

p = my_arr; 

the expression my_arr has type "5-element array of int" (int [5]) - since it is not the operand of the sizeof or unary & operators, it "decays" to an expression of type "pointer to int" (int *) and the address of my_arr[0] is assigned to p, which also has type int *:

p = my_arr; // int * = int *, equivalent to p = &my_arr[0]
        

Since each my_arr[i] has type int, the expression &my_arr[i] has type int *, so

p = &my_arr[i]; // int * = int *

sets p to point to the i'th element of the array.


However, in the expression

parr = my_arr; // int (*)[5] = int *

parr has type "pointer to 5-element array of int", or int (*)[5]. This type is not compatible with int *. In this case, we need to use the unary & operator on my_arr:

parr = &my_arr; // int (*)[5] = int (*)[5]

Since my_arr is the operand of the unary & operator, the expression does not decay to int *; instead, the type of the expression is "pointer to 5-element array of int".


Now for the fun bit - let's declare a 2d array my_2d_arr as

int my_2d_arr[3][5];

In this case, the expression my_2d_arr has type "3-element array of 5-element array of int" and will decay to type "pointer to 5-element array of int". Remember that the rule is "N-element array of T" (T [N]) => "pointer to T" (T *) - in this case, our T is "5-element array of int". So we can write

parr = my_2d_arr; // int (*)[5] = int (*)[5]

and it will work as expected. The address of my_2d_arr[0] gets assigned to parr. Just like above, it's equivalent to writing

parr = &my_2d_arr[0];

The expression my_2d_arr[0] has type "5-element array of int" (int [5]) - since it's the operand of the & operator, the decay doesn't occur, and the type of the expression is "pointer to 5-element array of int" (int (*)[5]).


Here's a handy table summarizing all of the above:

      Expression        Type          Decays to         Equivalent expression
      ----------        ----          ---------         ---------------------
          my_arr        int [5]       int *             &my_arr[0]
         &my_arr        int (*)[5]    n/a               n/a
         *my_arr        int           n/a               my_arr[0]
       my_arr[i]        int           n/a               n/a
      &my_arr[i]        int *         n/a               n/a

       my_2d_arr        int [3][5]    int (*)[5]        &my_2d_arr[0]
      &my_2d_arr        int (*)[3][5] n/a               n/a
      *my_2d_arr        int [5]       int *             my_2d_arr[0], &my_2d_arr[0][0]
    my_2d_arr[i]        int [5]       int *             &my_2d_arr[i][0]
   *my_2d_arr[i]        int           n/a               my_2d_arr[i][0]
   &my_2d_arr[i]        int (*)[5]    n/a               n/a
John Bode
  • 119,563
  • 19
  • 122
  • 198
0

Trying to find the dupe, but you need to take the address of the object and assign that to the pointer. You do that with the operator &.

parr = &my_arr;

I suggest you start looking for another tutorial. This one has multiple errors. i.e. you will learn wrong things.

JHBonarius
  • 10,824
  • 3
  • 22
  • 41
  • That fixed the problem... Thanks I should probably look into different pointers tutorial in that case! Perhaps you have some recommendations? – Lukas Petrikas Apr 19 '21 at 09:48
  • By using the operator &, you're making `parr` access a pointer to a pointer to the array, not the array itself. – rdbo Apr 19 '21 at 09:54
  • Well, in this case the array is allocated on stack, so you could access the array directly. But that aside, yes, that's what a pointer does. it points to another object. and if that object is a pointer, the pointer points to a pointer. the definition is correct in this case. – JHBonarius Apr 19 '21 at 09:57
  • Just tried compling this with GCC: `error: invalid initializer` on the line `int *parr[10] = &arr;` – rdbo Apr 19 '21 at 10:01
  • @rdbo crucial mistake. should be `int (*parr)[10] = &arr;` (or with 5 in this case) – JHBonarius Apr 19 '21 at 10:03
  • @JHBonarius Oh, my bad, seems you're right. I still don't think it's a good idea to access this array as a reference, as you'd have to dereference it everytime you want to read from/write to it from the pointer. Useful for matrices though. – rdbo Apr 19 '21 at 10:10
  • 1
    @rdbo this is just a coding example for a tutorial. However, consider using it as a function parameter. You don't want to copy the whole array, so pass a proper pointer. (maybe also look up some of the books in the links in my answer, there's definitely info on this in some of them) – JHBonarius Apr 19 '21 at 10:14
  • 1
    `(*parr)[0] = 10`...don't forget the parentheses! And yes, that's how pointers work. (C++ will not even allow a lot of things you can do in C due to type safety). – JHBonarius Apr 19 '21 at 10:30
  • I thought a little bit more about it, and this way seems better now. An extra dereference isn't going to hurt. – rdbo Apr 19 '21 at 10:32
0

In this assignment statement

parr = my_arr;

the left operand has the type int ( * )[5] while the right operand has the type int[5] and there is no implicit conversion from one type to another.

If you want to initialize the pointer parr with the address of the array my_arr as a whole object then you have to write

parr = &my_arr;

Pay attention to that the text in these calls of printf

printf("Address of p = %u\n", p );
printf("Address of parr = %u\n", parr );

is incorrect and moreover there are used incorrect conversion specifiers. The function do not output addresses if the variables p and parr. They are trying to output stored values in these pointers.

So you have to write for example

printf("Address stored in p = %p\n", ( void * )p );
printf("Address stored in parr = %p\n", ( void * )parr );

And in the both calls there will be outputted the same value.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335