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

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".

Related

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

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;

Retrieving 2D array from pointer in C

I tried the following code
char arr[5] = {'A', 'E', 'I', 'O', 'U'};
char (*p_arr)[1] = &arr;
printf("%c\n", p_arr[0][4]); //returns 'U'
On this stackoverflow thread,
char (*p_arr2D)[m] = &arr2D //or arr2D
is also a syntax for the decay of a n*m 2D-array arr2D, returning a pointer to its first element, an array of m elements.
p_arr[0] seems to be the "reverse" array decay, retrieving a 2D array from a pointer to an array. How can that happen ? In the code snippet above, is p_arr interpreted as a 1*5 array (from the original 1D-array with 5 elements) ?
a 2D array is stored in memory like a 1D array How are multi-dimensional arrays formatted in memory?
the char (*p_arr)[1] = &arr; creates a pointer to an array of char pointers with one element ( (*p_arr)[1] ) and by the assignment &arr this pointer gets the address of an already existing array with 5 elements
so printf("%c\n", p_arr[0][4]); prints the 5th element ( U ) because by p_arr[0][4] adresses the 5th element in line 1
printf("%c\n", p_arr[1][4]); would give an error
so the reason why this code works is that a 2D array is stored in memory like a 1D array
This declaration
char (*p_arr)[1] = &arr;
is incorrect because the declared pointer and the initializer have incompatible types. There is no implicit conversion from the type char ( * )[5], the type of the initializer, to the type char ( * )[1], the ty[e of the declared pointer. So you need an explicit casting to reinterpret a pointer of one type as a pointer of another type as for example
char (*p_arr)[1] = ( char ( * )[1] )&arr;
As for your question then if you have an object of type T where T is some type
T obj;
and a pointer to the object like
T *ptr = &obj;
then expression *ptr or ptr[0] yields the referenced object of the type T.
So let's assume that you have the following declarations
char arr[5] = {'A', 'E', 'I', 'O', 'U'};
char (*p_arr)[5] = &arr;
For the type char[5] that is the type of the variable arr you can introduce a typedef name.
typedef char T[5];
Then the declarations will look like
T arr = {'A', 'E', 'I', 'O', 'U'};
T *p_arr = &arr;
As it was mentioned above the expression *p_arr or p_arr[0] yields the referenced object of the type T that is of the type char[5].
From the C Standard (6.5.3.2 Address and indirection operators)
4 The unary * operator denotes indirection. If the operand points to a
function, the result is a function designator; if it points to an
object, the result is an lvalue designating the object. If the operand
has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an
invalid value has been assigned to the pointer, the behavior of the
unary * operator is undefined.
And (6.5.2.1 Array subscripting)
2 A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).
and at last (6.5.6 Additive operators)
7 For the purposes of these operators, a pointer to an object that
is not an element of an array behaves the same as a pointer to the
first element of an array of length one with the type of the object as
its element type.
So in this declaration
char arr[5] = {'A', 'E', 'I', 'O', 'U'};
char (*p_arr)[5] = &arr;
the pointer p_arr does not point to an array element. However it can behaves as it points to the first element of an array of length 1. You can imagine it the following way
char arr[1][5] = { {'A', 'E', 'I', 'O', 'U'} };
char (*p_arr)[5] = arr;
So the expression p_arr[0] gives the first element of the imagined two-dimensional array that is an element of the type char[5].
To begin with, the line char (*p_arr)[1] = &arr; is not valid C. Your compiler must give a diagnostic message. p_arr is an array pointer to an array of 1 char, but you assign it to point at an array of 5 char.
As for why it seems like you have a 2D array - you don't have one - is because p_arr[0] works like any other pointer arithmetic, giving you pointed-at item "offset + 0". Which is the array. And then you access item 4 in the array.
A simple example of the very same pointer arithmetic principle would be this:
int a;
int* ptr = &a;
ptr[0] = whatever; // perfectly valid C
ptr[0] is guaranteed to be equivalent to *(ptr+0).
Correct use of the array pointer should be printf("%c\n", (*p_arr)[4]). In this case it happened to work, but in other cases you might invoke undefined behavior, since p_arr is not allowed to point beyond the allocated memory.
You are declaring p_arr to be a pointer to an array of chars (and that array is of length one which is a sure sign of a problem).
You may want the much simpler syntax:
char *p_arr = arr;
or maybe:
#include <stdio.h>
int main() {
char arr[] = {"Hello world"};
char *p[3] = {NULL, arr, NULL};
printf("%s %c\n", p[1], p[1][3]);
}
John

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.

"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".

calling to function [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C sizeof a passed array
instead of sending the sizeof:
void main()
int x[] = {1, 2, 3, 1, 3, 0, 6};
dupes(x, sizeof x / sizeof x[0]);
...
}
int dupes(int a[], int n)
...
...
why cant i call it with only the array:
int main()
{
int x[] = {1, 2, 3, 1, 3, 0, 6};
dupes(x);
...
}
int dupes(int a[])
{
int n = sizeof a / sizeof a[0];
when i do this the size always gets 1 - and it cant be 1 casue i'm sending an array with 7 elements!
sizeof is not a function, it a compiler operator (so you don't "call" sizeof, you just use the sizeof operator). The compiler has no way to know the size of the formal argument a for your function dupes (and treat is as int* a, i.e. a pointer formal).
sizeof is always computed at compile time.
Arrays decay into a pointer to their first element when they are passed to a function. sizeof only works if you pass the actual original array.
In other languages array references always carry the length along with them but the C philosophy is against this kind of hidden preformance penalty so you have to pass the length yourself.
This prototype in C:
int dupes(int a[])
{
}
is equivalent to this prototype:
int dupes(int *a)
{
}
You array argument a is converted to a pointer to int.
Regarding function declarators, this appears in 6.7.5.3p7 in C99 standard
A declaration of a parameter as ‘‘array of type’’ shall be adjusted to
‘‘qualified pointer to type’’, where the type qualifiers (if any) are
those specified within the [ and ] of the array type derivation.
Arrays in C are second class citizens, you cannot pass arrays to functions. You can just pass a pointer to the first element of the array.
So when you compute sizeof a, the result is the size of the pointer and not the size of the array.
sizeof a / sizeof a[0] in the body of your function actually computes this: sizeof (int *) / sizeof (int) which yields 1 in your system, because the size of an int * is the same as the size of an int in your system.
It's because when You pass an array to a function, it is copied into a pointer and the information about it's size is lost. In the called function it is just a normal pointer.
So size of (a) becomes 4 (because its a pointer) and sizeof (a[0]) is also 4 (because its an integer), so n equals 1
When an expression of type "N-element array of T" appears in most contexts, it is implicitly converted to an expression of type "pointer to T" and its value is the address of the first element in the array. The only exceptions to this rule occur when the array expression is an operand of the sizeof and unary & operators, or is a string literal being used to initialize an array in a declaration.
When you call dupes, the expression x is converted from type "7-element array of int" to "pointer to int", so the dupes function receives a pointer value, not an array. In the context of a function parameter declaration, T a[N] and T a[] are equivalent to T *a.
So in the dupes function, sizeof a / sizeof a[0] is equivalent to sizeof (int *) / sizeof (int), which in your case is 1.
sizeof a[0]; retruns the first element of the array
and when you pass an array it returns the address of the first element of the array so you have to specify the length also.
internally traversing an array as follow:
int a[]={1,2,3};
when you pass a[] as a function argument it sends the address of the element a[0] that is internal address of the 1 and calculates a[1] as
address of a[0] + size of int (type of an array)
when you type sizeof(a[]) it will return the sizeof(int pointer) as a[0] contains the internal address(integer pointer).
It's because you cannot pass an array directly to a function. You can only pass a pointer to an element within such an array.
In function parameters, the [] does not mean array, it means a pointer
int dupes(int a[])
is exactly the same as
int dupes(int *a)
When you use the name of an array as a value, it actually means the pointer to the 1. element in that array. And a pointer is just that, a pointer. It doesn't know it's pointing into an array of a given size.
So e.g. int *a = x; will assign a pointer to the first element in x to a- Same thing when you call a function, dupes(x) will pass a pointer to the first element in x as the argument to the dupes function. This is exactly the same as calling dupes(&x[0])
Inside the dupes() function, its argument is just a pointer. So sizeof x/sizeof x[0] is equivialent to sizeof(int*)/sizeof(int), which is 1 if your pointers are the same size as an int.
(However, since you passed a pointer to the 1. element in an array, you can increment that pointer to access the other elements. e.g. x + 2 will make x point to the 3. element (counting from 1) in that array. And if you dereference that pointer, you get its value: *(x + 2). And remember that as a value, x[2] is the same as *(x + 2)

Resources