c++ arrays vs pointers - c++

In C++ following is valid
int *p = new int[3];
*p=0;
*(++p)=1;
Also following is valid
int j[] = { 0, 1, 2};
*j = 3;
Given, *j =3 works, Why is following invalid
*(++j)=4;//invalid.. lvalue required as increment operand

In an expression like this
*(++j)=4;//invalid.. lvalue required as increment operand
j which is an array int[3] "decays" to a pointer to the first element of that array. That pointer is an rvalue, and can't be assigned, therefore you can't do things like *(++j).
In your other example p is a pointer which is non const and can be assigned:
int *p = new int[3];
*p=0;
*(++p)=1;
The behavior you obtain with the rvalue is similar to what would happen with a const pointer:
int const *p = new int[3];
*p=0;
*(++p)=1;

Arrays and pointers are similar, but this is one place where they are not.
If you want to iterate over an array, use a separate pointer variable:
int j[] = { 0, 1, 2};
int* jp = j;
jp then points to the first element of j. Then:
*(++jp) = 4;
will work.

Related

Why in C++, I don't need to dereference a pointer to an array in order to access items in the array

I'm currently learning pointer. And when I create a pointer to an array with int type, I found that I can directly index the pointer without deferencing the pointer and the compiler still output exact items in my array. I do not understand why this works and why we don't need to first deference the pointer.
Code that without dereference
int arraySize = 5;
int* theArray = new int[arraySize];
for(int i = 0; i < 5; i++)
{
theArray[i] = i;
}
for (int i = 0; I < 5; i++)
{
std::cout << theArray[i] << std::endl;
}
And this gives me the output
Output without derefercing
However, when I wrote like this:
for (int i = 0; i < 5; i++)
{
(*theArray)[i] = i;
}
My compiler says that: Error: expression must have pointer-to-object type. (I'm using Visual Studio 2013.)
Any help would be appreciated.
Code that without dereference
[ code ]
That's incorrect. You are most certainly dereferencing your pointer:
theArray[i] = i;
That's a pointer dereference. The [] operator dereferences the pointer. This is equivalent to:
*(theArray+i) = i;
As you know, adding or subtracting a value to a pointer advances or decrements the pointer, producing a new pointer value, and then the pointer gets dereferenced.
Also:
*p = q;
is equivalent to
p[0] = q;
The [] operator is just a shorthand for adding an offset to a pointer, and dereferencing the resulting pointer with the * operator. The end result is exactly the same.
I do not understand why this works and why we don't need to first deference the pointer.
The first version is correct:
for(int i = 0; i < 5; i++)
{
theArray[i] = i;
}
because theArray[i] is actually *(theArray + i) - essentially pointer arithmetic is equivalent to array index.
On the other hand, the 2nd version is incorrect:
for (int i = 0; i < 5; i++)
{
(*theArray)[i] = i;
}
That's because (*theArray)[i] is actually pointer to array (not the array itself), and so it caused a type mismatch as the compiler already suggested.
A few other answers correctly say that *(theArray + i) is equivalent to theArray[i]. But the point I think you missed when learning is that unlike most objects a pointer to an array is not a pointer to the array that is then dereferenced, and then array logic, it is only a pointer to the first element of the array. That's why this:
int *myIntPointer = new int[5];
is NEARLY the same as this:
int myIntArray[5]; // "True" array on the stack
But you can also point it at something else:
int myInt = 10;
delete [] myIntPointer;
myIntPointer = &myInt;
It's also why doing the follow CAN give a compiler warning, but can also work (depends on the compiler):
myIntPointer = myIntArray; // Sometimes works, sometimes doesn't, compiler dependent
That's because allocating an array with new int[size] returns a pointer to an int not a pointer to an "array" type.
It's a weird corner case of C/C++ that arrays and pointers interact this way. You also run into it if you try and pass one of the "true" arrays into a function.
theArray[i] literally corresponds to *(theArray + i) so it already dereferences the pointer.
Indeed when you try to call operator[] on *theArray it yields you an error because it expects a pointer, not a real object.
You're actually asking the wrong question for your misunderstanding — you should be asking why you can write
int* theArray = new int[arraySize];
In c++, array types are not like other types, and have a number of special cases and rules that make them behave differently from other types. In particular, new T[N] does not return a "pointer to an N-long array of T", it returns a "pointer to T". (specifically, to the first element of the newly created array)
For a more mindboggling example of this, observe:
typedef int T[5];
T* p = new T; // this does not compile
int* q = new T; // this does compile

How do I make assignments to an array int (*&Test)[10]?

I am having problems understanding how to assign to the Test array as shown below:
int (*&Test)[10] = Parray; Test is a reference to a pointer to an array of ten ints.
The error I get is as follows:
error: incompatible types in assignment of 'int*' to 'int [10]'|.
I have done my research without understanding this completely. I'm reading C++ Primer 5th edition.
int main() {
int arr[10];
int n = 5;
int *ptr1 = &n;
int arr2[10];
int *ptrs[10]; // ptrs is an array of ten pointers
// Parray points to an array of ten ints
int (*Parray)[10] = &arr;
// arrRef refers to an array of ten ints
int (&arrRef)[10] = arr2;
// Test is a reference to a pointer to an array of ten ints.
int (*&Test)[10] = Parray;
// How can I assign to Test[0..1..2..etc]?
// This is what I am trying to do:
Test[0] = ptr1; // Error here
return 0;
}
How can I assign to Test[0] etc.?
Use the followi ng expression statement
Test[0][0] = *ptr1;
The type of expression Test[0] is int [10]. So Test[0][0] will have type int and *ptr1 has type int Of course ptr1 shall have a valid value that may be dereferenced.
It should be:
(*Test)[0] = 3;
(*Test)[1] = 5;
etc. Alternatively you can write Test[0][0] = 3; Test[0][1] = 5; however I think that is less clear.
Test is a reference to the same type as Parray. Dereferencing this gives an array of 10 int, which you can then use array syntax on.

Increment operator on pointer of array errors?

I'm trying something very simple, well supposed to be simple but it somehow is messing with me...
I am trying to understand the effect of ++ on arrays when treated as pointers and pointers when treated as arrays.
So,
int main()
{
int a[4] = { 1, 4, 7, 9 };
*a = 3;
*(a+1) = 4;
*++a = 4; //compiler error
}
1: So at *(a+1)=4 we set a[1]=4; //Happy
But when *++a = 4;, I'd expect pointer a to be incremented one since ++ is precedent to * and then * kicks in and we make it equal to 4. But this code just does not work... Why is that?
Another problem:
int main()
{
int* p = (int *)malloc(8);
*p = 5;
printf("%d", p[0]);
*++p = 9; //now this works!
printf("%d", p[1]); //garbage
printf("%d", p[0]); //prints 9
}
2: Now *++p = 9; works fine but it's not really behaving like an array. How are two different? This is just incrementing p, and making it equal to 9. If I print p[0], it now prints 9 and I see that though can't access it via p[0] anymore, *(p-1) shows 5 is still there. So indexing a pointer with [0], where exactly does it point to? What has changed?
Thanks a lot all experts!
The array names is not modifiable lvalue so operation ++ is not applied hence ++a that try to modify a is compilation time error (where a is array name).
Note *(a + 1) and *a++ are not same, a + 1 is a valid instruction as it just add 1 but doesn't modify a itself, Whereas ++a (that is equvilent to a = a + 1) try to modify a hence error.
Note 'array names' are not pointer. Pointers are variable but array names are not. Of-course when you assign array name to a pointer then in most expressions array names decays into address of first element. e.g.
int *p = a;
Note p points to first element of array (a[0]).
Read some exceptions where array name not decaying into a pointer to first element?
An expression a[i] is equivalent to *(a + i), where a can be either a pointer or an array name. Hence in your second example p[i] is valid expression.
Additionally, *++p is valid because because p is a pointer (a variable) in second code example.
int a[4] = { 1, 4, 7, 9 };
int *pa=a;
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, sopa=a and pa++ are legal. But an array name is not a
variable; constructions like a=pa and a++ are illegal
int* p = (int *)malloc(8);
Don't cast result of malloc()
Use index with pointer
p[1]=9; // p[1]==*(p+1)

Pointers problem

I have a question.
I created a correctly initialized integer pointer
int * p
and a correctly initialized integer array
int * array1 = new int[]
Which of the following is legal code?
p = array1;
array1 = p;
Or are both correct?
is this possible as well
p[0] since, to my pointer arithmetic knowledge, it doesn't add anything.
All in c++
If the question is trying to get at pointers versus arrays, they are not always compatible. This is hidden in the presented code because the array is immediately converted to a pointer.
int* array1 = new int[5]; // Legal, initialising pointer with heap allocated array
int array2[5] = {0}; // Declaring array directly on the stack and initalising with zeros
int *p = 0; // Declaring pointer and initialising to numm
p = array2; // Legal, assigning array to pointer
p = array1; // Legal, assigning pointer to pointer
array1 = p; // Legal, assigning pointer to pointer
array2 = p; // ILLEGAL, assigning pointer to array
Here array2 has an array type and cannot be used to store a pointer. Actually, the array cannot be reassigned at all, as it is not an l-value.
int array3[5] = {0}; // Declaring array directly on the stack and initalising with zeroes
array3 = array2; // ILLEGAL, array not an l-value
The array has a fixed address and reassiging it would be similar to trying to write:
int i = 0;
&i = p;
[Hopefully, trying to reassign the location of a variable is obvious nonsense.]
Both are legal.
The first, "p = array1", will cause your correctly initialized integer pointer to be leaked and to point p to the first occurrence of the array that array1 points to.
The second, "array1 = p", will cause the correctly initialized integer array to to be leaked and to point array1 to the single int that p points to.
So I suspect I'm missing something. Could you perhaps post complete code?
If both p and array1 are declared as "int *", as you imply here, then either assignment is legal, by definition.
both are leagal.
passing adresses to eachother. dont knw what u want to do
According to the explanation provided in this site. The first assigned in is correct but the second assignment cannot be considered valid. Please look under the title 'Pointers and arrays'.
You can assign your array variable to pointer variable. So p = array1 is correct.
You can refer this code.
#include <iostream>
using namespace std;
int main ()
{
int numbers[5];
int * p;
p = numbers; *p = 10;
p++; *p = 20;
p = &numbers[2]; *p = 30;
p = numbers + 3; *p = 40;
p = numbers; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << numbers[n] << ", ";
for (int n=0; n<5; n++)
cout << p[n] << ", ";
return 0;
}
If both are pointers then no need to declare pointer as array like int *array1 = new int[].
Both variables are of type pointer to int. So both assignments are legal. The fact that one of the variables is an array doesn't matter in C. Arrays and pointers are the same after initialization.
"I created a correctly initialized integer pointer int * p and a correctly initialized integer array int * array1 = new int[]"
First of all, keeping the syntactical mistakes aside, the terminology is wrong.
int *p; - Here you are just declaring a pointer to hold an integer variable's address. You are not initializing it. Declaration is different from initialization and initialization is different from assignment.
int *array1 = new int[]; - Keeping the error aside, this is not an initialized integer array. array1 is a pointer pointing to an array of integers.
And passing nothing to [] is incorrect. A value needs to be passed that decides number of memory locations to be allocated for holding integer values.
Answering the questions.
Which of the following is legal code?
p = array1;
If, array1 is properly initialized it's correct. p points to the first integer in the array1. Even if it is not properly initialized also, it is correct. In this case, both array and p points to garbage values.
int* array1 = new int[5]; // Notice **5** being passed.
array1 = p;
Infact this operation is useless. Both p and array1 were both pointing to the same location earlier. But this is legally correct.
is this possible as well p[0] ?
Yes, it's correct. p can dereference to 0 to 4 as it's index values. If you just want to p[0], in that case -
int* array1 = new int ; // Notice nothing being passed.

C/C++ Array initializer problem

Can someone explain why I can do:
int x[4] = { 0, 1, 2, 3 };
int *p = x;
But cannot do:
int x[2][2] = { 0, 1, 2, 3 };
int **p = x;
Is there a way to be able to assign to **p the x[][]?
TIA
A pointer to int int * can point at an integer within an array of integers, so that's why the first is OK;
int x[4] = { 0, 1, 2, 3 };
int *p = x;
This makes p point to x[0], the first int in x.
A pointer to a pointer-to-int int ** can point at a pointer-to-int within an array of pointers-to-int. However, your second array is not an array of pointers-to-int; it is an array of arrays. There are no pointers-to-int, so there is nothing sensible to point int **p at. You can solve this in two ways. The first is to change the type of p so that it is a pointer-to-array-of-2-ints:
int x[2][2] = { 0, 1, 2, 3 };
int (*p)[2] = x;
Now p points at x[0], the first int [2] in x.
The alternative is to create some pointers-to-int to point at:
int x[2][2] = { 0, 1, 2, 3 };
int *y[2] = { x[0], x[1] };
int **p = y;
Now p points at y[0], which is the first int * in y. y[0] in turn points at x[0][0], and y[1] points at x[1][0].
Using the pointer notation you can do this
*(p + n) will return back a value in the subscript n which is equivalent of
p[n], a "single dimension array"
*( * (p + i) + j) will return back a value in the subscripts i and j which
is equivalent of p[i][j], a "double dimension array"
This will prove that using array subscripts [] decays into pointers as per the rule - see ANSI C Standard, 6.2.2.1 - "An array name in an expression is treated by the compiler as a pointer to the first element of the array", furthermore, ANSI C Standard 6.3.2.1 - "A subscript is always equivalent to an offset from a pointer", and also ANSI C Standard 6.7.1 - "An array name in the declaration of a function parameter is treated as a pointer to the first element in the array"
If you are not sure in understanding how pointers and arrays work, please see my other answer which will explain how it works...
Please ignore anyone who says arrays and pointers are the same - they are not...
No, there's no way to assign the array to an "int **", because a two-dimensional array is an array of arrays, not an array of pointers.
You could for instance do:
int x1[2] = {0, 1};
int x2[2] = {2, 3};
int *x[2] = {x1, x2};
int **p = x;
... and maybe that would be an acceptable equivalent to what you are trying to do (depending on what exactly that is of course!).
Update: If you must keep x as a two-dimensional array, you could also do: int (*p)[2] = x; which gives you a pointer-to-array-of-int.
There is no way to meaningfully initialize you variable p with x. Why? Well, there's no way to answer your question until you explain how you even came to this idea. The type of p is int **. The type of x is int[2][2]. These are two different types. Where did you get the idea that you should be able to assign one to the other?
If you really need to access elements of your x through a pointer of type int **, you have to do it indirectly. You have to create an additional intermediate array that will hold pointers to first elements of consecutive rows of array x:
int *rows[2] = { x[0], x[1] };
and now you can point your p to the beginning of this intermediate array
int **p = rows;
Now when you assess p[i][j] you get x[i][j].
There's no way to do it directly, without an intermediate array.
If you are really using c++ instead of c, you can get this effect by using std::vector (or some other collection type).
typedef std::vector<std::vector<int> > intmatrix;
intmatrix x;
intmatrix::iterator p = x.begin();
or some such.
It's all about Standard Conversion rule ($4.2)
An lvalue or rvalue of type “array ofN
T” or “array of unknown bound of T”
can be converted to an rvalue of type
“pointer to T.” The result is a
pointer to the first element of the
array.
The type of od and td respectively are
char [3]
char [1][3]
This means that od has type 'array of 3 chars' (N = 3, T = char).
So in accordance with the above quote, it can be converted to 'pointer to char'
Therefore char *p = od; is perfectly well-formed
Similarly the type of od is 'array of 1 array of 3 chars' (N = 1, T = array of 3 chars).
So in accordance with the above quote, it can be converted to 'pointer to array of 3 chars'
Therefore char (*p)[3] = td; is perfectly well-formed
Is there a way to be able to assign to
**p the x[][]?
No. Because type of td[x][y] for valid x and y is char. So what you can really do is char *pc = &td[0][0].