Related
int var = 100;
cout << (int*)var<< endl;
cout << &var<< endl;
(int*)var printed just 100 in hex, which I don't quite understand. Can you explain why it is doing so?
I would like to know other ways of pointing to an address without creating a complete new pointer variable.
What you have just written does not make sense. First you say:
int var = 100;
... but then you typecast the value of var into "a pointer to an int":
(int *)var
The only reason why it didn't crash-and-burn is that you did not actually try to use that pointer to access something in memory. But, cout was smart enough to realize, "say, the programmer says that this is a pointer." So it printed, in hex, the value of the pointer itself, not any data that the pointer was supposedly pointing at.
Just To Be Clear:
(int *)var does not mean "point to the address of a variable." (If you want "the address of something," albeit not "a pointer to the same", use &var). Instead, this is just a typecast, which in this case means: "treat the value of var as 'a pointer to an int'."
If * means pointing to the adress of a variable, then...
Does * mean "pointing to the adress of a variable" though? What do you think this means?
21 * 2
* means different things in different contexts. In a type name, it means that the type is a pointer. In an expression it is an operator. In case the operator is binary and operands are numbers, it means multiplication. In case the operator is unary and the operand is a pointer, it means indirection through that pointer.
(int*)var printed just 100 in hex, which I don't quite understand. Can you explain why is it doing so
This is how reinterpreting an integer to a pointer type typically works. The value was 100, and the value remained 100 when you reinterpreted it as a pointer.
Strictly speaking, the conversion isn't meaningfully defined for integer types that aren't large enough to represent all pointer values, so converting an int doesn't make sense.
I would like to know other ways of pointing to an adress without creating a complete new pointer variable.
You've shown a way how to do that: &var. That creates a pointer object pointing to var without creating a pointer variable. Another way to create a pointer prvalue is use this keyword in a member function, or call a function that returns a pointer.
Is there any way to find the address of a reference?
Making it more specific: The address of the variable itself and not the address of the variable it is initialized with.
References don't have their own addresses. Although references may be implemented as pointers, there is no need or guarantee of this.
The C++ FAQ says it best:
Unlike a pointer, once a reference is
bound to an object, it can not be
"reseated" to another object. The
reference itself isn't an object (it
has no identity; taking the address of
a reference gives you the address of
the referent; remember: the reference
is its referent).
Please also see my answer here for a comprehensive list of how references differ from pointers.
The reference is its referent
NO. There is no way to get the address of a reference.
That is because a reference is not an object, it is an alias (this means it is another name for an object).
int x = 5;
int& y = x;
std::cout << &x << " : " << &y << "\n";
This will print out the same address.
This is because 'y' is just another name (an alias) for the object 'x'.
The ISO standard says it best:
There shall be no references to references, no arrays of references, and no pointers to references.
I don't like the logic a lot of people are using here, that you can't do it because the reference isn't "guaranteed to be just a pointer somewhere anyway." Just as int x may be only a processor register with no address, but magically becomes a memory location when & x is used, it still may be possible for the compiler to allow what you want.
In the past, many compilers did allow exactly what you're asking for, eg
int x, y;
int &r = x;
&r = &y; // use address as an lvalue; assign a new referent
I just checked and GCC will compile it, but with a strongly worded warning, and the resulting program is broken.
No.
As Bjarne Stroustrup says in TC++PL, a reference can be thought of as just another name for an existing entity (object or function). While this is not always the most precise description of the underlying low-level mechanism that implements references, it is a very good description of the concept the references are intended to implement at the language level. Not surprisingly, the language provides no means to obtain the address of reference itself.
At language level reference is not guaranteed to occupy a place in storage, and therefore in general case it has no address.
Just use the '&' operator.
e.g :
int x = 3;
int &y = x;
cout<<&y<<endl;
This will return the address of x since y is nothing more than the address of x.
From another instance of this same question: $8.3.2/3 - "It is unspecified whether or not a reference requires storage (3.7).".
So the C++ standard allows the compiler/runtime implementor to choose whether or not a reference lives in a separate memory location. However note that if it does live in a separate memory location, you can't find its address in a standard-compliant manner. So don't do it.
If you take an address of a reference, by definition in the C++ standard, you will get the address of what it refers to, rather than the address of the reference, if in fact that reference even exists as a separate entity in the runtime environment or not.
Not reliably, as references don't have to have a unique location in addressable memory.
Not by itself. If you want its "address", shove it in a struct or class. Even then that isn't necessarily guaranteed to get you within the vicinity of what you probably want to do which is using a pointer. If you want proof, the sizeof of a reference is equal to the referent type. Try it with char & and see.
It is possible, but not strictly using C++. Since the reference is passed as a parameter of a function, its value will be stored on the stack or in a register. This is hardware architecture dependent. Access to these values will require inline assembly. Consult the reference manual for the processor you are using to determine stack behavior and register addresses. Corrupting the stack or registers can very easily cause BSOD, data loss, or even permanent damage to your system. Proceed with extreme caution.
If you implement a reference as a member of a struct, you then can get its address:
struct TestRef{
int& r;
int i;
TestRef(int& ref): r(ref){
}
};
The reference indeed a pointer (in my case using Xcode compiler) and you can update it's value to re-assign the reference to a new variable.
To do so we need to find out the address of the reference and trick it value to address of other variable
Now the address of the reference TestRef.r is the address of TestRef object.Because r is the first member of TestRef.
You can re-assign the reference by updating the value store in the memory of TestRef.r.
This code below shows that you can get address of reference and you and re-assign a reference to a difference variable. Note: my OS is X64 OS (I use Xcode MacBook Pro 2015, MacOs 10.15.1).
#include <iostream>
using namespace std;
struct TestRef{
int& r;
int i;
TestRef(int& ref): r(ref){}
};
int main(int argc, const char * argv[]) {
int i = 10;
int j = 11;
TestRef r(i); // r.r is reference to i
cout << r.r << " " << i << " " << j << endl; // Output: 10 10 11
int64_t* p = (int64_t*)&r; // int32_t in 32 bit OS;
// Note:
// p is the address of TestRef r and also the address of the reference r.r
// *p is the address of i variable
//
// Difficult to understand? r.r indeed a pointer to i variable
// *p will return the address inside the memory of r.r
// that is the address of i variable
// this statement is true: *p == &i
// ------>
// now we change the value of *p to the address of j
// then r.r will be the reference of j instead the reference of i
*p = (int64_t)&j; // int32_t in 32 bit OS;
cout << r.r << " " << i << " " << j << endl; // Output: 11 10 11
return 0;
}
So in fact you can work around to re-assign a reference, like a hacker.
If we have code:
int b = 10;
int* a = &b;
std::cout << a << " " << &a << " ";
As the result, the addresses are different.
But what's the meaning of address of a pointer?
A pointer has the value of a variable's address, since we have a varaible in memory. But we don't have the value of address stored in memory, so why we have the address of an address?
Maybe I have some misunderstandings, thank you for your help.
Remember an address on your machine is going to be, itself, a 32 or 64-bit value (depending on your system architecture).
In your example, you have the integer b that stores the value 10 in some address, let's call it address 500
Then you have a pointer a, which stores the value 500, and IT has its own address.
What's the point? You can actually have double-pointers (or more).
You understand that in
char* string = "hello";
string is a pointer to the beginning of an array of characters
Then
char** strings;
is a pointer to a char*. That's how you could do an array of arrays, for example.
std::cout << a << " " << &a<<" ";
Yes ,both are different .
1. a has been assigned address of b , so it prints address of b.
2. &a prints address of pointer a itself .
And a and b don't have same address.
It's similar(to understand) to this example -
int b=9;
If you print b you get its value i.e 9 but if you print &b you gets its address , and in no ways they will be same .
Same is the case with pointers.
A pointer has the value of a variable's address, since we have a variable in memory. But we don't have the value of address stored in memory, so why we have the address of an address?
We declare a variable (pointers , array , just int, char) these all are declared in program and are stored in memory . As these are stored in memory ,they have their unique address.
A pointer has the value of a variable's address
I assume by a variable you mean the object corresponding to the variable. Nonetheless, this is not strictly true, and it's the edgecases where we start to make distinctions between addresses and pointer values.
There are pointer values that don't point at objects at all. Consider null pointers, for example.
Addresses, by definition, do point at objects... or functions.
what's the meaning of address of a pointer?
The term address of a pointer makes sense if you can imagine a variable declared to store a pointer (e.g. T *var;) and you take the address of it (&var).
so why we have the address of an address?
An address is a type of pointer value, but pointer values don't point at values; they point at objects or functions. &a is different to a because the two pointers point at different objects; one points at a and the other points at b.
Thanks for you all I knew what's wrong with it.
In fact I created a pointer in memory by int* a = &b; but I thought I didn't so it's my mistake.
But what I thought that you cannot output the address of something that does not exist in memory like cout<<&(&a),the compiler will tell you that "&" operator need a l-value variable.
And if you want to output the address of pointer to a, you define a pointer to pointer variable int **p2p=&a, and then you can cout<<&p2p , it works.
I'm teaching myself C++, and as such have been writing some example code to really nail my understanding of pointers and arrays.
I have written this:
int myints[] = {20, 40, 60, 80, 100};
// C style array? should be stored on stack? is myint's type pointer to int or an array of int? how does it differ from myotherints?
int* myotherints = new int[5]{20, 40, 60, 80, 100}; // new always returns pointer, is this a C++ style array?
// does this pointer get created on stack while the elements themselves are created in free heap?
int j = 5; // should be stored on stack
cout << "myints: " << myints << endl; // decays to pointer, shows address array myints is stored at
cout << "*myints: " << *myints << endl; // myints decays to pointer and is dereferenced to return value stored at start of array myints
cout << "myints[0]: " << myints[0] << endl; // [] dereferences and returns value for element 0 (20)
cout << "myotherints: " << myotherints << endl; // some value?? this is totally unlike the others, why? what is this?
cout << "*myotherints: " << *myotherints << endl; // dereferences pointer myotherints to get address that holds value 20 for first element
cout << "myotherints[0]: " << myotherints[0] << endl; // [] dereferences pointer to get address that holds value 20 for first element
cout << "j: " << j << endl << endl; // 5, sure
cout << "&myints: " << &myints << endl; // array behaving as pointer, gives address of myints[0]
cout << "&myints[0]: " << &myints[0] << endl; // array behaving as pointer, gives address of myints[0]
cout << "&myotherints: " << &myotherints << endl; // address of myotherints, is this where the pointer to the array is stored?
cout << "&myotherints[0]: " << &myotherints[0] << endl; // [] dereferences the pointer that myotherints points to and returns element 0
cout << "&j: " << &j << endl; // address of j
/*
myints: 0x7fff096df830 <-- this makes sense to me, array decays to pointer to give first element address
*myints: 20 <-- this makes sense to me, dereference first element address for value
myints[0]: 20 <-- [] dereferences implicitly, returns value from pointer
myotherints: 0x2308010 <-- myotherints is a pointer to an array of ints, but its address is much lower compared to myints and j, why is that?
*myotherints: 20 <-- getting the value from above address returns 20
myotherints[0]: 20 <-- [] dereferences to address pointed to by pointer myotherints, returns value
j: 5
&myints: 0x7fff096df830 <-- same as below
&myints[0]: 0x7fff096df830 <-- same as above, meaning *myints and myints[0] are the same thing, this address
&myotherints: 0x7fff096df828 <-- how can the pointer to myotherints array be stored here when dereferencing it (*) returns 20 and...
&myotherints[0]: 0x2308010 <-- dereferencing this address with [] also returns 20, yet they are different memory locations unlike myints
&j: 0x7fff096df824
*/
Is it true to say that myints is a "C style array" while myotherints is a "C++ style array"?
If I'm understanding correctly, myotherints is a pointer yet myints is an array that most of the time behaves like a pointer? So while you can do pointerish things with myints, there are times when it does not behave like a pointer, namely using & to reveal its address. This means myints is of a different type to a pointer. Is its type "array of ints"?
Where is myints (the thing that is myints, not the values in its array) stored, and how can I reveal its address if it always automatically dereferences to the location the array is stored at unlike the pointer returned with the C++ style new array?
Are these represented in memory in a functionally different way?
Any tips or directions to documentation that can really solidify my understanding here would be much appreciated. Thank you!
Both are things inherited from C (The proper C++ array thing is std::array), but you are confusing things:
The first is a C array, that is, a thing with static/automatic storage duration which represents a block of memory. The size and "position" (Address) of that block is determined at compile-time.
The second is a pointer to a dynamically allocated memory block. In other words, you use a pointer to store the address of the memory block you requested to the OS. This is confusing for novices since this thing is sometimes called dynamic array. Is not an array in the same sense a C array is, but in practice we use both in the same way, but for different purposes.
Regarding C++:
C arrays behave like pointers to the memory block with some suggar (Array indexing, etc), so they are always passed by reference (Since which we have is the address passed by value, not the array itself), and in fact they decay automatically into pointers in many situations. These issues make std::array a much better alternative, since it has correct value semantics and no implicit decaying.
In C++ manual memory management should be avoided, you should use the containers the Standard Library provides (The best well known std::vector). The C++ language provides features for automatic, deterministic, and safe resource management; memory resources included. You should use these. Manual memory management is provided only for very low-level programming and creation of your own resource management handler.
C++ got type decay from C.
In C there are few ways to usefully use an entire array. You cannot pass them to functions, return them from functions, perform [] or == or + or almost anything on them, at least directly.
Instead the array 'decays' to a pointer to its first element whenever you, well, look at it funny. (basically, whenever you use it in all but the few situations where it is treated as an actual array, it decays into a pointer).
So arr[3] becomes (&(first element of arr))[3] or *((&(first element of arr))+3) (these mean the same thing).
Similar thing happen when you return arr; or pass it to a function (in C). Your cout << arr means cout.operator<<( arr ), which is just a function. Well, it could also be operator<<( cout, arr ). In C++, you can pass a reference to an actual array to a function, but it takes a bit of work and is not happening in your example code.
If you type &arr decay does not occur, and you get a pointer to the entire array. This matters because of pointer arithmetic, among other reasons, and is how arrays-of-arrays can work with zero overhead. (&arr)+1 points to past-the-end of the array, no matter how big it is -- ((&(arr[0]))+1) points to the second element of the array.
This is how int arr[3]={4,5,6}; works, or int arr[]={4,5,6}; (same thing -- second one just determines the number 3 for you). arr in both cases is of type int[3]. It decays to int* easily, but it is of type int[3]. sizeof(arr) is three times the sizeof(int), not sizeof(int*).
When you new int[3] , you do not get a pointer to int[3], instead you get a pointer the first element of the int[3] array. In a sense, it gets pre-decayed. This is the type of the pointer -- the address of the array and first element is the same. But type information (which is a complie time concept) differs!
It is also stored on the free store, and not automatic storage (aka the heap and stack repectively). But that is not the fundamental difference.
The only thing C++ about the new int[3] was that you used new -- you can use malloc to get data space on the free store, and get a pointer to the first element as an int* in C as well.
It sounds like you have questions about pointers v arrays more than anything, Ill try and go through and hit all of your questions though,
int myints[] = {20,40,60,80,100};
C style array?
Well yes that is how you declare a C style array
is this on the stack?
Yes the entire array (all 5 variables) is located on the stack, this means that when its block goes out of scope the data itself goes out of scope as well, being "freed" by moving the stack pointer, this does not mean you cannot make a pointer to this array for use in other functions using the & operator though.
how is this different from myOtherInts?
This is a value on the stack, whereas myotherints is a value on the heap, with a pointer on the stack.
int* myOtherInts = new int[]{20,40,60,80,100};
does this pointer get created on stack while the elements themselves are created in free heap?
Yes declaring an int* means that you are declaring a pointer on the stack (the pointer not the value is created on the stack) and when you assign that variable to what the new function returns, (which should be memory allocated on the heap which must be freed later) you then have a stack stored pointer to a heap stored value.
cout << "&myotherints: " << &myotherints << endl;
address of myotherints, is this where the pointer to the array is stored?
Yes this returns the address of which location in memory holds the pointer to your actual data which is different than where your data is actually stored.
//myotherints: 0x2308010 <-- myotherints is a pointer to an array of ints, but its address is much lower compared to myints and j, why is that?
the value you are printing here is the address where your data is stored which is different than the location that pointer is stored in. The reason why this value is much lower is because this address that this memory resides on is controlled by the heap, which typically holds the lower address spaces of the program.
&myotherints: 0x7fff096df828 <-- how can the pointer to myotherints array be stored here when dereferencing it (*) returns 20 and...
&myotherints[0]: 0x2308010 <-- dereferencing this address with [] also returns 20, yet they are different memory locations unlike myints
This ones a little bit tricky. Recall that the & operator means "give me the address of" so to translate your code down to english a little bit you have
give me the address of myotherints
recall that myotherints is a pointer that you allocated on the stack, however this pointer points to memory on the heap. so you should expect to get a value that looks like it came from the stack (ie, generally a higher value)
give me the address of the first element of myotherints
now, again myotherints is a pointer to a value on the heap, and when you dereference it with [0] you get the value of your first element, which is stored on the heap, so when you ask for the address of something stored on the heap, you should expect a different result from something stored on the stack. (ie. a rather low number representing heap data)
EDIT: for the truly C++ way to allocate arrays you should probably be using std::array see Manu's answer
new operator, in fact, is a special kind of method and in a nutshell it requests operating system to give some free memory and returns address of newly allocated memory. So, it returns standard memory address. myints is a mere address in a nutshell. Memory to store it is not allocated on the stack. You can perform basic pointer algebra on it but you can't modify it's address. If you're familiar with asm, you may think of myints as a simple label. In C and C++ you can indeed define labels in your methods like this:
...
some_label:
/* some code here*/
goto some_label;
The compiler shall generate code that shall instruct processor to use some kind of jump instruction. Some jmp stack_pointer + some_label. Likewise, trying to modify myints fourth value number instructs compiler to generate call similar to previous example like "write this value on address stack_pointer + myints + 4 * sizeof(member of myints)" or something like that.
As background, I gave an answer to this post a little while ago:
Return array in a function
And it unintentionally kicked off a really long comment chain about pointers vs. arrays in C++ because I tried to oversimplify and I made the statement "arrays are pointers". Though my final answer sounds pretty decent, it was only after some heavy editing in response to a lot of the comments I got.
This question is not meant to be troll bait, I understand that a pointer and an array are not the same thing, but some of the available syntax in the C++ language certainly makes them behave very similarly in a lot of cases. (FYI, my compiler is i686-apple-darwin9-g++-4.0.1 on OS X 10.5.8)
For instance, this code compiles and runs just fine for me (I realize x[8] is a potential segmentation fault):
//this is just a simple pointer
int *x = new int;
cout << x << " " << (*x) << " " << x[8] << endl; //might segfault
//this is a dynamic array
int* y = new int[10];
cout << y << " " << (*y) << " " << y[8] << endl;
//this is a static array
int z[10];
cout << z << " " << (*z) << " " << z[8] << endl;
That particular snippet makes it look like pointers and arrays can be used almost identically, but if I add this to the bottom of that code, the last two lines won't compile:
x = y;
x = z;
y = x;
y = z;
//z = x; //won't compile
//z = y; //won't compile
So clearly the compiler at least understands that z and x are different things, but I can interchange x and y just fine.
This is further confusing when you look at passing arrays to functions and returning arrays from functions. Consider this example (again, I am aware of the potential segmentation faults here when passing x):
void foo(int in[])
{
cout << in[8] << endl;
}
void bar(int* in)
{
cout << in[8] << endl;
}
int main()
{
//this is just a simple pointer
int *x = new int;
foo(x);
bar(x);
//this is a dynamic array
int* y = new int[10];
foo(y);
bar(y);
//this is a static array
int z[10];
foo(z);
bar(z);
}
All this code properly compiles and runs on my machine.
I feel like I have a decent internal understanding of what's going on here, but if you asked me to articulate exactly what's happening, I don't feel like I could satisfactorily explain. So here's what I'm getting at:
When I pass an array to a function as int* in instead of int in[], what am I gaining or losing? Is the same true when returning an array as int*? Are there ever bad side effects from doing this?
If I asked you what the data type of y is, would you say pointer to int, array of ints or something else?
Similarly, what happens when I say x = y vs. x = z? I'm still able to use x[] and access the things that were originally in y or z, but is this really just because pointer arithmetic happens to land me in memory space that is still valid?
I've dug through all the similar array/pointer questions on SO and I'm having trouble finding the definitive explanation that clears this up for me once and for all.
C++ is statically typed, so of course the compiler understands that x and z are not the same kind of thing. They have different types - z is an array, x and y are pointers.
The reason z = x doesn't compile isn't (just) that the types are incompatible, though, it's that you can't assign to an array variable at all. Ever. x = z assigns to x, a pointer to the first element of z. x = y assigns the value of y to x.[*]
When I pass an array to a function as int* in instead of int in[], what am I gaining or losing?
They do exactly the same thing, so you have no choice to make. Possibly you have been misled by the fact that C++ syntax permits int in[] as a function parameter. The type of the parameter in is not any kind of array, it is int*.
If I asked you what the data type of y is
It's int*. That's what it's declared as, so that's what it is.
The value that it holds is a pointer to (the first element of) an array. I frequently use that formula: "pointer to (the first element of)" in cases where I'd like to say "pointer to array", but can't because there's the potential for ambiguity as to whether the type involved is pointer-to-array, or not.
However, pointers-to-arrays are rarely used in C++, because the size of the array is part of the type. There's no such type as "pointer to an array of int" in C++, just "pointer to array of 1 int", "pointer to array of 2 int", etc. This usually isn't very convenient, hence the use of a pointer to the first element of an array whose size may not be known at compile time.
is this really just because pointer arithmetic happens to land me in memory space that is still valid
Pretty much, yes. The size of the array is part of the type of z, but is not part of the type of x or y, and also is not part of the type of the result of z decaying to a pointer to its first element. So y could be a pointer to the first of 10 elements, or just to 1 element. You only know the difference by context, and by requiring of your callers that the value you have points to what it's supposed to point to.
"Happens" is leaving too much to chance, though - part of your job when using arrays is to make sure you don't stray beyond their bounds.
[*] z = x isn't allowed, even after you've done x = z, because z is (and always will be) an particular array of 10 ints in memory. Back when C was designed, there was a question of whether array variables could in principle be "reseatable", meaning that you could do:
int z[10];
int y[10];
z = y; // z is now an alias for y
y[0] = 3;
// z[0] now has the value 3
Dennis Ritchie decided not to allow this, because it would prevent him from distinguishing arrays from pointers in a way that he needed to do. So z cannot ever refer to a different array from the one it was declared as. Read all about it here: http://cm.bell-labs.com/cm/cs/who/dmr/chist.html, under "Embryonic C".
Another plausible meaning for z = y could be memcpy(z,y,sizeof(z)). It wasn't given that meaning either.
The fundamental difference between a pointer and an array is that the pointer has a unique memory address that holds the address of the array data.
An array name, though treated as a pointer based on context, does not itself have a memory location whose address you can take. When it is treated as a pointer, its value is generated at runtime as the address of its first element.
That is why you can assign its value to another pointer but not vice versa. There is no pointer memory location to treat as an l-value.
Arrays are not pointers, but arrays easily decay to pointers to their first element. Additionally, C (and thus C++) allow array access syntax to be used for pointers.
When I pass an array to a function as int* in instead of int in[], what am I gaining or losing? Is the same true when returning an array as int*? Are there ever bad side effects from doing this?
You're gaining nothing, because int[] is just another way to write int*. If you want to pass an array, you have to pass it per reference, exactly matching its size. Non-type template arguments can ease the problem with the exact size:
template< std:::size_t N >
void f(int (&arr)[N])
{
...
}
If I asked you what the data type of y is, would you say pointer to int, array of ints or something else?
It's a pointer to the first element of a dynamically allocated array.
Similarly, what happens when I say x = y vs. x = z?
You assign the addresses of different objects of different types to the same pointer. (And you leak an int on the heap. :))
I'm still able to use x[] and access the things that were originally in y or z, but is this really just because pointer arithmetic happens to land me in memory space that is still valid?
Yep. As I said, pointers conveniently and confusingly allow array syntax to be applied to them. However, that still doesn't make a pointer an array.
Here's an snippet from this book (and C++ semantics follows from its backward compatibility with C). Array "are" pointers in the following cases:
An array name in an expression (in contrast with a declaration) is treated by the compiler as a pointer to the first element of the array (this does not apply to sizeof) (ANSI C Standard, 6.2.2.1)
A subscript is always equivalent to an offset from a pointer (6.3.2.1)
An array name in the declaration of a function parameter is treated by the compiler as a pointer to the first element of the array (6.7.1)
This basically means that:
int arr[20]; int* p = arr;
is equivalent to:
int arr[20]; int* p = &arr[0];
Then
int arr[20]; int x = arr[10];
is equivalent to:
int arr[20]; int x = *( arr + 10 );
And
void func( int arr[] );
is equivalent to:
void func( int* arr );
On the other hand, pointers are never transformed back into arrays - that's why your last two lines do not compile.
When I pass an array to a function as
int* in instead of int in[], what am I
gaining or losing? Is the same true
when returning an array as int*? Are
there ever bad side effects from doing
this?
AFAIK, one is just syntactic sugar for the other and they mean exactly the same.
The version with [] probably just gives a strong hint that this function expects a pointer into an array, not a pointer to a single object.
You will notice a difference when it comes to real multi-dimensional arrays vs array of pointers (to arrays), because in such case only the first dimension decays to a pointer with multi-dimensional arrays. Those things have a completely different layout in memory (one big contiguous block vs one small block of pointers to distinct blocks of memory).
If I asked you what the data type of y
is, would you say pointer to int,
array of ints or something else?
The type of y is a pointer to int. In fact, in case of a dynamically allocated array, you never get to see the array at all! That is, there is no way to determine the size of the allocation with sizeof, unlike actual arrays.
Similarly, what happens when I say x =
y vs. x = z? I'm still able to use x[]
and access the things that were
originally in y or z, but is this
really just because pointer arithmetic
happens to land me in memory space
that is still valid?
This is because x is a pointer. You will not be able to do z = x; because you can't assign to arrays.
There's no difference (at all) between a function parameter like int *in and int in[]. For a function parameter, these are just different ways of spelling pointer to T. The only way they can differ at all is (possibly) something like readability (e.g., if you intend to always pass the base address of an array, you might find array notation more fitting, whereas if you intend to pass the address of a single object, you might find pointer notation more tasteful).
In the code above, y clearly has the type pointer to int.
x and y are pointers, which can be assigned. z is an array, which cannot be assigned.
As an aside (which has some relevance to the topic - would have added this as a comment but don't have enough rep.) - you can gauge the number of elements in an array vs. using a pointer. Or stated differently sizeof returns sizeof(array_type)*num_elements_in_array vs returning the size of the pointer. Glib provides this macro for this purpose.
When I pass an array to a function as int* in instead of int in[], what am I gaining or losing? Is the same true when returning an array as int*? Are there ever bad side effects from doing this?
Your not gaining or losing anything
If I asked you what the data type of y is, would you say pointer to int, array of ints or something else?
I would call y a pointer to an array of ints
Similarly, what happens when I say x = y vs. x = z? I'm still able to use x[] and access the things that were originally in y or z, but is this really just because pointer arithmetic happens to land me in memory space that is still valid?
x = y does not make a copy of the array pointed to by y only a copy of the pointer in y.
x = z does not make a copy of the array z, only a pointer to the value of the first element.
Also, free allocated memory.