I am attempting to write portable code that allows the function to access a variable like an array, even if it is just a single value. The idea behind it is that the code will not make an array of size 1, but I need to be able to loop over all the values in the array if it is an array. Since I can't use sizeof(foo) to determine whether the memory is larger than a single instance sizeof(foo)/sizeof(int) might work, but it is too cumbersome to include in the main code. Macros wouldn't help because if I used a ternary operator like I'd expect #define ARRAY_OR_NOT(foo, type) (sizeof(foo)/sizeof(type) > 1) ? (foo) : (&foo) to return a pointer, in order to access with indexing. This problem is the compiler doesn't like the mixing of types between pointers and non-pointers.
So my second attempt was function overloading.
int * convert(int value)
{return &value;}
int * convert(int * value)
{return value;}
I know that this wouldn't work, because the first function would return the address of the temporary variable copy in that function scope. So my third attempt was
int * convert(int * value)
{return value;}
int * convert(int ** value)
{return *value;}
Every time I would call convert, pass the address of the value: convert(&foo).
This should work, and (I think) it avoids returning a temporary function scope
address. The result of convert would be accessible with indexing. In a controlled for loop, the code would run smoothly. The program would know how many elements are in value, but it would be faster to run everything inside a for loop than not.
So why does my second block of code produce the "Warning returning temporary scope blahblahblah" warning?
UPDATE: Major XY problem here.
Basically I'm trying to wrap all my code in a loop and access each value in a variable, one value per loop iteration. The system would know how many values are in that variable, but the code base is so large that wrapping everything in an if/else would be slow. So the way to access some value in the for loop with an index would be int foo = convert(&maybeArray)[counter]; Then I would use foo several times in the for loop.
For some reason Visual Studio was throwing an error while with the second block of code. Added this to OP.
Another solution would be to make 2 functions with overloaded operators that would basically execute the entire code, without converting each variable, but the code base is very large, and this needs to be as portable as possible. Referencing convert would be more future proof I would believe.
You've tagged this as C++, so I'm assuming you are using a C++ compiler.
There's a lot going on in your question, so I'm going to simplify. You want a C++ function convert(x) that will:
if x is an array, return the address of the first element
if x is not an array, return &x.
(Generally, maybe you need to redesign this whole thing, convert seems like a pretty strange function to want).
template<typename T, size_t N>
auto convert( T (&t) [N] ) -> T* {
return t; // just let pointer decay work for us here
}
template<typename T>
auto convert( T &t) -> T* {
return &t;
}
And, in C++, I would never use sizeof with things that I think are arrays. This template technique is a safer way to count the number of elements in an array.
Also, do you expect to have arrays of pointers, and to want to treat a single pointer as a single-element-array of pointers? If so, then tread carefully. Something that looks like an array, might actually be a pointer, e.g. arrays in parameter lists foo(int is_really_a_pointer[5]) { ...}. See the comment by #MSalters for more. Might be good to use his assert to catch any surprises. If you're just using int, then don't use the typename T in my templates, just force it to be int for clarity.
Finally, maybe instead of turning arrays into pointers, you should ask for a function that turns a non-array into a reference to a single-element array?
Update Here is a more complete example showing how to use convert and convert_end to find the beginning and end of an array to iterate over all the elements in an array; where, of course, a non-array is treated as an array of one element.
In C, there exist only pass by value. When you pass a pointer to a function then its address is copied to the function parameter. This simply means that if p is a pointer in calling function then a function call
int x = 5;
int *p = &x;
int a = foo(p);
for function definition
int foo(int *p1)
{
return *p1*2;
}
is implies that:
copy the address p points to parameter p1, i.e make p and p1 points to the same location.
any changes to the location pointed by p1 in function foo is reflected to *p because p and p1 is pointing to same location. But, if at any point p1 points to another location then this does not imply that p will point to that location too. p and p1 are two different pointers.
When you you pass a pointer to pointer, as in your last snippet of second block,
int * convert(int ** value)
{return *value;}
if *value changes to points to different location after argument is passed to it, then that pointer whose address is passed will also be updated with this location. In this case no need to return *value, but returning do no harm.
Related
I am reading a book about c and the following paragraph is a bit unclear for me:
Surprisingly, passing the pointer is not efficient in the above example! That's because of the fact that the int type is 4 bytes and copying it is more efficient than copying 8 bytes of its pointer. But this is not the case regarding structures and arrays. Since copying structures and arrays is done byte-wise, and all of the bytes in them should be copied one by one, it is usually better to pass pointers instead.
as I know all the operations in CPU are limited to arithmetic(plus or minعس) or bit-wise kind of operation so
What does the writer mean about copying array and structure, isn't an int copying a bit shifting operation?
Second: are pointers array?
NOTE: the book name is Extreme C and published by packT
and following example is what the author is referring to:
#include <stdio.h>
void func(int* a) {
int b = 9;
*a = 5; a = &b;
}
int main(int argc, char** argv) {
int x = 3;
int* xptr = &x;
printf("Value before call: %d\n", x);
printf("Pointer before function call: %p\n", (void*)xptr); func(xptr);
printf("Value after call: %d\n", x);
printf("Pointer after function call: %p\n", (void*)xptr);
return 0;
}
'''
The book is not clear and it's also wrong.
The assumption seem to be that an 8 byte pointer is "harder" to copy than a 4 byte integer. That's wrong for nearly all modern CPUs.
Further, the part about copying an array is just plain wrong. That is not what C does. Passing an array in C does not involve an copy. It's actually just like passing a pointer.
The part about structs is however correct... as long as the struct isn't just a simple integer or char but "something bigger".
What does the writer mean about copying array
Sounds like rubbish... as C doesn't pass array by doing a copy
What does the writer mean about copying ... structure,
Structs are copied by value. So passing a struct to a function involves copying every byte of the struct. That is rather expensive if the struct is large.
are pointers array?
No. Pointers are pointers. But... Under the correct circumstances a pointer can be used as an array because *(p + i) is the same as p[i]
What does the writer mean about copying array and structure?
Let's compare two functions taking a large amount of data (e.g. a struct with lots of data members):
void f(const big_type_t* p_big_type);
void g(const big_type_t big_type);
Both can effectively read the values from the caller-specified big_type_t object, but in the former case f() need only be passed a pointer (which is typically 8 bytes on modern everyday hardware) to tell it where the caller has a big_type_t object for it to use. In the latter case g() pass-by-value argument asks the compiler to make a complete copy of the caller's big_type_t argument and copy it to a location on the stack where g() implicitly knows to find it. Every byte of the data in the struct must be copied (unless the compiler's smart enough to optimise under the as-if rule, but that's a bit of a distraction - it's generally best to write code so it's not unnecessarily inefficient if not optimised well).
For built-in arrays, the situation is different. C and C++ implicitly pass arrays by pointer, so...
void h(const int* my_array);
void i(const int my_array[]);
...are both called the same way, with the my_array argument actually being a pointer to the first int the caller specifies.
In C++ there are also std::array<>s, which are effectively struct/classes with a static-sized array data member (i.e. template <typename T, size_t N> struct array { T data_[N]; ... }). They can be passed by-value, the same as structs. So, for large std::array objects, access via a pointer or reference is more efficient than doing a full copy.
Sometimes a function really does want a copy though, as it may need to do something like sort it without affecting the caller-specified variable passed to that argument. In that case, there's not much point passing by pointer or reference.
isn't an int copying a bit shifting operation?
No... the term "bit shifting" has a very specific meaning in programming. Consider an 8-bit integer - say 0x10010110. If we shift this value one bit to the right, we get 0x01001011 - a 0 is introduced on the left, and a 0 is discarded on the right. If we shift the new value to the right again, we could get either 0x00100101 (add 0 at left; discard at right) or - what's called a circular shift or rotation - 0x100100101`, where the right-most bit is moved to become the left-most bit. Bit-shifting happens to CPU registers, and the shifted values can be stored back into the memory where a variable is located, or used in some calculation.
All that's quite unrelated to memory copying, which is where the bits in one value are (at least notionally, without optimisation) copied into "another" value. For large amounts of data, this usually does mean actually copying the bits in a value read from memory to another area of memory.
Second: are pointers array?
No they're not. But, when you have an array, it easily "decays" to a pointer to its first element. For example:
void f(const char* p);
f("hello");
In C++, "hello" is a string literal of type char[6] (as there's implicitly a null character at the end. When calling f, it decays from array form to a pointer to the first character - 'h'. That's usually desirable to give the called function access to the array data. In C++, you can also do this:
template <size_t N> void f(const char(&arr)[N]);
f("hello");
The call above does not involve decay from an array to a pointer - arr is bound to the string literal array and N is derived as 6.
What does the writer mean about copying array and structure, isn't an int copying a bit shifting operation?
When you pass an object of struct type as a parameter in a function, the contents of that structure are copied into the formal parameter:
struct foo {
...
};
void do_something_with( struct foo arg )
{
// do something with arg
}
int main( void )
{
struct foo f = { 1, 2.0, "three" };
...
do_something_with( f );
...
}
The objects main:f and do_something_with:arg are two separate instances of struct foo - when you pass f as an argument, its contents are copied into arg. Any changes you make to the contents of arg do not affect the contents of f.
The thing is, the author of the book is wrong about arrays - when you pass an array expression as an argument to a function, what you are actually passing is a pointer to the first element, not the whole array.
Second: are pointers array?
Arrays are not pointers - however, unless it is the operand of the sizeof or unary & operators, an expression of type "N-element array of T" will be converted, or "decay", to an expression of type "pointer to T" and the value will be the address of the first element of the array.
When you pass an array expression as an argument to a function, what the function actually receives is a pointer to the first element of the array - no copy of the array is made like it is for the struct above.
Finally - while runtime efficiency does matter, correctness, clarity, and maintainability matter more. If it makes sense to pass an argument as a pointer (such as you want the function to modify the argument), then by all means do so. But don't start passing everything as a pointer because it might speed things up. Start by making things clear and correct - then, measure the performance of your code and take action based on that. Most of your runtime performance gains come from using the right data structures and algorithms, not how you pass arguments.
While the sample code has much to be desired and some bugs, I think that the gist of what the author is saying is that for a small data type it is more efficient to directly pass a parameter to a function by value (int) rather than by passing by pointer (int *). When a function is called, parameters are pushed onto the stack and and a type of int would require 2 bytes, but an int *parameter may require 4 or 8 bytes depending on the system.
When passing a struct as a parameter, the overall size of the struct will typically be greater than 4 or 8 bytes, so passing a pointer to thr struct may be more efficient, since only 4 or 8 bytes would need to be copied to the stack.
I am not sure why the author mentioned arrays, since an array cannot be passed to a function by value unless it is contained in a struct.
I have this enqueue function that takes in a queue pointer and an int pointer to enqueue. I have this constant defined as
#DEFINE ENGINE 1
and I want to pass it to the function. However, I get an error saying this is an integer and can't be cast to int*. Then I tried to pass it by putting a "&" but it did not work either as I need a real variable instead of a defined constant. Also (int *) did not work either. Is there an easy way to cast my variable so that the function accepts it?
int queueEnqueue(queue* q, int* value){
if(!queueIsFull(q)){
q->rear = (q->rear + 1) % q->capacity;
q->array[q->rear] = *value;
q->size = q->size + 1;
return(1);
}
return(0);
}
queueEnqueue(queue, ENGINE);
In this case, better to pass the second integer argument as integer like:
int queueEnqueue(queue* q, int value)
And call it as:
queueEnqueue(queue, ENGINE);
You have no reason to use a pointer here. Pointers and references are used when you don't want to pay for copying data or you want to modify their content such that the caller also sees the changes.
The reason it doesn't work in your case is the address of a number is meaningless. You can only take the address of variables.
If you want to use a reference here you can use a const & it will prolong the lifetime of temporary:
int queueEnqueue(queue* q, const int& value)
The macro ENGINE has no type, you have to cast directly when the function called.
queueEnqueue(queue, (int *)(ENGINE));
Anyway it makes no sense to use pointer in that case and you will get segmentation fault if it is not a code of an embedded system. If you write your code to an embedded system and ENGINE contains a real physical address it must be aligned to 4 bytes when you access with an integer pointer otherwise it lead to exception/trap.
I have searched and searched for an answer to this but can't find anything I actually "get".
I am very very new to c++ and can't get my head around the use of double, triple pointers etc.. What is the point of them?
Can anyone enlighten me
Honestly, in well-written C++ you should very rarely see a T** outside of library code. In fact, the more stars you have, the closer you are to winning an award of a certain nature.
That's not to say that a pointer-to-pointer is never called for; you may need to construct a pointer to a pointer for the same reason that you ever need to construct a pointer to any other type of object.
In particular, I might expect to see such a thing inside a data structure or algorithm implementation, when you're shuffling around dynamically allocated nodes, perhaps?
Generally, though, outside of this context, if you need to pass around a reference to a pointer, you'd do just that (i.e. T*&) rather than doubling up on pointers, and even that ought to be fairly rare.
On Stack Overflow you're going to see people doing ghastly things with pointers to arrays of dynamically allocated pointers to data, trying to implement the least efficient "2D vector" they can think of. Please don't be inspired by them.
In summary, your intuition is not without merit.
An important reason why you should/must know about pointer-to-pointer-... is that you sometimes have to interface with other languages (like C for instance) through some API (for instance the Windows API).
Those APIs often have functions that have an output-parameter that returns a pointer. However those other languages often don't have references or compatible (with C++) references. That's a situation when pointer-to-pointer is needed.
It's less used in c++. However, in C, it can be very useful. Say that you have a function that will malloc some random amount of memory and fill the memory with some stuff. It would be a pain to have to call a function to get the size you need to allocate and then call another function that will fill the memory. Instead you can use a double pointer. The double pointer allows the function to set the pointer to the memory location. There are some other things it can be used for but that's the best thing I can think of.
int func(char** mem){
*mem = malloc(50);
return 50;
}
int main(){
char* mem = NULL;
int size = func(&mem);
free(mem);
}
I am very very new to c++ and can't get my head around the use of double, triple pointers etc.. What is the point of them?
The trick to understanding pointers in C is simply to go back to the basics, which you were probably never taught. They are:
Variables store values of a particular type.
Pointers are a kind of value.
If x is a variable of type T then &x is a value of type T*.
If x evaluates to a value of type T* then *x is a variable of type T. More specifically...
... if x evaluates to a value of type T* that is equal to &a for some variable a of type T, then *x is an alias for a.
Now everything follows:
int x = 123;
x is a variable of type int. Its value is 123.
int* y = &x;
y is a variable of type int*. x is a variable of type int. So &x is a value of type int*. Therefore we can store &x in y.
*y = 456;
y evaluates to the contents of variable y. That's a value of type int*. Applying * to a value of type int* gives a variable of type int. Therefore we can assign 456 to it. What is *y? It is an alias for x. Therefore we have just assigned 456 to x.
int** z = &y;
What is z? It's a variable of type int**. What is &y? Since y is a variable of type int*, &y must be a value of type int**. Therefore we can assign it to z.
**z = 789;
What is **z? Work from the inside out. z evaluates to an int**. Therefore *z is a variable of type int*. It is an alias for y. Therefore this is the same as *y, and we already know what that is; it's an alias for x.
No really, what's the point?
Here, I have a piece of paper. It says 1600 Pennsylvania Avenue Washington DC. Is that a house? No, it's a piece of paper with the address of a house written on it. But we can use that piece of paper to find the house.
Here, I have ten million pieces of paper, all numbered. Paper number 123456 says 1600 Pennsylvania Avenue. Is 123456 a house? No. Is it a piece of paper? No. But it is still enough information for me to find the house.
That's the point: often we need to refer to entities through multiple levels of indirection for convenience.
That said, double pointers are confusing and a sign that your algorithm is insufficiently abstract. Try to avoid them by using good design techniques.
A double-pointer, is simply a pointer to a pointer. A common usage is for arrays of character strings. Imagine the first function in just about every C/C++ program:
int main(int argc, char *argv[])
{
...
}
Which can also be written
int main(int argc, char **argv)
{
...
}
The variable argv is a pointer to an array of pointers to char. This is a standard way of passing around arrays of C "strings". Why do that? I've seen it used for multi-language support, blocks of error strings, etc.
Don't forget that a pointer is just a number - the index of the memory "slot" inside a computer. That's it, nothing more. So a double-pointer is index of a piece of memory that just happens to hold another index to somewhere else. A mathematical join-the-dots if you like.
This is how I explained pointers to my kids:
Imagine the computer memory is a series of boxes. Each box has a number written on it, starting at zero, going up by 1, to however many bytes of memory there is. Say you have a pointer to some place in memory. This pointer is just the box number. My pointer is, say 4. I look into box #4. Inside is another number, this time it's 6. So now we look into box #6, and get the final thing we wanted. My original pointer (that said "4") was a double-pointer, because the content of its box was the index of another box, rather than being a final result.
It seems in recent times pointers themselves have become a pariah of programming. Back in the not-too-distant past, it was completely normal to pass around pointers to pointers. But with the proliferation of Java, and increasing use of pass-by-reference in C++, the fundamental understanding of pointers declined - particularly around when Java became established as a first-year computer science beginners language, over say Pascal and C.
I think a lot of the venom about pointers is because people just don't ever understand them properly. Things people don't understand get derided. So they became "too hard" and "too dangerous". I guess with even supposedly learned people advocating Smart Pointers, etc. these ideas are to be expected. But in reality there a very powerful programming tool. Honestly, pointers are the magic of programming, and after-all, they're just a number.
In many situations, a Foo*& is a replacement for a Foo**. In both cases, you have a pointer whose address can be modified.
Suppose you have an abstract non-value type and you need to return it, but the return value is taken up by the error code:
error_code get_foo( Foo** ppfoo )
or
error_code get_foo( Foo*& pfoo_out )
Now a function argument being mutable is rarely useful, so the ability to change where the outermost pointer ppFoo points at is rarely useful. However, a pointer is nullable -- so if get_foo's argument is optional, a pointer acts like an optional reference.
In this case, the return value is a raw pointer. If it returns an owned resource, it should usually be instead a std::unique_ptr<Foo>* -- a smart pointer at that level of indirection.
If instead, it is returning a pointer to something it does not share ownership of, then a raw pointer makes more sense.
There are other uses for Foo** besides these "crude out parameters". If you have a polymorphic non-value type, non-owning handles are Foo*, and the same reason why you'd want to have an int* you would want to have a Foo**.
Which then leads you to ask "why do you want an int*?" In modern C++ int* is a non-owning nullable mutable reference to an int. It behaves better when stored in a struct than a reference does (references in structs generate confusing semantics around assignment and copy, especially if mixed with non-references).
You could sometimes replace int* with std::reference_wrapper<int>, well std::optional<std::reference_wrapper<int>>, but note that is going to be 2x as large as a simple int*.
So there are legitimate reasons to use int*. Once you have that, you can legitimately use Foo** when you want a pointer to a non-value type. You can even get to int** by having a contiguous array of int*s you want to operate on.
Legitimately getting to three-star programmer gets harder. Now you need a legitimate reason to (say) want to pass a Foo** by indirection. Usually long before you reach that point, you should have considered abstracting and/or simplifying your code structure.
All of this ignores the most common reason; interacting with C APIs. C doesn't have unique_ptr, it doesn't have span. It tends to use primitive types instead of structs because structs require awkward function based access (no operator overloading).
So when C++ interacts with C, you sometimes get 0-3 more *s than the equivalent C++ code would.
The use is to have a pointer to a pointer, e.g., if you want to pass a pointer to a method by reference.
What real use does a double pointer have?
Here is practical example. Say you have a function and you want to send an array of string params to it (maybe you have a DLL you want to pass params to). This can look like this:
#include <iostream>
void printParams(const char **params, int size)
{
for (int i = 0; i < size; ++i)
{
std::cout << params[i] << std::endl;
}
}
int main()
{
const char *params[] = { "param1", "param2", "param3" };
printParams(params, 3);
return 0;
}
You will be sending an array of const char pointers, each pointer pointing to the start of a null terminated C string. The compiler will decay your array into pointer at function argument, hence what you get is const char ** a pointer to first pointer of array of const char pointers. Since the array size is lost at this point, you will want to pass it as second argument.
One case where I've used it is a function manipulating a linked list, in C.
There is
struct node { struct node *next; ... };
for the list nodes, and
struct node *first;
to point to the first element. All the manipulation functions take a struct node **, because I can guarantee that this pointer is non-NULL even if the list is empty, and I don't need any special cases for insertion and deletion:
void link(struct node *new_node, struct node **list)
{
new_node->next = *list;
*list = new_node;
}
void unlink(struct node **prev_ptr)
{
*prev_ptr = (*prev_ptr)->next;
}
To insert at the beginning of the list, just pass a pointer to the first pointer, and it will do the right thing even if the value of first is NULL.
struct node *new_node = (struct node *)malloc(sizeof *new_node);
link(new_node, &first);
Multiple indirection is largely a holdover from C (which has neither reference nor container types). You shouldn't see multiple indirection that much in well-written C++, unless you're dealing with a legacy C library or something like that.
Having said that, multiple indirection falls out of some fairly common use cases.
In both C and C++, array expressions will "decay" from type "N-element array of T" to "pointer to T" under most circumstances1. So, assume an array definition like
T *a[N]; // for any type T
When you pass a to a function, like so:
foo( a );
the expression a will be converted from "N-element array of T *" to "pointer to T *", or T **, so what the function actually receives is
void foo( T **a ) { ... }
A second place they pop up is when you want a function to modify a parameter of pointer type, something like
void foo( T **ptr )
{
*ptr = new_value();
}
void bar( void )
{
T *val;
foo( &val );
}
Since C++ introduced references, you probably won't see that as often. You'll usually only see that when working with a C-based API.
You can also use multiple indirection to set up "jagged" arrays, but you can achieve the same thing with C++ containers for much less pain. But if you're feeling masochistic:
T **arr;
try
{
arr = new T *[rows];
for ( size_t i = 0; i < rows; i++ )
arr[i] = new T [size_for_row(i)];
}
catch ( std::bad_alloc& e )
{
...
}
But most of the time in C++, the only time you should see multiple indirection is when an array of pointers "decays" to a pointer expression itself.
The exceptions to this rule occur when the expression is the operand of the sizeof or unary & operator, or is a string literal used to initialize another array in a declaration.
In C++, if you want to pass a pointer as an out or in/out parameter, you pass it by reference:
int x;
void f(int *&p) { p = &x; }
But, a reference can't ("legally") be nullptr, so, if the pointer is optional, you need a pointer to a pointer:
void g(int **p) { if (p) *p = &x; }
Sure, since C++17 you have std::optional, but, the "double pointer" has been idiomatic C/C++ code for many decades, so should be OK. Also, the usage is not so nice, you either:
void h(std::optional<int*> &p) { if (p) *p = &x) }
which is kind of ugly at the call site, unless you already have a std::optional, or:
void u(std::optional<std::reference_wrapper<int*>> p) { if (p) p->get() = &x; }
which is not so nice in itself.
Also, some might argue that g is nicer to read at the call site:
f(p);
g(&p); // `&` indicates that `p` might change, to some folks
So, I always knew that the array "objects" that are passed around in C/C++ just contained the address of the first object in the array.
How can the pointer to the array "object" and it's contained value be the same?
Could someone point me towards more information maybe about how all that works in assembly, maybe.
Short answer: A pointer to an array is defined to have the same value as a pointer to the first element of the array. That's how arrays in C and C++ work.
Pedantic answer:
C and C++ have rvalue and lvalue expressions. An lvalue is something to which the & operator may be applied. They also have implicit conversions. An object may be converted to another type before being used. (For example, if you call sqrt( 9 ) then 9 is converted to double because sqrt( int ) is not defined.)
An lvalue of array type implicitly converts to a pointer. The implicit conversion changes array to &array[0]. This may also be written out explicitly as static_cast< int * >( array ), in C++.
Doing that is OK. Casting to void* is another story. void* is a bit ugly. And casting with the parentheses as (void*)array is also ugly. So please, avoid (void*) a in actual code.
You are mixing two unrelated (and, actually, mutually exclusive) things, which creates more confusion.
Firstly, you are correctly stating that "array objects that are passed around in C/C++ just contained the address of the first object in the array". The key words here are "passed around". In reality arrays cannot be passed around as array objects. Arrays are not copyable. Whenever you are using an array-style declaration in function parameter list it is actually interpreted as pointer declaration, i.e. it is a pointer that you are "passing around", not the array. However, in such situations your equality does not hold
void foo(int a[]) {
assert((void *) &a == (void *) a); // FAIL!!!
}
The above assertion is guaranteed to fail - the equality does not hold. So, within the context of this question you have to forget about arrays that you "pass around" (at least for the syntax used in the above example). Your equality does not hold for arrays that have been replaced by pointer objects.
Secondly, actual array objects are not pointers. And there's no need to take the term object into quotation markes. Arrays are full-fledged objects, albeit with some peculiar properties. The equality in question does indeed hold for the actual arrays that have not lost their "arrayness", i.e. array object that have not been replaced by pointer objects. For example
int a[10];
assert((void *) &a == (void *) a); // Never fails
What it means is that numerically the address of the entire array is the same as the address of its first element. Nothing unusual here. In fact, the very same (in nature) equality can be observed with struct types in C/C++
struct S { int x; } a;
assert((void *) &a == (void *) &a.x); // Never fails
I.e. the address of the entire struct object is the same as the address of its first field.
How can the pointer to the array "object" and it's contained value be the same?
An array is a contiguous block of memory which stores several elements.
Obviously, the first element in the array is located at some address.
There's no data "in between" the first element and the beginning of the actual array.
Therefore, the first element has the same address as the array.
Please read the following thread
http://www.cplusplus.com/forum/beginner/29595/
It basically explains that (&a != a) due to the type difference (since &a returns the pointer to the array and a to the first element) even though they both point to the same address.
Since you are casting them both to (void*) only the address value is compared and found to be equal, meaning that ((void*) a == (void*)&a) as you've stated. This makes sense since the array's address has to be the same as the first elements.
Let's look at these two declarations:
int a[4];
int * b;
Both a and b have a type compatible with int * and can, for example, be passed as an argument to a function expecting int *:
void f(int * p);
f(a); // OK
f(b); // OK
In case of a, the compiler allocates space for 4 int values. When you use the name a, such as when calling f(a), the compiler just substitutes the address of where it allocated the first of those int values, since it knows.
In case of b, the compiler allocates space for one pointer. When you use the name b, such as when calling f(b), the compiler generates code for retrieveing the pointer value from the allocated storage.
When it comes to &, that's when the difference between a and b becomes apparent. & always means the address of the storage the compiler has allocated for your variable: &a is the address of those four int values (therefore coinciding with just a), while &b is the address of the pointer value. They have different types, too.
&a is not exactly the same as a, though, even though they compare as equal. They have a different type: &a is a pointer and a is an array. You can notice the difference, for example, if you apply the sizeof operator to these expressions: sizeof(a) will evaluate to the size of four int values, while sizeof(&a) is the size of a pointer.
Ok, So what I thought happened is that when you created an array, you allocated space for the array somewhere and you created a pointer to its first object somewhere else, and what you passed around in your code was the pointer.
This is actually the behavior of what happens when you create an array with new in C++ or with malloc in C/C++. As such,
int * a = new a[SIZE];
assert((void*)&a==(void*)a); // Always fails
What I learned is that for arrays declared in the style of int a[SIZE];, a pointer to the first element is created when you try to pass the array to a function (this is called array-pointer decay). It's interesting to note that, indeed, as AndreyT writes,
void foo(int a[]) {
assert((void *) &a == (void *) a); // Always fails
}
This shows that it's only when you try to pass arrays around that a pointer is created for arrays in the style of int a[SIZE];.
I know this might be a common question but I have tried to search but still cannot find a clear answer.
I have the following code:
int* f() {
int a[] = {1,2,3};
return a;
}
int main() {
int a[] = f(); // Error here
getch();
return 0;
}
This code produces the error message: "Cannot convert from 'int *' to 'int []'"
I found this quite strange because I have read that pointer and array are similar. For example, we can use a[i] instead of *(a + i).
Can anyone give me a clear explanation, please?
There are actually two errors in this code.
Firstly, you are returning the address of a temporary (the int array within f), so its contents are undefined after the function returns. Any attempt to access the memory pointed to by the returned pointer will cause undefined behaviour.
Secondly, there is no implicit conversion from pointers to array types in C++. They are similar, but not identical. Arrays can decay to pointers, but it doesn't work the other way round as information is lost on the way - a pointer just represents a memory address, while an array represents the address of a continuous region, typically with a particular size. Also you can't assign to arrays.
For example, we can use a[i] instead of *(a + i)
This, however, has little to do with the differences between arrays and pointers, it's just a syntactic rule for pointer types. As arrays decay to pointers, it works for arrays as well.
The type int[] doesn't actually exist.
When you define and initialize an array like
int a[] = {1,2,3};
the compiler counts the elements in the initializer and creates an array of the right size; in that case, it magically becomes:
int a[3] = {1,2,3};
int[] used as a parameter to a function, instead, it's just plain int *, i.e. a pointer to the first element of the array. No other information is carried with it, in particular nothing about the size is preserved. The same holds when you return a pointer
Notice that an array is not a pointer: a pointer can be changed to point to other stuff, while an array refers always to the same memory; a pointer does not know anything about how big is the space of memory it points to, while the size of an array is always known at compile time. The confusion arises from the fact that an array decays to a pointer to its first element in many circumstances, and passing it to a function/returning it from a function are some of these circumstances.
So, why doesn't your code work? There are two big errors:
You are trying to initialize an array with a pointer. We said that an int * doesn't carry any information about the size of the array. It's just a pointer to the first element. So the compiler cannot know how big a should be made to accomodate the stuff returned by f().
In f you are returning a pointer to a variable that is local to that function. This is wrong, because a pointer does not actually store the data, it only points to where the data is stored, i.e. in your case to the a local to f. Because that array is local to the function, it ceases to exist when the function exits (i.e. at the return).
This means that the pointer you are returning points to stuff that does not exist anymore; consider the code:
int * a = f();
This initialization works, and you can try to use a later in the function, but a will be pointing to the no-longer existent array of f; in the best case your program will crash (and you'll notice immediately that you've done something wrong), in the worst it will seem to work for some time, and then start giving strange results.
int * and int [] are similar but different.
int * is a real pointer, meanwhile int[] is an array reference ( a sort of "constant pointer" to the begin of the data) wich cannot be modified. So, a int * can be threated like a int [] but not viceversa.
You can use a[b] and*(a+b) interchangeably because that is exactly how a[b] is defined when one of a or b is a pointer and the other is of integer or enumeration type.
Note: This also means that expressions like 42[a] are perfectly legal. Human readers might object strongly, but the compiler won't bat an eye at this.