Why cannot we change the base address of an array [duplicate] - arrays

This question already has answers here:
Why can't I increment an array?
(5 answers)
Is an array name a pointer?
(8 answers)
Closed 1 year ago.
I have an array arr say
int arr[3] = {1, 2, 3};
so as per my knowledge this arr is just like any variable that has a name arr just like
int a = 4;
a is an integer variable that asks 4 bytes of memory. And arr asks 3 * 4
= 12 bytes of memory and arr has properties like 12 bytes of memory and when used as an Rvalue it decays to a
(pointer value not a pointer variable)
so as it decays to a pointer value like &arr[0] we can use a pointer variable to point (grab the address)
int* ptr = arr; //here arr implicitly converts to &arr[0]
so here arr and ptr have the same address but ptr is like copied the memory of &arr[0] and stores it. Whereas arr is literally the address in the memory which only decays like &arr[0] when used as Rvalue.
if we do something like
arr++;
complier throws error as Expression must be a modifiable lvalue
As the arr is allocated on the stack we cannot change the address
because we are asking cpu to change the address of the array, if we change it we loose the array address and cannot further access it
Code
#include <stdio.h>
int main()
{
int arr[3] = { 1, 2, 3 };
arr++; // not allowed
int* p = arr;
p++; // allowed because its a copy of (arr) address.
return 0;
}
That's how what i know and correct me with more resources.

arr is not a pointer, it's an array. When you use the word arr the compiler may convert it to a pointer for you - it does &arr[0] automatically, and gets the address of the first element, which is a pointer value, not a pointer variable. And you can't change values. You can't do (&some_variable)++;, you can't do 5++;, and you can't do (&arr[0])++; which is what arr++; would mean.

Arrays are not pointers.
Consider the following demonstrative program.
#include <stdio.h>
int main(void)
{
int arr[3] = { 1, 2, 3 };
int *p = arr;
printf( "sizeof( arr ) = %zu\n", sizeof( arr ) );
printf( "sizeof( p ) = %zu\n", sizeof( p ) );
return 0;
}
Its output might look like
sizeof( arr ) = 12
sizeof( p ) = 8
Arrays are non-modifiable lvalues. That means that you for example can not assign one array to another or apply an increment operator.
On the other hand, arrays used in expressions are implicitly converted (with rare exceptions) to pointers to their first elements.
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
So for example in this declaration
int *p = arr;
the array arr used as an initializer expression is implicitly converted to pointer to its first element that has the type int *.
To set the pointer p to point to the second element of the array arr you could use the pointer arithmetic the following way
int *p = arr + 1;

Related

Is the array variable a pointer, which points to the first element of an array? [duplicate]

This question already has answers here:
What is array to pointer decay?
(11 answers)
Is an array name a pointer?
(8 answers)
Closed 1 year ago.
I read this on the internet that an array variable points to the first element of an array. The example of the code is given below :
#include <stdio.h>
int main()
{
int i,a[10];
for ( i = 0; i <= 9; ++i )
{
printf ("The address of the array element %d is = %p\n",i+1, &a[i]);
}
printf ("The address of the &a is = %p\n", &a);
printf ("The address of &a[0] is = %p\n", &a[0] );
printf ("The address of a is = %p", a);
return 0;
}
according to the internet source : The array variable a and the array element a[0] both have the same address because the array variable name a points to the first element of the array, i.e. a[0]. My question is :
Is the array variable a a pointer, since it's pointing to the first element of the array?
If the array variable a is a pointer, then shouldn't the address of the pointer a and the variable a[0] (to which the pointer a is pointing) differ? (here we get the same address)
If the array variable a is not a pointer then how shall we explain the code given below?
a[0] = *a
a[1] = *a+1
a[2] = *a+2
a[3] = *a+3
a[4] = *a+4
a[5] = *a+5
I suppose this is a very long question but please, do tell me the answer as I have wrecked my mind over this and now I want to beat my head against the wall. Also I am new to stack overflow.
Arrays are not pointers. To be sure run this simple program
#include <stdio.h>
int main( void )
{
int a[10];
printf( "sizeof( a ) = %zu\n", sizeof( a ) );
printf( "sizeof( &a[0] ) = %zu\n", sizeof( &a[0] ) );
}
Its output might look like
sizeof( a ) = 40
sizeof( &a[0] ) = 8
But array designators used in expressions with rare exceptions are indeed implicitly converted to pointers to their first elements.
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
As for your question
If the array variable a is not a pointer then how shall we explain the
code given below?
a[0] = *a
a[1] = *a+1
a[2] = *a+2
a[3] = *a+3
a[4] = *a+4
a[5] = *a+5
then after reading the provided quote from the C Standard it is clear that the array designator a in this expression *a is converted to pointer to its first element. That is you have in fact *( &a[0] ) or just a[0]. And the above records are equivalent to
a[0] = a[0]
a[1] = a[0]+1
a[2] = a[0]+2
a[3] = a[0]+3
a[4] = a[0]+4
a[5] = a[0]+5
As for your question about addresses then the expression &a and &a[0] have the same value because it is the value of the address of the first byte occupied by the array. However types of the expressions are different. The expression &a has the type int ( * )[10] and the expression &a[0] has the type int *.

Compiler error while incrementing the address in a character array [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is array name a pointer in C?
Suppose I have a char array say arr and arr will represent the address of first element so arr++ should be perfectly legal then why compiler says 'lvalue required'.
Also if I do:
arr=arr+1 then why it is invalid conversion. I am just increasing pointer by one. Compiler tells that on LHS the operand type is char[4] but on RHS it is char *.
main()
{
char arr[]={'a','b','c','d'};
for(;arr!=arr+4;arr++) //lvalue required
printf("%c",*arr);
}
An array name is not a variable that can be assigned to. If you want to modify it, you should use a pointer variable:
char *arr_ptr = arr;
You can then do arr_ptr++ and arr_ptr = arr_ptr+1;
Arrays aren't pointers. arr does not represent an address.
An array name, or any expression of array type, is implicitly converted to a pointer to the array's first element unless it's either:
The operand of a unary & (address-of) expression (which yields the address of the whole array, not of its first element -- same memory address, different type); or
The operand of a sizeof operator (sizeof arr yields the size of the array, not the size of a pointer); or
The operand of an _Alignof operator (_Alignof arr yields the alignment of the array, not the alignment of a pointer); or
A string literal in an initializer that's used to initialize an arrary object.
_Alignof is new in C2011.
(The conversion is often referred to as a "decaying".)
None of these apply here, so arr++ tries to increment a pointer object. The problem is, there is no pointer object, just a pointer value. arr, after it decays to a pointer value, is not an lvalue, which means it cannot appear on the left side of an assignment or as the operand of ++.
Similarly, given:
int x;
the expression x is an lvalue, so you can write x = 42; -- but the expression (x + 1) is not an lvalue, so you can't write (x + 1) = 42;. You can assign to x because it refers to an object. (x+1) doesn't refer to an object, so there's nothing to assign to. arr, after it decays, doesn't refer to an object either (you have an array object, but there's no pointer object).
(Your use of arr != arr + 4 should have been a clue; that can never be true.)
Rather than this:
char arr[] = {'a', 'b', 'c', 'd'};
for (; arr != arr + 4; arr++) {
printf("%c", *arr);
}
you can write this:
char arr[] = {'a', 'b', 'c', 'd'};
char *ptr;
for (ptr = arr; ptr != arr + 4; ptr++) {
printf("%c", &ptr);
}
Incidentally, at the top of your program, you should change this:
main()
to this:
#include <stdio.h>
int main(void)
Also, run, do not walk, to the comp.lang.c FAQ and read section 6, "Arrays and pointers".

Why isn't this pointer arithmetic allowed in C? [duplicate]

This question already has answers here:
Is array name a constant pointer in C++?
(2 answers)
Closed 6 years ago.
char arr[] = "Hello";
arr = arr + 1; // error occurs
As far as I know, an expression that has array type is converted to pointer type that points to the initial element of the array. Therefore, I expected arr = arr + 1 (pointer to first element(arr) of the array becomes the pointer to the second element of the array)to work. Why doesn't this work in C?
arr + 1 is indeed a pointer to the second element of the array (i.e. &arr[1]).
However, that does not mean that you can somehow write that pointer value back into arr. You can't do it for at least two reasons.
Firstly, arr is an array of char elements, not a pointer. There's an obvious type mismatch here.
Secondly, being an array, arr a non-modifiable lvalue. You cannot change arr itself, you can only change its elements (this distinction is somewhat hard to grasp, but it is there).
Finally, if we just ignore the deeper intricacies and focus on what formally happens at the top level, due to array type decay your expression is equivalent to
(char *) arr = (char *) arr + 1;
The assignment is impossible since the left-hand side is a result of [implicit] type conversion. In C type conversions always produce rvalues. You cannot assign to rvalues.
In other words, it is not the "pointer arithmetic" that's disallowed here. The pointer arithmetic is fine. It is what you do with the result of that pointer arithmetic that causes the error.
Arrays are non-modifiable lvalues. They can't be the left operand of an assignment operator.
C11-§6.3.2.1:
A modifiable lvalue is an lvalue that
does not have array type, does not have an incomplete type, [...]
§6.5.16/2:
An assignment operator shall have a modifiable lvalue as its left operand.
In the statement
arr = arr + 1;
arr is the left operand of = operator and is of array type. It can't be modified.
So, it's not the pointer arithmetic but the constraint by the language on the assignment operator that is the reason for syntactical error.
Note that in some contexts arrays decay to a pointer to its first element, though pointers and arrays are different types. Arrays are not pointers. It is only the pointer arithmetic and array indexing which are equivalent. For example
char *ptr = &arr[0] + 1 => &(*(arr + 0)) + 1 => &(*arr) + 1 => arr + 1 // * and & nullify each other
This is because arrays are similar to pointers except that they can not be modified. However you can modify a pointer that is pointing to an array. For the above example you can do like this:
char arr[]="Hello";
char *ptr=arr;
ptr=ptr+1;
Initially the pointer ptr will be pointing to the first character of the array i.e. 'H' and after modifying the value it will point to the second character i.e. 'e'. You can also do the following:
char arr[]="Hello";
char *ptr=arr;
ptr=arr+1;
Both produce the same effect which shows that arr+1 is indeed pointer arithmetic. However you can not modify the value of arr because its type is that of a character array and not pointer to a character array.
As far as I know, an expression that has array type is converted to pointer type that points to the inital element of the array.
It is true in most contexts. It is not true in the following contexts:
When using the addressof operator (&arr). The type of &arr is char (*)[6]. It is not char**.
When using the sizeof operator. sizeof(arr) is 6. Had it been a pointer, it would be the size of a pointer (4 or 8 in most common platforms).
When used as the LHS of an assignment operator. A variable of array type is not modifiable.
Therefore, I expected arr = arr + 1 (pointer to first element(arr) of the array becomes the pointer to the second element of the array)to work. Why doens't this work in C?
The RHS of the expression evaluates to a pointer to the second element of arr. However, that line does not work due to (3) above. arr is not a modifiable value. It cannot be used as the LHS of an assignment operator.
char[] is not pointer, while char* is a pointer.
This works, but it is wrong solution:
int main()
{
char *arr = "Hello";
arr = arr + 1; // Wrong!
printf("%s\n", arr); // Output: ello
}
If arr is heap-allocated with malloc you can get memory leak if free memory starting arr+1 not arr.
But you can do something like this:
int main()
{
char arr[] = "Hello";
char *wordFromSecondLetter = &arr[0] + 1;
printf("%s\n", wordFromSecondLetter); // Output: ello
}
Or like this
int main()
{
char arr[] = "Hello";
printf("%s\n", &arr[1]); // Output: ello
}
Because arr is not a pointer but a char array. You can verify this by checking sizeof arr. To get a pointer to char, you should use char *arr = "Hello";.
The biggest difference between a pointer and an array is that you can directly assign a value to a pointer, but you can't do this to an array.
In fact, when you write arr + 1, arr "decays" to the pointer to its first element, that is to say, arr == &arr[0]. So arr + 1 is legal pointer arithmetic, but giving its value to arr, which is an array, is illegal.

Does C compiler allocates memory for variable name used for declaring an array?

Let us take an example :--
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = NULL;
For the variable arr, will there be any memory allocation ??
Now, what will happen if =>
p = arr;
p = &arr;
p = &arr[0];
Please help me out to understand this.
This declaration:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
causes 10 * sizeof (int) bytes to be allocated to hold the 10-element array object. (No space for any pointer object is allocated.) The array is initialized as specified.
int *p = NULL;
creates a single pointer object and initializes it to contain a null pointer value.
p = arr;
arr is an expression of array type. In most contexts, its value is implicitly converted to a pointer to its first element. So this assignment causes p to point to the first (0th) element of arr; *p == 1.
p = &arr;
This is invalid. &arr is of type int(*)[10], or pointer to array of 10 ints. p is of type int*. The types are incompatible. Any conforming C compiler must diagnose this error. (The diagnostic may be a non-fatal warning, but don't let that fool you; it's still an error, what the C standard calls a "constraint violation".)
p = &arr[0];
This is identical to p = arr;. arr[0] is the first (0th) element of the array, an int object with the value 1. &arr[0] is the address of that int object, and is of type char*. So this also causes p to point to the initial element of the array arr.
After this assignment, you can use either arr or p as the prefix for an indexing operator. The indexing operator is actually defined to take a pointer, not an array, as its prefix, so arr[0] uses the result of the array-to-pointer conversion, making it identical to p[0].
But arr and p still cannot always be used interchangeably. For example, sizeof arr gives you the size of the array object (10 * sizeof (int)), while sizeof p gives you the size of a pointer (sizeof (int*)).
Suggested reading: Section 6 of the comp.lang.c FAQ.
(To answer the question in your title, the compiler doesn't, or at least isn't required to, allocate memory at run time for the name of an array. It won't allocate 3 bytes of memory at run time because you named your array arr, or 22 bytes because you called it array_with_a_long_name. It might do so for debugging purposes, but then any such allocated space isn't accessible to your program.)
arr[10] creates locations for 10 ints.
p = arr ;
p= &arr[0] ;
are the same thing.
&arr is not something generally useful. It is a int (*)[10] which the compiler should complain about assigning to p.
In fact, if you do a little test and print out the addresses of these three:
printf("X: %lx %lx %lx\n", (long) arr, (long) &arr, (long) &arr[0]) ;
gcc ends up giving you the same thing for all three cases.
% ./a.out
X: 7fff906b5b20 7fff906b5b20 7fff906b5b20
But where you can really see the difference is if you ask for each item +1 :
printf("X: %lx %lx %lx\n", (long) arr, (long) &arr, (long) &arr[0]) ;
printf("X+1: %lx %lx %lx\n", (long) (arr +1), (long) ( &arr +1) , (long) ( &arr[0] +1 )) ;
% ./a.out
X: 7fff73c105b0 7fff73c105b0 7fff73c105b0
X+1: 7fff73c105b4 7fff73c105d8 7fff73c105b4
arr +1 is four bytes larger than arr (the size of an int), as is &arr[0] +1, but &arr +1 is forty bytes larger, the size of the entire array.
Storage is not set aside for variable names (arrays or otherwise), except to support debuggers.
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize an array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of this expression will be the address of the first element of the array.
So, taking your three cases:
p = arr;
The expression arr has type "10-element array of int". Since it is not the operand of either the sizeof or unary & operators, it is converted to an expression of type "pointer to int", or int *, and its value is the address of the first element of the array.
p = &arr;
The expression arr has type "10-element array of int". Since arr is the operand of the unary & operator, the conversion above is not performed; instead, the type of the expression &arr is "pointer to 10-element array of arr", or int (*)[10]. The value is the same as the above expression (the address of the array is the same as the address of the first element of the array), but the types of the two expressions are different (int * vs. int (*)[10]), and types matter for things like pointer arithmetic.
p = &arr[0];
Gives the same type and result as p = arr;.
For your array, storage is set aside as follows:
+----+
arr[0]: | |
+----+
arr[1]: | |
+----+
... ...
+----+
arr[9]: | |
+----+
Note that there is no separate storage for a variable named arr that points to the beginning of the array; that pointer value is inferred from the array expression as described above. You can assign to arr[N], but there's no separate arr to assign anything to (part of the reason why array expressions are non-modifiable lvalues).

"lvalue required" error when trying to increment array [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is array name a pointer in C?
Suppose I have a char array say arr and arr will represent the address of first element so arr++ should be perfectly legal then why compiler says 'lvalue required'.
Also if I do:
arr=arr+1 then why it is invalid conversion. I am just increasing pointer by one. Compiler tells that on LHS the operand type is char[4] but on RHS it is char *.
main()
{
char arr[]={'a','b','c','d'};
for(;arr!=arr+4;arr++) //lvalue required
printf("%c",*arr);
}
An array name is not a variable that can be assigned to. If you want to modify it, you should use a pointer variable:
char *arr_ptr = arr;
You can then do arr_ptr++ and arr_ptr = arr_ptr+1;
Arrays aren't pointers. arr does not represent an address.
An array name, or any expression of array type, is implicitly converted to a pointer to the array's first element unless it's either:
The operand of a unary & (address-of) expression (which yields the address of the whole array, not of its first element -- same memory address, different type); or
The operand of a sizeof operator (sizeof arr yields the size of the array, not the size of a pointer); or
The operand of an _Alignof operator (_Alignof arr yields the alignment of the array, not the alignment of a pointer); or
A string literal in an initializer that's used to initialize an arrary object.
_Alignof is new in C2011.
(The conversion is often referred to as a "decaying".)
None of these apply here, so arr++ tries to increment a pointer object. The problem is, there is no pointer object, just a pointer value. arr, after it decays to a pointer value, is not an lvalue, which means it cannot appear on the left side of an assignment or as the operand of ++.
Similarly, given:
int x;
the expression x is an lvalue, so you can write x = 42; -- but the expression (x + 1) is not an lvalue, so you can't write (x + 1) = 42;. You can assign to x because it refers to an object. (x+1) doesn't refer to an object, so there's nothing to assign to. arr, after it decays, doesn't refer to an object either (you have an array object, but there's no pointer object).
(Your use of arr != arr + 4 should have been a clue; that can never be true.)
Rather than this:
char arr[] = {'a', 'b', 'c', 'd'};
for (; arr != arr + 4; arr++) {
printf("%c", *arr);
}
you can write this:
char arr[] = {'a', 'b', 'c', 'd'};
char *ptr;
for (ptr = arr; ptr != arr + 4; ptr++) {
printf("%c", &ptr);
}
Incidentally, at the top of your program, you should change this:
main()
to this:
#include <stdio.h>
int main(void)
Also, run, do not walk, to the comp.lang.c FAQ and read section 6, "Arrays and pointers".

Resources