Why are the addresses of these two local variables the same? [duplicate] - c++

This question already has answers here:
What is array to pointer decay?
(11 answers)
Closed last year.
I have defined a function here that accepts an array as a parameter
void print(char ch[]);
When I call the function and give it the array as an argument
int main(){
char ch[10];
print(ch);
}
And I print the addresses of these two variables in two different functions,
#include <stdio.h>
void print(char ch[]) {
printf("address of ch is %d\n",ch);
}
int main() {
char ch[10];
print(ch);
printf("address of ch is %d\n",ch);
return 0;
}
the address of the array in the main function must be different from the address of the array as a parameter in the function I defined, but it is the same. Why?
And whether the address of a variable can be negative?
Thanks for taking the time to read this question.

char ch[10];
This variable is an array. It implicitly converts to a pointer to first element. The value of the pointer is the address of the object that it points, and that address is the output that you see1.
void print(char ch[]) {
This parameter is a pointer. It may look like an array, but array parameters are adjusted to be pointers to the element of the array instead. When you output the value of a pointer, you see the address of the pointed object; not the address of the variable that stores the pointer.
Since the pointer that you passed as an argument points to the first element of the local array, the address that you see1 is the same.
The variables have different addresses, but the value of the parameter variable is the same as the address of the first element of the array variable.
1 Except, you used the wrong format specifier that doesn't match the type of the argument, so the behaviour of the program is actually undefined. Don't do this. If you absolutely must use printf, then you must use the %p format specifier and convert the argument to void*.

For starters to output a pointer you need to use the conversion specifier %p instead pf the conversion specifier %d. Otherwise the call of printf invokes undefined behavior.
printf("address of ch is %p\n", ( void * )ch);
Secondly within the function this call of printf does not output the address of the variable ch itself. It outputs the address of the first element of the array pointed to by the pointer expression ch. As the array is not moved within memory then you will get the same value of the address.
To output the address of the function parameter you need to write
void print(char ch[]) {
printf("address of ch is %p\n", ( void * )&ch);
}
Pay attention to that in this call
print(ch);
the array is implicitly converted to pointer to its first element. And the compiler adjusts the function parameter having an array type to pointer to the array element type
void print(char *ch) {
There is a difference between these two calls of printf in main where the source array is declared and within the function
printf("address of ch is %p\n", ( void * )ch);
printf("address of ch is %p\n", ( void * )&ch);
Within the function the first call outputs the address of the first element of the array pointed to by the pointer ch that is the address of the extent of memory occupied by the array.
The second call outputs the address of the local variable ch itself having the type char * (as pointed above).
In main these calls outputs the same value that is the address of the extent of memory occupied by the array. The first call outputs the address of the first element of the array and the second call outputs the address of the array as a whole object. The both values are the initial address of the extent of memory occupied by the array.

You're right, two different arrays can't have the same address.
char ch[] is not an array though. Attempting to use an array as a function parameter silently creates a pointer instead, so in this case it means char *ch. (But char ch[10]; in main is still an array, since it's not a parameter.)
ch (where ch is a char ch[] parameter) is not an address of ch. It's an address that ch points to. &ch would an address of ch itself, and it would have a different value.
But for char ch[10] in main, due to it being an array, ch and &ch have the same value (but different types: char * vs char (*)[10] (pointer to an array of 10 char)).

Why are the addresses of these two local variables the same?
Passing a C-style array to a function actually passes its pointer to that function, not the whole array. This void print(char ch[]); is the same as void print(char* ch); So both functions are printing the address of the same array in main function (char ch[10];).
If you want to pass a copy of an array to a function, you can use std::array as below:
#include <cstdio>
#include <array>
template<std::size_t N>
void print(std::array<char, N> ch) {
printf("address of ch is %d\n", ch.data());
}
int main() {
std::array<char, 10> ch;
print(ch);
printf("address of ch is %d\n", ch.data());
return 0;
}
Now the addresses won't be the same.
And whether the address of a variable can be negative?
Here:
printf("address of ch is %d\n",ch);
the above statement is interpreting ch (a pointer) as a decimal value (because of '%d'). That's why you're seeing a negative number. You need to use %p instead:
void print(char ch[]) {
printf("address of ch is %p\n", (void*) &ch);
}

Related

Why is that you can modify an array inside a function without using any reference or pointer [duplicate]

This question already has answers here:
Array changed in a void function, is still changed outside! why? (scope)
(4 answers)
Passing an array as a parameter in C
(3 answers)
Passing Arrays to Function in C++
(5 answers)
Passing an array as an argument to a function in C
(11 answers)
Closed 11 months ago.
I don't get it why you can alter the values inside the array, without using a reference or a pointer (&, *), I'm a freshmen student, and I don't know the reason behind, I hope someone can provide a logical answer, please refer to the code below, Thank You in Advance.
#include <iostream>
using namespace std;
void a(int x[]){
for(int i = 0; i < 5; i++){
x[i] += 2;
}
}
int main(){
int x[5] = {1,2,3,4,5};
a(x);
for(auto b : x){
cout << b << " ";
}
return 0;
}
A function parameter is never an array in C++. When you declare a function parameter as an array, it is automatically adjusted to be a pointer to element of such array. These declarations are effectively identical:
void a(int x[]); // looks like an array of int of unknown bound
void a(int* x); // declaration above is adjusted to this
void a(int x[1234]); // the size is ignored completely
An array implicitly converts to a pointer to the first element of the array (such conversion is called decay). Hence, you can call the function that doesn't accept an array parameter by passing an array argument:
int* ptr1 = x; // implicit conversion
int* ptr2 = &x[0]; // same conversion explicitly
a(x); // same conversion happens here
These two rules (function parameter adjustment and array to pointer decay) make it so that what syntactically looks like passing arrays by value, is actually done using indirection. Within the function, you modify the elements by indirecting through the pointer parameter that points to the array that exists outside of the function.
Important note: The adjustment of array to pointer in function parameter does not apply in other contexts. Arrays and pointers are distinct types with different properties.
Another note: The adjustment does not apply to parts of compound types. For example, a function parameter of type "pointer to array" will not be adjusted to be "pointer to pointer" and "reference to array" will not be adjusted to be "reference to pointer".
The parameter having the array type in this function declaration
void a(int x[]){
is adjusted by the compiler to pointer type to array elements type. That is the above declaration is equivalent to
void a(int *x){
In this call of the function
a(x);
the array designator is implicitly converted to pointer to its first element. That is the call is equivalent to
a( &x[0]);
So within the function you have a pointer to the first element of the array declared in main.
Using the pointer arithmetic you can access elements of the array. That is the elements of the array are passed to the function by reference in the C meaning indirectly through a pointer to them.
Within the function the variable x has the type int *. And this expression statement
x[i] += 2;
is equivalent to
*( x + i ) += 2;
Beacuse
void a(int x[]){
is the same as
void a(int *x){
and so you are using a pointer
Why?
Because an array like
int x[10];
'decays' to a pointer when passed to a function (and in other places). This can be very confusing but at the same time is very flexible
It mens that I can have a function like strlen that can accpet a 'real' array, or a pointer. These 'strings'
char *s1 = malloc(10);
strcpy(s1, "hello");
char s2[] = "hello";
char *s3 = "hello";
store their data in different ways but all can be handled by
size_t strlen(const char *s);
note that this is exactly the same as
size_t strlen(const char s[]);
they are 2 different ways of writing the same thing. Personal preference is for the second type if its really is an 'array' vs a pointer to maybe an array.
One issue with this 'decay' is that inside strlen (or any pointer/array accepting function) it is impossible to 'know' the length just from the parameter. The compiler knows that the size of s2 is 6 but this information is not carried forward to the function.
Regularly SO sees this
void my_func(int *arr){
int len = sizeof(arr)/sizeof(arr[0]);
....
}
int a[10];
my_func(a);
This will give len = 1 or 2 (depending on 32 or 64 bit machine), never 10
The flexibility costs a litle power

Double Pointers and a Parenthesis between them

I am learning c pointer and I follow c4learn as tutorial. In pointer to array of string section, which has following code:
char *arr[4] = {"C","C++","Java","VBA"};
char *(*ptr)[4] = &arr;
I didn't get what is
*(*ptr)[4]
? Wasn't it possible to use it like
**ptr
instead?
Update1:
Currently I am in the next section, function pointer and I saw again similar code:
void *(*ptr)();
char *(*ptr)[4]
is a pointer to a length 4 array of pointers to char (char*). Since arr is a length 4 array of char*, ptr can be made to point to arr by assigning it the address of arr, &arr.
void *(*ptr)();
Is a pointer to a parameterless function returning void*. For example
void* fun(); // function
void *(*ptr)(); // function pointer
p = fun; // function pointer points to function
C syntax can be quite confusing, so it may be easier to illustrate this with some examples. Note that whitespaces between T and ; make no difference.
T name[N]; // size N array of T
T * name[N]; // size N array of pointer to T
T (*name)[N]; // pointer to size N array of T
T ** name[N]; // size N array of pointer to pointer to T
T *(*name)[N]; // pointer to size N array of pointer to T
char *ar[4];
Declares ar as an array of four pointers to chars.
To declare a pointer, you take the declaration of something it can point to, and replace the variable name with (*some_other_name).
So char *(*ptr)[4]; declares ptr as a pointer to an array of four pointers to chars. Normally you can drop the brackets, but in this case, char **ptr[4]; would declare ptr as an array of four pointers to pointers to chars which is not what we want.
Similarly for a function pointer. void *fn() declares a function. void *(*ptr)() declares a pointer that could point to fn. void **ptr() would declare a function with a different return type.
Wasn't it possible to use it like **ptr instead?
Yes, assuming you mean like ptr2 below:
const char* arr[4] = {"C","C++","Java","VBA"};
const char* (*ptr)[4] = &arr;
const char** ptr2 = arr;
There is a difference though... with ptr the type still encodes the array length, so you can pass ptr but not ptr2 to functions like the one below:
template <size_t N>
void f(const char* (&arr)[N]) { ...can use N in implementation... }
Currently I am in the next section, function pointer and I saw again similar code: void *(*ptr)();
That creates a pointer to a function - taking no arguments - returning a void* (i.e. the address of an unspecified type of data, or nullptr).
char *(*ptr)[4] is an array pointer to an array of pointers.
With less obfuscated syntax: if you have a plain array int arr[4]; then you can have an array pointer to such an array by declaring int (*arr_ptr)[4].
So there are arrays, regular pointers and array pointers. Things get confusing because when you use the array name by itself, arr, it decays into a regular pointer to the first element. Similarly, if you have a regular pointer and let it point at the array, ptr = arr; it actually just points at the first element of the array.
Array pointers on the other hand, points at the "whole array". If you take sizeof(*arr_ptr) from the example above, you would get 4*sizeof(int), 4*4=16 bytes on a 32-bit machine.
It should be noted that an array pointer a mildly useful thing to have. If you are a beginner, you don't really need to waste your time trying to understand what this is. Array pointers are mainly there for language consistency reasons. The only real practical use for array pointers is pointer arithmetic on arrays-of-arrays, and dynamic allocation of multi-dimensional arrays.

Differences in using array in main program or in functions sub-routines

I'v got some question about using array pointers in program.
When I use some array name (which is a const pointer to first array element)
char charTab[] = "ABCDEFGHIJKLMNOPRSTUWXYZ"; /* Basic data buffer */
char *charPtr = charTab; /* Assign */
charPtr += 3; /* It's ok, now we point 4th element */
charTab += 3; /* No, the lvalue required for '+' operand */
But when I create let's say the following function:
void CharTabMove(char *tabToMove, int noToMove);
With definition
void CharTabMove(char *tabToMove, int noToMove)
{
printf("-------IN FUNCTION---------\n");
printf("It's pointing to %c\n", *tabToMove);
tabToMove += noToMove;
printf("Now it's pointing to %c\n", *tabToMove);
printf("-------LEAVING FUNCTION---------\n");
fflush(stdout);
}
The function is allow to move this pointer along the array with no problem. Sure, after leaving the function the pointer will be still pointing to first element of charTab, but why the function is allowed to move the constant pointer?
Thanks in advice for response, I'm trying to explain that to my 11 yo nephew :)
---EDIT after couple of years ---
Ok, time pass and now I see why my question was not formulated accurately. I misguided you by using term const pointer referring to array name before and after passing it function. To rephrase, question boils down to:
Why this is not allowed:
char charTab[] = "ABCDEFGHIJKLMNOPRSTUWXYZ"; /* Basic data buffer */
charTab += 3; /* No, the lvalue required for '+' operand */
While this is allowed:
char charTab[] = "ABCDEFGHIJKLMNOPRSTUWXYZ"; /* Basic data buffer */
void CharTabMove(char *tabToMove, int noToMove)
{
tabToMove += noToMove;
}
CharTabMove(charTab)
And the answer is as I gathered and refined all of your answers, charTab acts almost like constant pointer to first element of array, but essentially is not an lvalue or a pointer statement, so arthmetic operations are not allowed. When passing it to function, this almost like constant pointer to first array element will be casted and passed by value as regular pointer, so operations can be executed on it.
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so pa=a and pa++ are legal. But an array name is not a
variable; constructions like a=pa and a++ are illegal. here pa is pointer.
charPtr += 3; ==> this is allowed because this is pointer , pointer arithmetic is allowed and you can change the location of pointer.
charTab += 3; ==> here this is illegal.you should not change the position of array.
and
tabToMove ==> is character pointer.you can modify it.
First of all, the name of the array is not a constant pointer, it is just name of the array; the point is that an array in almost any context decays to a pointer to the first element of the array.
The array by itself cannot be incremented, but, once it decays to a pointer to the first element and is assigned to some pointer variable, it can be incremented (the second step is fundamental, since, to increment something, you must have an lvalue).
Now, functions cannot directly receive arrays as parameters (even if you write an array in the function signature it's implicitly interpreted as a pointer), so, when you pass an array to a function it surely decays to a pointer to its first element, and it's used to initialize the parameter of the function, which then can be incremented as you wish: in facts, the parameter tabToMove is just a local variable of type char * which is initialized with the passed argument, i.e. the pointer to the first element of the array.
In other words, if you write
char foo[]="asdasdas";
CharTabMove(foo, 5);
is like you were doing
char foo[]="asdasdas";
char *tabToMove=foo;
int noToMove=5;
CharTabMove(tabToMove, noToMove);
charTab is an array; charPtr and tabToMove are pointers. If you were able to change charTab you'd effectively lose track of where the beginning of the array is. If you change charPtr or tabToMove you don't have the same problem -- they're copies of the pointer to the beginning of the array.
but why the function is allowed to move the constant pointer?
It's not a constant pointer -- you've declared it as char *.
You cannot change a const pointer.
Actually, in the function, you just change a non-const pointer which just has the same value(passed by value when calling function) of your const point.

Difference between char[] and char* in function call

I have found myself unable to explain why the following piece of code works. Needless to say, I am quite new to C++...
#include <cstdio>
void foo(char* p)
{
p[0] = 'y';
}
int main()
{
char a[1];
a[0] = 'x';
printf("a[0] = %c\n", a[0]);
foo(a);
printf("a[0] = %c\n", a[0]);
return 0;
}
This program outputs
a[0] = x
a[0] = y
What intrigues me us that I am not passing a pointer, but an array, to foo. So how can foo change the value of the array a? Does this apply only to arrays of char?
The answer to Difference between char and char[1], confirms my observation, but it does not go into detail about why this is the case.
Thanks!
When you're passing an array to a function it decays to a pointer to the first element.
The following are completely equivalent:
void foo(char* p);
void foo(char p[]);
void foo(char p[42]); /* Or any other number. */
Does this apply only to arrays of char?
It applies to any array. I recommend the aryptr section of the C FAQ.
In C, arrays, in most contexts (*), decay into a pointer to their first element.
In your case, the array a decays into a pointer to a[0].
The array int arr[12][23], when used just by its identifier, decays to a pointer to its first element, namely arr[0], which is of type int (*)[23] (pointer to array of 23 ints).
(*) Arrays do not decay when used as the argument to the sizeof operator, or when used as argument to the & operator or when used as initializer (a string literal) for a character array.
When You say
char a[5];
the compiler allocates 5 sequential blocks of memory, and the address of the first block is assigned to a. So by definition name of the array (a in our case) is just a pointer to a memory location.
Now when we say a[0], compiler manipulates it as *(a+0*sizeof(array datatype i.e. char, int etc.)), symbolically a[i] is represented as *(a+i*sizeof(array datatype i.e. char, int etc.))
As far as function parameter passing is concerned When we pass an array to a function basically it is just the address of the first element which is passed. For more details regarding this plz follow this link or read the #cnicutar's answer (as he has already posted a correct answer there is no point repeating that again)...
You can try this to convince yourself how this works.
int a[8], *p;
p = a;
printf("%p, %p, %p\n", a, &a[0], p);
An array is nothing more than a pointer (to the first element), at least for argument passing sake.
The three prototypes here are equivalent:
void foo(char *p);
void foo(char p[]);
void foo(char p[42]);
C says a declaration of parameter of type array of T is adjusted to a declaration of type pointer to T.
Array name points to the address of the first element of the array. Please refer: Is an array name a pointer?

Does an Array variable point to itself?

I tried some code to check the behavior of array and pointers. Its as follows.
#include <stdio.h>
main(){
int s[]={1,2};
int *b=s;
printf("%d, %d, %d\n", s, &s, *s);
printf("%d, %d, %d\n", b ,&b, *b);
}
Initially I thought of pointers and array to be same BUT...
To my surprise the value of 's' and '&s' are SAME unlike 'b'. Does that mean an Array variable "points to itself?"
I am also now confused with what actually is a variable "name"? How its binding takes place with a location in memory? I am just unable to visualize things that go on there!
And where in memory (RAM) is all the information stored at run time?
OK, let say the following is how the memory looks when you execute
int s[]={1,2};
int *b=s;
s[]
+-----+-----+
| 1 | 2 |
+-----+-----+
100 104
^
|
| int *b = &s
+-----+
| 100 |
+-----+
200
s is an array. What that means is, it is a contiguous memory location which is associated with a variable s and each element is accessed by offsetting the array variable name.
So when you use s it actually boils down to the address of the array (which is 100 in this case). And when you do *s, it boils down to *(s+0) which is equivalent of s[0] and so *s represents the contents stored in the zeroth location (in this case s[0] is 1). When do do an &s, this will print the address of the s (which is100` in this case).
Note that, here s and &s represents an address; *s and s[x] represents an integer.
The same applies to the pointer. So, b prints the content it has, which is the address of s (which is 100 in this case). &b prints the address of b, which is 200 in this case. And, *b prints the content of the first element of the array s which is 1.
I have modified you program to make it print the address.
#include <stdio.h>
int main(void)
{
int s[]={1,2};
int *b=s;
printf("%p, %p, %d\n", (void *)s, (void *)&s, *s);
printf("%p, %p, %d\n", (void *)b, (void *)&b, *b);
return 0;
}
Output:
0xbfc4f3e4, 0xbfc4f3e4, 1
0xbfc4f3e4, 0xbfc4f3ec, 1
EDIT: %p expects void *. Added the same!
An array, when used as an argument to a function, decays into a pointer to its first element. Similarly, taking the address of an array results in a pointer to the location of the first element (but with a different type).
As for your second question, a variable name only exists at compile-time. It typically has no representation in memory at runtime.
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be replaced with an expression of type "pointer to T", and the value of the expression will be the address of the first element in the array.
Assume the following code:
int arr[10];
foo(arr);
In the call to the function foo, the expression arr is converted from type "10-element array of int" to "pointer to int", and the address of the first element of arr is what actually gets passed to foo.
We would define foo as either
void foo(int a[]) {}
or
void foo(int *a) {}
In the context of a function parameter declaration, T a[] and T a[N] are identical to T *a; the parameter is a pointer type, not an array type. Note that this is only true for function parameter declarations.
As mentioned above, one exception to this rule is when the array expression is the operand of the unary & operator. If we change the call to foo to read
foo(&arr);
then the type of the expression &arr is "pointer to 10-element array of int", or int (*)[10], and the value of the expression is the address of a. For this, the definition of foo would be
void foo(int (*a)[10]) {}
In C, the address of the array and the address of the first element of the array are the same - thus both of the expressions arr and &arr have the same value, but their types are different. This matters for operations involving pointer arithmetic. For example, assume our code had been written
int arr[10];
foo(arr);
...
void foo(int *a)
{
...
a++;
...
}
On entry, a points to arr[0]. The expression a++ would advance the pointer to point to the next integer in the array (arr[1]).
Now assume the code had been written as
int arr[10];
foo(&arr);
...
void foo(int (*a)[10])
{
...
a++;
...
}
On entry, a still points to arr[0] (remember, the address of the array is the same as the address of the first element of the array), but this time the expression a++ will advance the pointer to point to the next 10-element array of integers; instead of advancing the pointer sizeof (int) bytes, we advance it sizeof (int[10]) bytes.
So this is why in your printf statement you see the same values for both s and &s. You should use the %p conversion specifier to print pointer values, and it expects the corresponding argument to be type void *, so change those printf statements to
printf("%p %p %d\n", (void *) s, (void *) &s, *s);
printf("%p %p %d\n", (void *) b, (void *) &b, *b);
A simple way to think about this is that an array as a pointer can't be changed by assignment, it is effectively a constant pointer to a known amount of memory.
To try that, use:
myptr = myarray;
Which is perfectly ok, and then try:
myarray = myptr;
Which is not.