This question already has answers here:
What is array to pointer decay?
(11 answers)
Closed 7 years ago.
I saw this code in this link-http://www.tutorialspoint.com/cplusplus/cpp_pointers_vs_arrays.htm. Look at the first piece of code.
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr;
// let us have array address in pointer.
ptr = var;
for (int i = 0; i < MAX; i++)
{
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// point to the next location
ptr++;
}
return 0;
}
Shouldn't it be ptr = &var instead of ptr = var? It is below the comment. Why is it declared simply asvar instead of &var?
var will decay into a pointer to its first element.
ptr = var;
is equivalent to
ptr = &var[0];
&var is a pointer to an array, not to an int.
int (*aptr)[MAX] = &var;
would be valid, but it doesn't mean the same - *aptr is an array with MAX elements, not an int.
The tutorial's claim that "pointers and arrays are interchangeable in many cases" is completely wrong.
The only time you can "interchange" anything is this case; when something expects a pointer, an array decays into a pointer to its first element.
There is not a single case where you can use a pointer in place of an array.
Confusingly, ptr is often called "a pointer to an array" or even "an array" in informal conversation, even though this is formally incorrect.
This is because "a pointer to the first element of an array" is quite a mouthful, and to a non-beginner it's usually clear from context what is actually meant.
An array "decays" to a pointer to its first element in assignments, parameter passing etc. That would be a pointer to int, which is what p is declared as.
You actually can take the address of the array, although it is much less common. The address then is the address of the whole array, like this:
int (*parr)[3] = &var;
Now cou can say, for example, int i = (*parr)[1]; to initialize i with the second element of var, 100.
The address of the whole array is numerically identical with the address of its first element because the first element is where the array starts, after all. That may seem funny: What's the point then?
The difference is in type, which (apart from mere grammar questions about type compatibility -- but you can always cast those away in C!) determines what happens when you do pointer arithmetics. Consider
int *ptr = var;
int (*parr)[3] = &var;
printf("ptr: %p, parr: %p\n", ptr, parr);
printf("Increment ptr: %p, incremented parr: %p\n", ptr+1, parr+1);
Related
This question already has answers here:
What is array to pointer decay?
(11 answers)
Passing the address of an array into a function in C++
(3 answers)
Why do the following have the same value: the pointer to an array, the dereferenced pointer to the array?
(3 answers)
How come an array's address is equal to its value in C?
(6 answers)
Closed 9 months ago.
I am a beginner to data structures and algorithms, started studying the pointers now and before asking the question here I read this recommended post but I couldn't understand it so I am asking the query here.
I have been told by a friend that array's name is a pointer to the first value in the array, as arr returns the address of arr[0], arr+1 returns address of arr[1], so when I write this
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i = 10;
int arr[3] = {1, 2, 3};
int *ptr = &i;
cout << arr << " " << &arr << endl;
cout << ptr << " " << &ptr;
return 0;
}
Both arr and &arr give same result
0x61ff00 0x61ff00
While ptr and &ptr give different results
0x61ff0c 0x61fefc
Can someone tell me why is this happening ?
Arrays are not pointers!
Arrays do decay to a pointer to their first element in all sorts of circumstances. For example std::cout << arr; actually prints the memory address of the first element of the array. std::cout << &arr; prints the memory address of the array. As the address of the first element is the same as the address of the array you see the same value.
However, just because they have the same value, does not mean they are the same. arr can decay to a int*, while &arr is a pointer to an array, a int(*)[3].
I hope the following will help to clear things up a little:
#include <iostream>
#include <type_traits>
void make_it_decay(int x[]) {
std::cout << std::is_same_v< decltype(x), int*> << "\n";
}
int main() {
int arr[3] = {1,2,3};
//std::cout << (arr == &arr) << "\n"; // does not compile !
std::cout << (arr == &(arr[0])) << "\n";
std::cout << std::is_same_v< decltype(arr), int[3]> << "\n";
std::cout << std::is_same_v< decltype(&arr),int(*)[3]> << "\n";
std::cout << std::is_same_v< decltype(&arr[0]), int* > << "\n";
make_it_decay(arr);
}
output:
1
1
1
1
1
I use decltype to infer the type of certain expressions and std::is_same_v to see if the expressions are of same type.
arr is of type int[3]. It is an array. It is not a pointer.
&arr is the address of the array. It is a pointer to an array with three elements, a int(*)[3].
&arr[0] even though it has the same value as &arr is of different type. It is a pointer to int, an int*.
When we pass arr to a function then it decays to a pointer to the first element of the array. And we can see that inside the function x is int*.
Now to your quesiton...
Above I tried to lay out what happens when you write std::cout << arr. Pointers are different, because ... well arrays are not pointers.
std::cout << ptr; // prints the value ptr
std::cout << &ptr; // prints the address of ptr
Perhaps some visualization helps. The difference in types gets most apparent when incrementing the pointers
-------------------
| arr |
-------------------
| 1 | 2 | 3 |
-------------------
^ ^ ^
&arr | &arr + 1
&arr[0] |
&arr[0] + 1
array's name is a pointer to the first value in the array
The above statement is not technically correct. What happens is that in many contexts the array decays to a pointer to its first element due to type decay. This means, in your example, when you wrote std::cout << arr, there was an implicit array-to-pointer conversion which converted your array arr of type int[3] to a pointer to its first element which is the type int*.
Note
Note also that even though the decayed pointer and the address of the array both have the same value their types are different. The decayed pointer is of type int* while the &arr is of type int (*)[3].
Can somebody explain to me why this code works?!!
I know A holds &A[0] and it is not a real pointer as if you cout<<&A you would get &A[0], but this result looks very strange to me.
int main()
{
double A[] = {2.4, 1.2, 4.6, 3.04, 5.7};
int len = *(&A+1) - A; // Why is this 5?
cout << "The array has " << len << " elements." << endl;
return 0;
}
And why this code doesn't work? And how can you make it work?
void test(double B[])
{
int len = *(&B+1) - B;
cout << len << endl;
}
int main()
{
double A[] = {2.4, 1.2, 4.6, 3.04, 5.7};
test(A);
system("pause");
return 0;
}
The expression is parsed like this:
(*((&A) + 1)) - A
The probably vexing part is that for some (but not all!) parts of this expression, the array decays to a pointer to the first element. So, let's unwrap this:
First thing is taking the address of the array, which gives you a pointer to an array of five elements.
Then, the pointer is incremented (+ 1), which gives the address immediately following the array.
Third, the pointer is dereferenced, which yields a reference to an array of five elements.
Last, the array is subtracted. It is only here that the two operands actually decay to a pointer to their first elements. The two are the length of the array apart, which gives the number of elements as distance.
&A takes the address of A itself. The type of A is double[5].
When you take the address of A itself and increment that pointer by 1, you are incrementing it by sizeof(double[5]) bytes. So now you have a pointer to the address following the A array.
When you dereference that pointer, you have a reference to the next double[5] array following A, which is effectively also a double* pointer to the address of A[5].
You are then subtracting the address of A[0] (an array decays into a pointer to its first element), and standard pointer arithmetic gives you 5 elements:
&A[5] - &A[0] = 5
Hello i'm a noob in programming, i have a small doubt regarding pointers
#include<iostream>
using namespace std;
int main()
{
int myAge = 16;
int* agePtr = &myAge;
cout << "address of pointer" << agePtr << "Data at memory address" << *agePtr << endl;
int badNums[5] = {4, 13, 14, 24, 34};
int* numArrayPtr = badNums;
cout<< "address" << numArrayPtr << "value" << *numArrayPtr << endl;
numArrayPtr++;
cout<< "address" << numArrayPtr << "value" << *numArrayPtr << endl;
return 0;
}
In the first case while pointing an integer i use &myAge where as in
the second case of incrementing Arrays if i use &badNums the compiler
is returning an error, but if i use badNums its compiling why should
we use badNums instead of &badNums in the second case?
how can I increment the value in integer using pointers?
Arrays implicitly decay to pointers, as per the rules of c++. There are many implicit conversions in c++, this is one of them. When assigning an array to a pointer, it provides you with a pointer to the first element in the array.
Taking the address of an array (&badNums) will yield a pointer to the array, not to the first element. Array pointers are slightly more complicated and encode the size of the array in the type. The correct type for that assignment would be int (*numArrayPtr)[5] = &badNums; where numArrayPtr is a pointer to an array of 5 ints.
To increment a value pointer to by a pointer, you must first dereference that pointer using operator * just like if you wanted to read from or write to that value. It would look like (*numArrayPtr)++;.
In the first case, using &myAge refers to the address of that integer value. The reason why you must use badNums instead of &badNums when doing assignment to the integer pointer is because badNums is already an integer pointer. Arrays implicitly decay into pointers, so using &badNums in that assignment would work if you were doing:
int **numArrayPtr = &badNums;
which is just a pointer to a pointer to the address of badNums. So,
int *numArrayPtr = badNums;
just means that we have a pointer to the address of badNums.
When we have an integer pointer like this, you can increment the value of each integer in the array by doing this:
for (int i = 0; i < 5; i++){
numArrayPtr[i]++;
}
or, we can do the same thing without using array notation:
for (int *i = numArrPtr; i != numArrPtr + 5; i++){
(*numArrPtr)++;
}
I hope that answers your questions fully.
I have a small doubt regarding pointers
Just like i in badnums[i] is an index within array badnums[], a pointer is an index to something stored in memory. Since any variable is stored in memory, you can access the contents of a variable with a pointer to whatever it contains (which is what languages implicitly do when using variables in your code).
The difference is that with pointers you must know the type of what the pointer designates, while an index uses the known type of the indexed elements of the variable it points to... because sooner than later you will iterate the contents of some known variable using a pointer.
To fully understand how pointers, values, and references work, I am making a basic C++ program that attempts to tamper with some static and dynamic arrays and understand exactly how they should be passed in.
First I generate a static array of 3 elements. I then pass it into a function that modifies all elements. I then pass it into another function with a slightly different signature, but can also alter the array's values.
Next I generate a dynamically sized array, pass it into a function by reference so that all of the values in this dynamically sized array can be altered.
The code is as follows:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
void changeIndexStaticArrayMethod1(int* stat);
void changeIndexStaticArrayMethod2(int (&stat)[3]);
void changeIndexDynamicArrayMethod1(int* dyn, int size);
int main() {
const int MAX = 3;
int arr[MAX] = { 1,2,3 };
changeIndexStaticArrayMethod1(arr);
cout << arr[0] << endl;
cout << arr[1] << endl;
cout << arr[2] << endl;
cout << endl;
changeIndexStaticArrayMethod2(arr);
cout << arr[0] << endl;
cout << arr[1] << endl;
cout << arr[2] << endl;
int SIZE;
cout << "Please choose a size for the array" << endl;
cin >> SIZE;
int *ne = new int[SIZE];
//Build array
for (int i = 0; i < SIZE; i++) {
ne[i] = i;
}
changeIndexDynamicArrayMethod1(ne, SIZE);
for (int i = 0; i < SIZE; i++) {
cout << "ne[" << i << "] = " << ne[i] << endl;
}
//To hang program
cin >> SIZE;
delete[] arr;
delete[] ne;
return 0;
}
void changeIndexStaticArrayMethod1(int* stat) {
stat[0] = 10;
stat[1] = 20;
stat[2] = 30;
}
void changeIndexStaticArrayMethod2(int (&stat)[3]) {
stat[0] = 40;
stat[1] = 50;
stat[2] = 60;
}
void changeIndexDynamicArrayMethod1(int* dyn, int size) {
for (int i = 0; i < size; i++) {
dyn[i] = i * 10;
}
}
All of the above code works how I want it to, I just have a few questions as to why (some of the methods of passing arrays by reference I have found on other SO questions).
In the changeIndexStaticArrayMethod1() and changeIndexDynamicArrayMethod1() functions, why are we able to use the dereference * operator for our array as reference? My knee jerk reaction is seeing that as practically passing the array in by values since it is the dereference operator. I know that with arrays, it is much different than using variables, but also, why will the following not work for single int variables:
void changeStaticNumber(int* num){
num = 100;
}
Obviously the above will work if we use &num and not int* num, and obviously I don't fully understand the relationship between pointers and arrays, but I cannot figure out why when we pass an array by reference, int* staticArray is ok.
Any explanation for these problems I am having would be much appreciated. Thanks.
why are we able to use the dereference * operator for our array as reference?
The * in C means many things. It can mean the unary indirection ("contents of") operator, it can mean the binary multiplication operator and it can mean a pointer declaration. The int* stat is a pointer declaration.
Since you aren't using the * to dereference the contents of the pointer inside that function, I'm not quite sure what you are asking.
When you take the array name of your array in main(), it "decays" into a pointer to the first element. So what those function do, is to take a pointer by value. If you dereference the pointer by typing *stat = something; you access the actual array in main.
Should you do something weird like changing the pointer itself, for example stat++;, then it will not affect the address used in main. You passed the pointer itself by value, so the pointer is a local copy.
My knee jerk reaction is seeing that as practically passing the array in by values since it is the dereference operator.
You can't really pass arrays by value in C or C++, without resorting to dirty tricks (storing them inside structs or classes). For example, had your function been written as void changeIndexStaticArrayMethod1(int stat[3]) it would still give you a pointer to the first element. It will not pass an array by value, as the syntax might trick you into believing.
why will the following not work for single int variables:
void changeStaticNumber(int* num){ num = 100; }
Because num is the pointer itself, not its contents. In order to write code like that, you could pass the variable by reference int& num. Behind the lines this is really the same thing as passing a pointer, just with simplified syntax.
To understand the relation between pointers and arrays better, start by reading this whole chapter: http://c-faq.com/aryptr/index.html (C and C++ are identical when it comes to pointers).
Let me see if I can take a stab at this.
Pointers are simply address holders. Once you do int * ptr = myarray; --- what you are in tern doing is storing the address of the pointer my array into ptr --- array names are actually pointers to the first memory location in the array. You can use pointer arithmetic to get at everything else for example myarray +1 will point you to the next location or myarray[1].
Passing by value is not very useful when you need to modify your array. Passing in by reference is essentially making a pointer to the array and passing that. Since arrays like vectors are contiguous blocks of memory you can index through them rather easily.
As far as your example goes void changeStaticNumber(int* num){ num = 100; } will not work because what you are attempting to do is store 100 into the pointer's address. If you deference num and make it void changeStaticNumber(int* num){ *num = 100; } it will work because you are actually going one step further and accessing the data that num is pointing to. When you use &num it is essentially the same thing - & just gives you the address of something.
For example if you want to point a pointer to an int what you would do is
int num = 5;
int *ptr = #
at this point in time ptr has the same address in num. To print out the data in num or that ptr is pointing to you need to dereference or go one step further as I like to tell myself and dereference to so cout << *ptr;
In both changeIndexStaticArrayMethod1 and changeIndexDynamicArrayMethod1 you are not passing an array there is no pass by reference (which only happens if the parameter type is a reference type -- i.e. with &). The parameter has type int * (pointer to int). You are passing a pointer to int by value. There is no "dereference operator" in either function.
ne is already an int *, so passing it is nothing special. arr is an int [3], an array, not a pointer. In C, when an array-of-T is used in a context that expects a pointer-to-T, it is implicitly converted (without you needing to do anything) to a pointer to its first element. So when you do, changeIndexStaticArrayMethod1(arr), the compiler gets a pointer to the first element of arr, and passes that to the function.
The [] operator works on pointers. a[i] is always guaranteed to be the same as *(a + i). Inside both the changeIndexStaticArrayMethod1 and changeIndexDynamicArrayMethod1 functions, [] is used to access subsequent elements using a pointer to the first element.
In "void pointers" example in the tutorial on cplusplus.com, I try to compare like following. Why do we still need * in parenthesis? What is happening when no *?
void increase(void* data, int psize) {
if (psize == sizeof(char)) {
char* pchar;
pchar = (char*) data;
cout << "pchar=" << pchar << endl;
cout << "*pchar=" << *pchar << endl;
//++(*pchar); // increases the value pointed to, as expected
++(pchar); // the value pointed to doesn't change
} else if (psize == sizeof(int)) {
int* pint;
pint = (int*) data;
//++(*pint); // increases the value pointed to, as expected
++(pint); // the value pointed to doesn't change
}
}
int main() {
char a = 'x';
int b = 1602;
increase(&a, sizeof(a));
increase(&b, sizeof(b));
cout << a << ", " << b << endl;
return 0;
}
Update after accepting solution) I try to make clear what I didn't get, based on #Cody Gray's answer. The address of pchar is incremented to point to nonsense location. But because variable a in main is coutted instead of pchar, this cout still prints a value that somewhat makes sense (in this example it would be 'x').
The * operator dereferences the pointer.
Therefore, this code:
++(*pint)
increments the value pointed to by pint.
By contrast, this code:
++(pint)
increments the pointer itself, pint. This is why the value pointed to by the pointer doesn't change. You're not changing the value pointed to by the pointer, but rather the value of the pointer itself.
Incrementing a pointer will cause it to point to an entirely different value in memory. In this case, since you only allocated space for a single integer, it will point to a nonsense value.
When you make a cast from pointer to other pointer
char* pchar;
pchar = (char*) data;
you telling to compiler to process this memory as char pointer, in which you could perform pointer arithmetic to this variable. Therefore, you are not working with the value of the pointer just with pointer, that's is a memory address in which you are making the arithmetic.
To work with the value you need to use "*" or access to memory pointer by the char.