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 :
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 .
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.
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.
Related
I was learning how to find the length of an array and I'm baffled by this solution. I tried to find an explanation online but there seems to be none.
int arr[5] = {5, 8, 1, 3, 6};
int len = *(&arr + 1) - arr;
cout << "The length of the array is: " << len;
The memory address of the array is the same as the memory address of the first element, and when you add to or subtract from a pointer, it is done by the size of the type it points to, so:
arr refers to int, and &arr refers to int[5].
&arr+1 increments the memory address in the size of five integers.
If you do (&arr+1)-arr you get a compile error, because they are different types.
If you do (&arr+1)-&arr you get 1, because the offset of the memory address is the same as one size of int[5].
Therefore, when you do *(&arr+1), you get the same memory address but pointing to int and not int[5]. Now you wont get a compile error, because both pointers point to int and you get the offset of the memory address in terms of int size, and not int[5].
Memory addresses and types are quite difficult to explain sometimes, I hope I made it clear. Here you have some code you can run to see some of the concepts mentioned:
int arr[5] = {5, 8, 1, 3, 6};
int len = *(&arr + 1) - arr;
cout << "arr: " << arr << endl;
cout << "arr + 1: " << arr+1 << endl;
cout << "&arr: " << &arr << endl;
cout << "&arr + 1: " << &arr+1 << endl;
cout << "*(&arr + 1): " << *(&arr+1) << endl;
// cout << "&arr + 1 - arr: " << &arr+1-arr << endl;
// error: invalid operands of types ‘int (*)[5]’ and ‘int [5]’ to binary ‘operator-’
cout << "The length of the array is: " << len;
The type of the array arr is int[5], the type of &arr is int(*)[5]. (&arr + 1) increases the array address on sizeof(int[5]) as it's done by the rules of the pointer arithmetic, i.e. computes the address after the array. *(&arr + 1) is int[5], an array right after arr, where arr[5] would place. The both arguments of the substractions decay to int*. The substraction of pointers to int gives 5.
This may be considered as undefined behavior, since substraction of pointers belonging to different object storages is not defined. Also results of expressions with pointers addressing unallocated memory (like the (&arr + 1)) are undefined.
First, the traditional way to get the size of an array is sizeof a/sizeof *a. C++11 adds std::extent<decltype(a)>::value. There is of course no way to get an array’s size from just a pointer to it, as in
void f(int x[]) {/* no size here */}
Since an array is not a suitable operand to -, the array-to-pointer conversion occurs for the right-hand operand, producing an int*. Both operands must be of this type for the subtraction to result in a number of ints. &arr is of course a pointer to the array (of type int(*)[5], which conveys the size), and so therefore is &arr+1. Adding a * (or, equivalently, writing (&arr)[1]) produces an lvalue that supposedly refers to “the next array after arr”, which itself decays to a pointer that works with -.
However, as the indexing form indicates, this involves referring to an array that does not exist and is thus undefined behavior.
I'm trying to modify a variable by a pointer, the problem is that they have the same address but the output is not right.
Here's the code:
int *ret;
int set = 56;
ret = (int *)&ret - 1;
*ret = 3;
cout << ret << endl << &set << endl << set <<endl;
The output is:
0x61ff08
0x61ff08
3
This look great, but what is really weird is that when I replace:
cout << ret << endl << &set << endl << set <<endl;
With this:
cout << ret << endl << set <<endl;
The output becomes:
0x61ff04
56
The pointer change of value and the set variable isn't modified though. It's like if I take out the &set of the cout the address pointed of the pointer exchange his address with the variable.
If I do this:
ret = (int *)&ret + 1; // instead of -1
The output becomes:
0x61ff0c
3
Can I have an explanation? I didn't find any documentation about this.
Can I have an explanation? I didn't find any documentation about this.
Main documentation in this case is C++ standard, though it is sometimes not to easy to find and comprehend information from there. So short version in your case - you can only subtract or add integers to a pointer when resulting pointer would point to an element in the same array or pointing to the fictitious element behind the last (in this case it is illegal to dereference your pointer). For this purpose single variable is treated like one element array (so for pointer to single variable you can basically only do pointer + 1). All other hacky tries to access variables through magic with pointer arithmetics are illegal and lead to Undefined Behavior.
Details about UB you can find here What exactly do "IB" and "UB" mean?
The answer was that the compiler is giving address by he's own way to the variable/pointers according to the code so the addresses can change, to fix this problem by only using addresses
instead of :ret = (int *)&ret - 1;
we can use :ret = (int *)ret - ((int)(ret - &set));
(i didn't want to use the basic ret = &set because i was trying to do it by manipulation only addresses)
This question already has answers here:
C pointer to array/array of pointers disambiguation
(13 answers)
Closed 8 years ago.
I have read the pointer to array c++
and have some experiment on it.
#include <iostream>
using namespace std;
int main()
{
int g[] = {9,8};
int (*j)[2] = &g;
int *i = g;
int n = (*j)[0];
int m = *(i + 0);
cout << "n:" << n << endl;
cout <<"m:" << m << endl;
cout << "=============" << endl;
cout << "*(j):" << *(j) << endl;//9's address ???
cout << "j:" << j << endl;//9's address ???
cout << "&j:" << &j << endl;//what it is???
cout << "&(*j)" << &(*j) << endl;//9's address ???
cout << "=============" << endl;
cout << "*(i):" << *(i) << endl;//get the value pointered by i
cout << "i:" << i << endl;//i's value store g's address
cout << "&i:" << &i << endl; //i's address
cout << "&(*i):" << &(*i) << endl;//9's address
cout << "=============" << endl;
cout << "*(g):" << *(g) << endl;//get the value pointered by g
cout << "g:" << g << endl;//g's value store 9's address
cout << "&g:" << &g << endl;//9's address???
cout << "&(*g):" << &(*g) << endl;//9's address
return 0;
}
The result is :
n:9
m:9
=============
*(j):0x7fff56076bbc
j:0x7fff56076bbc
&j:0x7fff56076bb0
&(*j)0x7fff56076bbc
=============
*(i):9
i:0x7fff56076bbc
&i:0x7fff56076ba8
&(*i):0x7fff56076bbc
=============
*(g):9
g:0x7fff56076bbc
&g:0x7fff56076bbc
&(*g):0x7fff56076bbc
[Finished in 0.3s]
What I want to ask is:
1.Why
int (*j)[2] = &g;
int *i = g;
if I change either one &g to g, or g to &g, it will give a compile error, what is the difference?
(I think that the array name is a pointer, so why cannot I use int (*j)[2] = g and what is the meaning of &g, it is a pointer already, why get address again?)
2.
Since the &g and g, their address are the same, why cannot be exchanged?
3.
Why the &g's value is 9's address? Is it store its own address?
4.
Can you explain the j variable part?
I cannot understand why j stores the 9's address and *(j) gets the 9's address, &(*j) gets the 9's address too?
I am very confused about it now. What I totally understand is about the i variable part,
g variable part is confused about the &g, and the j varialbe part is all confused.
The int (*j)[2] = &g; part is confused too.
You can have a look at this post to understand why g and &g hold the same address:
How array name has its address as well as its first element in it?
The compiler complains when you change either of g to &g because there is a type mismatch. This means that semantically, g and &g have different meanings, even though they may refer to the same thing: g, when used in an expression, decays into pointer to int (int *), but &g is of type pointer to array of 2 ints. These are not compatible types; you can't assign a pointer to an array of ints to something that is a pointer to int (and the same happens the other way around).
Your claim that g is already a pointer is wrong: g is an array. When used in an expression, it decays into a pointer to the array's first element. A pointer is just something that holds an address; an array is an address (the address of its first element). With &g, you get a pointer to an array, you don't get pointer to pointer because arrays do not decay into pointers when the referencing operator is used. Think of it like this: if an array is an address, then applying the "address of" operator - & - yields this same address, which is, by convention, the address of the first element. When you don't apply the & operator, in an expression, the array decays into a pointer to the first element, and then again - it points to the first element, the same address as &g.
g is the variable (in this case array), &g is the address of the variable (in this case the address of the beginning of the array. You might understand that, but the compiler does not, and thus it's giving you an error.
They probably could be exchanged, if you were willing to do type-casting, but that's not a really good idea in this case.
Because g is the array of integers, and the address of the first (0-th) element of that array just happens to be the address of the whole array. Doesn't it make sense?
j in your case is a pointer to the array, of course it is also a pointer to the address with the 0-th element of that array (by definition)
(*j)[2] is pointer to array of 2 integers. In other words it is (almost) equivalent with pointer to pointer to ints. The line int (*j)[2] = g; tries to assign int* to (int**) which is a type mismatch. The line int *i = &g; tries to assign int** to int* which is again a type mismatch.
(I think that the array name is a pointer, so why cannot I use int (*j)[2] = g and what is the meaning of &g, it is a pointer already, why get address again?)
The address of what? In its type checking C++ distinguishes address of variables of different types, so even though int* and int** are both addresses (pointers) they point to different types.
I want to check how pointer address will be changed when I'm increasing/decreasing pointer value.
My code is:
void pointers_plus_minus()
{
char *c = (char *) 0x7fff80ccd35c;
int *i = (int *) 0x7fff80ccd35c;
c++;
i++;
cout << "char pointer" << c << endl;
cout << "int pointer" << i << endl;
}
But this code gives me Segmentation fault (core dumped).
I understand that something wrong with address, but it's not clear what. How to fix it? I'm using 64bit Ubuntu.
You can't operate on pointers like they are integers (well, not outside well-defined contexts).
You're only allowed to do c++ and i++ if the pointers point inside an array which you own.
Oops, I think this is actually well-defined because 1 element is treated as an array of 1, and you're allowed to go past the end of an array by one element. Reading from that pointer is still undefined though.
Regardless, although undefined, the crash is probably because cout << c attempts to print out a string, not a pointer. Cast it to void*:
cout << "char pointer" << static_cast<void*>(c) << endl;
Although this will satisfy your curiosity, which is good, it's still undefined and shouldn't do it.
You asked how to assign a constant address to a pointer, but doing so (a) is horrendously non-portable, and (b) doesn't necessarily serve your purpose, which is to see the effect of incrementing a pointer.
Here's a program that may satisfy your curiosity without possibly blowing up due to undefined behavior:
#include <iostream>
int main() {
const int len = 10;
char char_array[len];
int int_array[len];
char *cp = char_array;
for (int i = 0; i <= len; i ++) {
std::cout << "cp = " << static_cast<void*>(cp) << "\n";
cp ++;
}
std::cout << '\n';
int *ip = int_array;
for (int i = 0; i <= len; i ++) {
std::cout << "ip = " << static_cast<void*>(ip) << "\n";
ip ++;
}
}
The output on my (64-bit) system is:
cp = 0x7fffaa5ddc30
cp = 0x7fffaa5ddc31
cp = 0x7fffaa5ddc32
cp = 0x7fffaa5ddc33
cp = 0x7fffaa5ddc34
cp = 0x7fffaa5ddc35
cp = 0x7fffaa5ddc36
cp = 0x7fffaa5ddc37
cp = 0x7fffaa5ddc38
cp = 0x7fffaa5ddc39
cp = 0x7fffaa5ddc3a
ip = 0x7fffaa5ddc00
ip = 0x7fffaa5ddc04
ip = 0x7fffaa5ddc08
ip = 0x7fffaa5ddc0c
ip = 0x7fffaa5ddc10
ip = 0x7fffaa5ddc14
ip = 0x7fffaa5ddc18
ip = 0x7fffaa5ddc1c
ip = 0x7fffaa5ddc20
ip = 0x7fffaa5ddc24
ip = 0x7fffaa5ddc28
Some notes on this:
The pointer increments are valid because each pointer points to an element of an array of the proper type, or just past the end of it, at all times. (You're allowed to construct a pointer just past the end of an array; you're not allowed to dereference such a pointer.)
The output produced when print a pointer of type void* is implementation-defined. On my system, it happens to be a hexadecimal representation of the pointer value, interpreted as if it were an integer -- which is probably the most common way it's done.
You can see that the char* pointer appears to be incremented by 1 each time, and the int* pointer by 4. On my system (and probably yours), pointers are stored as byte addresses. Pointer arithmetic is defined in units of the pointed-to type, not in terms of bytes. Incrementing an int* pointer causes it to point to a memory location sizeof (int) bytes after the previous location -- in this case, 4 bytes. All pointer arithmetic is defined this way; ptr2 - ptr1 gives you the number of elements (of whatever type ptr1 and ptr2 point to) between the two addresses.
The specific values printed tell you something about how memory addresses are managed on your system. The mapping between pointers and integers will generally reflect the system's memory model. That model is largely implementation-specific.
Seg faults, my favorite error messages next to stack overflows, are when you've tried to write to an illegal memory space. That said, how can you guarantee that when your program has been loaded into memory that your stack/heap space falls within the area you are trying to reserve, and more so why would you even want to do this? This is something that can probably be done in Assembly since you have much lower access to the hardware, but I seriously doubt it can be done (or should be done if you can) in C.
This is going to be a long-winded post, so I apologize in advance.. but trying to ask multiple questions with context:
So, I've been trying to learn C++, and I've been picking everything up fairly easily, but I make a habit of trying to do things alongside the tutorials in "slightly different ways", in order to ensure that I understand the functionality of the thing I'm learning.
I seem to have hit a mental roadblock regarding constants and their involvements with pointers.
In the previous section, I think I got a pretty solid grip on references, dereferences (and the difference between * when used for dereferences and pointers), and then wrote this code:
int a[5];
int * p;
p = a;
cout << "Select the value for the first item at address(" << &a[0] << ")" << nl;
cin >> *p;
p++;
cout << "Select the value for the second item at address(" << &a[1] << ")" << nl;
cin >> *p;
p++;
cout << "Select the value for the third item at address(" << &a[2] << ")" << nl;
cin >> *p;
p++;
cout << "Select the value for the fourth item at address(" << &a[3] << ")" << nl;
cin >> *p;
p++;
cout << "Select the value for the fifth item at address(" << &a[4] << ")" << nl;
cin >> *p;
for (int n=0;n<5;n++)
cout << a[n] << "(" << &a[n] << ")" << nl;
Now, I realize that this isn't necessarily the most "optimized" solution, ever.. but it worked, I was able to "write" into the array I had store on the memory, and display the changes. It was neat, and like I said.. I think I got a pretty good understanding of how these things worked.
..and then, I hit the next section, which used the example:
const char * terry = "hello";
to teach me, and I quote: "As in the case of arrays, the compiler allows the special case that we want to initialize the content at which the pointer points with constants at the same moment the pointer is declared" (this being on the cplusplus.com tutorial).
Anyway, to get to the point: in order to try and familiarize myself with it and the previous section, I tried writing:
const char * p = "Hello.";
for (int n=0;n<5;n++)
cout << p[n] << "(" << &p[n] << ")" << nl;
cout << nl;
..and this does not work. I essentially tried replicating my previous code (although without the writing aspect) in an attempt to be able to read the RAM-location of each character in this constant array, and I experimented with every possible combination of pointers, references, dereferences, etc.. but I just get a print out of the whole "Hello." array with &p.
How in the hell does one get the reference of a constant array? I think I understand the basic premise that I'm creating an array and immediately allocating it to memory, and then assigning a pointer (p) to the first block ("H")'s location.. but I can't seem to print the blocks out. I was able to get the location of the first block to print at one point (can't remember what code I used to do this) and tied it into the for loop, but even then.. it just ALWAYS printed the location of the first block, even when assigned to follow the [n] count.
I have no idea what I'm missing, here, or if I'm just trying to reach "over my head", but maybe I just don't understand the usage/point of creating an array without being able to location the memory assignment of each item within it..
This brings me to my next issue, though. How does one get the memory location of a char variable, whether constant or not? I have been having issues with this code, as well:
char const a = 100;
int * b = &a;
cout << a << nl << *b << nl;
cout << nl;
Obviously, this doesn't work.. because I can't assign b to the location of a, since they're different variables.. and obviously making a char pointer is silly, since it's just going to print messed up/null characters instead of the location (I checked this, obviously.. not just assuming).
I hope I'm just missing an option to use which may just be "more advanced" than where I'm currently at.. but if I'm not, I don't quite see the point in being able to access the block location of any type of variable/constant, if you can't access ALL of them due to restrictions of the type being used.
This problem is sorta what limits the third quoted code, too: the fact that I can't just assign a variable to hold the &p value, since it itself would have to be a char to be compatible.. which is pointless since char can't hold the eight-digit reference.
In
const char * p = "Hello.";
[...] cout << &p[n] [...]
&p[n] is a pointer to char, and cout::operator<< has an overload that takes a pointer to a char and prints a null-terminated string, that's probably why you're confused.