2

This post is more of a type of confirmation post rather than a particular question.

I read up some answers on this site and other places to clear up my confusion regarding pointers of type, ex- int(*)[size] which are pointers to an array. From what I've understood, there are some basic differences which I concluded on - 1) pointer arithmetic, 2) dereferencing . I wrote up this code to differentiate between int* and int(*)[size].

int arr1[5] {} ;
int (*ptr1) [5] = &arr1 ;
(*ptr1)[3] = 40 ;
cout << ptr1 << endl ; 
cout << ptr1[3] << endl;
cout << ptr1 + 3 << endl ;


int arr2[5] {} ;
int* ptr2 = arr2 ;
ptr2[3] = 40 ;
cout << ptr2  << endl ;
cout << ptr2[3] <<endl ;
cout << ptr2 + 3 << endl ;

Output : enter image description here

On observing the output of arithmetic on int(*)[size] its evident that when we add say i to it , it jumps over a block of 4*size*i memory whereas the int* jumps over a 4*i memory block. Also in int* the expression of the form ptr2[i] is equivalent to *(ptr2+i) but in pointers of type int(*)[size] this is not the case ptr1[i] is equivalent to (ptr1 + i) and to replicate the action of ptr2[i] we have to do (*ptr1)[i] in this case.

Are there anymore significant differences between the pointers of such type and which pointer amongst them should be preferred and why ? Please correct my analysis if I have gone wrong somewhere .

7
  • 2
    Btw the first snippet with ptr1[3] has undefined behavior. Commented Oct 24, 2022 at 5:02
  • @JasonLiam Could you explain why? Commented Oct 24, 2022 at 5:07
  • Why still use pointers to a "C" style array when we have std::vector? To make an "array" of "arrays" use std::vector<std::vector<int>> (or std::array). Those types will also help you avoid memory allocation mistakes. Commented Oct 24, 2022 at 5:08
  • @Dhrxv Because in ptr1[3] you're trying to access memory that is not meant to be accessed by you. Commented Oct 24, 2022 at 5:08
  • @PepijinKramer I am doing this for the sole purpose of understanding pointers. I have no desire to use this practically, although thanks for the suggestion. Commented Oct 24, 2022 at 5:10

2 Answers 2

1

There are no differences between different kinds of pointers.

If p has the type T*, p + k is the address k * sizeof(T) away from p.

If p is the location of an object that is not an array element (as is the case when you acquire it with &), p[3] and p+3 are both undefined.
(In this case, p[0] is the only well-defined indexing, and p+0 and p+1 are the only well-defined arithmetical expressions – but you're not allowed to dereference p+1.)

Your pointer-to-array code is more similar to this int* version:

int x = 0;
int* ptr2 = &x ;
ptr2[3] = 40 ;
cout << ptr2  << endl ;
cout << ptr2[3] <<endl ;
cout << ptr2 + 3 << endl ;

which you can probably see is Just Wrong.

Sign up to request clarification or add additional context in comments.

5 Comments

Yes I realize that the memory is not meant to be accessed by me. I could however use this in a 2-d array to jump over from a row to the next row, so I just used this as an example to differentiate bw the two types . What would be the equivalent expression for this (*ptr1)[3] in terms of pointer arithmetic and dereference operator like the equivalent of ptr2[3] is *(ptr+3)
@molbdnilo First you've said in your answer that "p+3 are both undefined.". Then you said, "p+0 and p+1 are the only well-defined arithmetical expressions". This seems contradictory.
@Dhrxv There are no differences; if the equivalent of p[3] is *(p+3), and p is (*ptr1), the equivalent must be *((*ptr1) + 3), but I do not understand why anyone would prefer unreadable pointer arithmetic to indexing.
Oh I see so is ptr1 basically a pointer to a pointer to an array then?
@Dhrxv No, it's a pointer to an array. *ptr1 is an array - it's an int[5] - and like all arrays it can decay into a pointer to its first element. That is, *ptr1 + 3 is equivalent to &(*ptr1)[0] + 3.
0

Are there anymore significant differences between the pointers of such type and which pointer amongst them should be preferred and why ?

Yes, the first snippet with ptr1[3] results in undefined behavior as you're trying to access memory(pointed by ptr1 + 3) that is not meant to be accessed by you.

Note that just the expression ptr1 + 3 is well-defined but if we try to dereference this like *(ptr1 + 3) or ptr1[3] then we will have undefined behavior.

Undefined behavior means anything1 can happen(from C++ standard's perspective) including but not limited to the program giving your expected output. But never rely on the output of a program that has undefined behavior.

On the other hand, ptr2[3] is well-defined.


1For more reading(technical definition of) on undefined behavior you can refer to undefined behavior's documentation which mentions that: there are no restrictions on the behavior of the program.

3 Comments

Yes I realize that the memory is not meant to be accessed by me. I could however use this in a 2-d array to jump over from a row to the next row, so I just used this as an example to differentiate bw the two types .
@ArminMontigny Happy diwali to you too. Yes, actually dereferencing the pointer is undefined behavior but the expression ptr1 + 3 is well-defined. While *(ptr1 + 3) is undefined.
Pointer arithmetic is well defined only if the result is an element of the same array as the pointer, or one-past-the-end. You don't need to dereference for it to be undefined. (And dereferencing is not the same as accessing memory.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.