For example,
I declared variable like this,
char szBuffer[12] = {"Hello"};
char szData[12] = {"Cheese"};
szBuffer = szData;
is error, since szBuffer can't be l-value.
szBuffer has its own address, for example, 0x0012345678, and szBuffer's value is also its address, 0x0012345678.
So I think "array name can't be l-value" means that an array's address and its value have to be equal.
Am I right?
If I'm right, why do they have to be equal?
array name can't be l-value
It means an array can not be used as l-value or left hand side of the assignment operator (not to be confused with initialization). An l-value must be modifiable. You can modify the contents of array but not the array itself.
In C you can not assign to arrays. Though you can intialize them.
You should use strcpy(szBuffer, szData) or memcpy(szBuffer, szData, 12).
Also there is no need of {} in the initialization from string literal.
If you insist on using operator =, you need to put your string in a struct because struct object copy is allowed in C.
ex:
struct string {
char name[12];
};
struct string szBuffer = {"Hello"};
struct string szData = {"Cheese"};
szBuffer = szData;
No, it won't mean such a thing.
Array's address isn't value of array in general.
Arrays in expression except for operands of sizeof and unary & operator are automatically converted to pointers to first arguments of that array.
Therefore, the converted pointer is not an l-value and you cannot assign there.
array name can't be l-value means that array names cannot be used on the left side of an =.
To be more clearer, you need a modifiable l-value on the left side of a =
Arrays are modifiable l-value when they are used with indices like arr[i].
But array name themselves are not, and hence cannot be used on the left side of a =
An L-value is something that can appear on the left hand side of an assignment. Examples: Scalar variables, array elements, pointer dereferences. An array name is not an L-value in C. Instead, you can do one of two things: (1) a pointer assignment, if you just need a pointer to the array, or (2) an array copy, if you really need to copy the array itself.
Related
In C language, an Array is a collection of same data type, that is when we are defining an array like this :
int my_list[50];
we are allocating 50 consecutive location in the computer memory to store 50 integer.
when somebody says my array is "my_list", what does it mean? does it collectively denotes all the 50 spaces that I have defined in the memory?
if that is the case , when I'm trying to learn pointers, they say, no no, there is a pointer whose name is "my_list" and it points to my_list[0];
my conclusions are like this:
"my_list" does denote all the 50 memory location collectively, but when we are defining the array , the machine is generating a pointer whose name is "accidentally" "my_list" and it points to my_list[0];
array my_list denotes all the 50 location collectively and pointer my_list only points to my_list[0], though their name overlaps they are totally different things.
please correct me if i'm wrong.
does it collectively denotes all the 50 spaces that I have defined in the memory?
Yes, my_list is the array.
… they say, no no, there is a pointer whose name is "my_list" and it points to my_list[0];
“They” are wrong. There is no pointer named my_list.
However, when an array is used in an expression, it is automatically converted to a pointer to its first element except when it is the operand of sizeof, is the operand of unary &, or is a string literal used to initialize an array.
Thus, if you, for example, use my_list like a pointer, as in int *p = my_list + 5;, or you pass it to a function, as in foo(50, my_list);, then it is automatically converted to a pointer, as if you had written int *p = &my_list[0] + 5; or foo(50, &my_list[0]);.
For the exceptions: With sizeof, sizeof my_list gives the size of the whole array, the size of 50 int. There is no automatic conversion to a pointer, so sizeof my_list does not give the size of a pointer. And with unary &, &my_list is a pointer with type “pointer to array of 50 int” rather than a pointer with type “pointer to pointer to int”.
(An array you declare with a name, like my_list, is of course not a string literal. A string literal can be used to initialize an array, as in char MyString[] = "Hello";. In this case, the array formed by the string literal is used to initialize buffer; it is not converted to a pointer.)
Let's say we have
int foo[4] = {1, 2, 3, 4};
foo would then be a pointer to the first element of the array.
We can do:
printf("%p", foo); // OUTPUT is some address 0xffffcc00
Now if we do:
printf("%p", &foo); // OUTPUT is the same address 0xffffcc00
Looking online, I see this particular syntax for &<array-name> takes the address of the entire array. This explains the two same values above, because the starting element's address is the same as the whole array's address.
But in general, my understanding is that & should take address of whatever is on its right. (i.e. in this case, it "should" have taken the address of the pointer to the first element of the array.)
So why isn't &foo taking the address of the pointer foo?
If this is an exception to the C language, is this the only exception, or are there other cases like this?
There is a common misconception that pointers and arrays are the same thing. They are not, but they are related.
Your first example works:
printf("%p", foo);
Because in most contexts an array decays to a pointer to the first element of the array.
One of the situations where this is not the case is when an array is the operand of the address-of operator &. This gives the address of the entire array, not just the first element (even though the values are the same).
This is detailed in section 6.3.2.1p3 of the C standard:
Except when it is the operand of the sizeof operator, the
_Alignof 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.
Basically, Pointers used to access array elements in a alternative
ease way.In Low level Programming, each and every variable has an
address to allocate in memory. BTW, the array is also a variable
name as like scalar variable.
Unlike Scalar Variables, Array variable has few things.,
List(sequences) of elements allocated in subsequent memory address.
So we can get all the elements by using first element address
FYI, Array Name == Address of the first element == Address of the array
(foo == &foo == &foo[0])
So while you are trying to get elements by using this notation foo, initially it points to (&foo + 0) , so based on ith value you can access all the elements one by one.
Hope this Answer will helps.:)
I prefer using this explanation about '& basically means "the address-of operator"' thesis. So, Arrays are not pointers! But an array can automatically "decay" into a pointer. Into &foo[0], in your case. But &foo is a pointer to an array of four integers because of its type. To get PoC you need to check ptype foo vs ptype &foo under GDB.
Im trying to create a 2d array for multiple data types but it seems to not be accepting the char data type. Why is this?
struct {
union {
int ival;
float fval;
char cval[50];
} val;
} as[120][4];
as[0][1].val.cval = "Testtttt"; ***This does not work***
as[1][1].val.ival = 3; ***This works***
You are in c, thus you should use string.h when it comes to string handling!
Change this:
as[0][1].val.cval = "Testtttt";
to this:
strcpy(as[0][1].val.cval, "Testtttt");
by using strcpy(), instead of the assignment operator (this would work in c++, not in c).
Of course, alternative functions exist, such as strncpy()* and memcpy().
Moreover, since C string handling seems new to you, you must read about null terminated strings in C.
*Credits to #fukanchik who reminded me that
In C, this code
as[0][1].val.cval
can not be assigned to. Per the C Standard, 6.3.2.1 Lvalues, arrays, and function designators:
Except when it is the operand of the sizeof operator, the _Alignof
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.
Without getting too in-depth into the C Standard, an lvalue is something you can assign something to. Thus, this code
as[1][1].val.ival
represents an lvalue and you can assign 3 to it.
The reason an array can't be assigned to is because it decays to "an expression with type ‘‘pointer to type". In other words, a bare array like
as[0][1].val.cval
is treated as the address of the array.
And the address of the array is where it is and is not something that can be assigned to.
Your val.cval members are arrays of char. String literals also represent arrays of char. C does not support whole-array assignment, regardless of the type of the array elements.
You can copy the contents of one array to another in various ways. strcpy() will do it for null-terminated arrays of char. memcpy() and / or memmove() will do it more generally, and of course you can always write an element-by-element copy loop.
You cannot copy the contents of one array to another using the = operator; you must use a library function like strcpy (for strings) or memcpy (for anything else), or you must assign each element individually:
as[0][1].val.cval[0] = 'T';
as[0][1].val.cval[1] = 'e';
as[0][1].val.cval[2] = 's';
...
as[0][1].val.cval[7] = 't';
as[0][1].val.cval[8] = 0;
Remember that in C, a string is a sequence of character values terminated by a 0-valued byte. Strings (including string literals like "Testtttt") are stored as arrays of char, but not all arrays of char store a string.
I am having a tough time understanding the type and use of the name of the array in C. It might seems a long post but please bear with me.
I understand that the following statement declares a to be of type int [] i.e array of integers.
int a[30];
While a also points the first element of array and things like *(a+2) are valid. Thus, making a look like a pointer to an integer. But actually the types int [] and int* are different; while the former is an array type and later is a pointer to an integer.
Also a variable of type int [] gets converted into a variable of type int* when passing it to functions; as in C arrays are passed by reference (with the exception of the sizeof operator).
Here comes the point which makes me dangle. Have a look at the following piece of code:
int main()
{
int (*p)[3];
int a[3] = { 5, 4, 6 };
p = &a;
printf("a:%d\t&a:%d\n",a,&a);
printf("%d",*(*p + 2));
}
OUTPUT:
a:2686720 &a:2686720
6
So, how does the above code work? I have two questions:
a and &a have the same values. Why?
What exactly does int (*p)[3]; do? It declares a pointer to an array, I know this. But how is a pointer to an array different from the pointer to the first element of the array and name of the array?
Can anyone clarify things up? I am having a hell of a lot of confusions.
I know that I should use %p as a placeholder instead of using %d for printing the value of pointer variables. As using the integer placeholder might print truncated addresses. But I just want to keep things simple.
Other answers already explained the issue. I am trying to explain it with some diagram. Hope this will help.
When you declare an array
int a[3] = {5, 4, 6}
the memory arrangement looks like
Now answering your question:
a and &a have the same values.How?
As you already know that a is of array type and array name a becomes a pointer to first element of array a (after decay),i.e it points to the address 0x100. Note that 0x100 also is the starting address of the memory block (array a). And you should know that, in general, the address of the first byte is said to be the address of the variable. That is, if a variable is of 100 bytes, then its address is equal to the address of its first byte.
&a is address of the entire memory block, i.e it is an address of array a. See the diagram:
Now you can understand why a and &a both have same address value although both are of different type.
What exactly it does int (*p)[3]; Declares a pointer to an array,i know this.But,how a pointer to an array is different from the pointer to the first element of the array and name of the array?
See the above figure, it is explained clearly how pointer to an array is different from the pointer to an array element.
When you assign &a to p, then p points to the entire array having starting address 0x100.
NOTE: Regarding to the line
... as in C arrays are passed by references (with exception of sizeof function).
In C, arguments are passed by value. No pass by reference in C. When an ordinary variable is passed to a function, its value is copied; any changes to corresponding parameter do not affect the variable.
Arrays are also passed by value, but difference is that the array name decays to pointer to first element and this pointer assigned to the parameter (here, pointer value is copied) of the function; the array itself isn't copied.
In contrast to ordinary variable, an array used as an argument is not protected against any change, since no copy is made of the array itself, instead copy of pointer to first element is made.
You should also note that sizeof is not a function and array name does not act as an argument in this case. sizeof is an operator and array name serves as an operand. Same holds true when array name is an operand of the unary & operator.
a and &a have the same values.How?
They have the same value but different types. Array objects have no padding between elements (before or after) so the address of the array and the address of the first element of the array are the same.
That is:
(void *) a == (void *) &a
What exactly it does int (*p)[3]; Declares a pointer to an array,i know this.But,how a pointer to an array is different from the pointer to the first element of the array and name of the array?
These are two different pointer types. Take for example, pointer arithmetic:
a + 1 /* address of the second element of the array */
&a + 1 /* address one past the last element of the array */
EDIT: due to popular demand I added below some information about conversion of arrays.
With three exceptions, in an expression an object of type array of T is converted to a value of type pointer to T pointing to the first element of the array. The exceptions are if the object is the operand of sizeof or & unary operator or if the object is a string literal initializing an array.
For example this statement:
printf("a:%d\t&a:%d\n", a, &a);
is actually equivalent to:
printf("a:%d\t&a:%d\n", &a[0], &a);
Also please note that d conversion specifier can only be use to print a signed integer; to print a pointer value you have to use p specifier (and the argument must be void *). So to do things correctly use:
printf("a:%p\t&a:%p\n", (void *) a, (void *) &a);
respectively:
printf("a:%p\t&a:%p\n", (void *) &a[0], (void *) &a);
a corresponds to the pointer pointing at 0th element of the array. Whereas,the same is the case with &a.It just gives the starting address of the array.
As,a --> pointer pointing to starting element of array a[],it does not know about other element's location..
&a --->address location for storing array a[] which stores first element location,but knows every element's location.
Similarly,other elements location will be (a+2),(a+4) and so upto the end of the array.
Hence,you got such result.
int (*p)[3] is a pointer to the array. had it been int *p[3],it would been meant entirely different. It'd have meant an array of pointers which would have been totally different from this context.
Pointer to an array will automatically take care of all the other
elements in the array.In this case,your's is (p);
Whereas,the pointer to the first element of the array,i.e., a will
only know about first element of the array.You'll have to manually
give pointer arithmetic directions to access next elements.See,in this
case---we can get second element from a by adding 2 to a,i.e.
a+2,third element by adding 4 to a,i.e., a+4 and so on. // mind the
difference of two as it is an integer array!
In answer to question 1, this is simply an aspect of the C language as designed, unlike most other modern languages C/C++ allows direct manipulation of addresses in memory and has built in facilities to 'understand' that. There are many articles online that explain this better than I could in this small space. Here is one and I am sure there are many others: http://www.cprogramming.com/tutorial/c/lesson8.html
From C99 Standard n1124 6.3.2.1 p3
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.
a and &a have the same value because a long time ago you were required to use the address operator & on arrays to get the array's address, but it is no longer necessary. The name of the array (a in this case) these days just represents the memory address of the array itself, which is also what you get from &a. It's a shorthand that the compiler handles for you.
I have this code:
char *name[] = { "a1", "b2", "c3", "d4" };
printf("%s\n", *name); //the critical line
Related to critical line:
In this form, the output is simple: a1.
If I replace the critical line with:
printf("%s\n", ++*name);
then the output is 1. I think until now everything is good.
Taking in account that name is a pointer to the first string of characters, respectively "a1", I replace the critical line with:
printf("%s\n", ++name);
in the hope that I'll get "b2" result as output. But I get this error:
../src/test.c:32: error: lvalue required as increment operand.
Question: I can't understand why ++*name is legal - name is a pointer to first string of characters - and ++name isn't. In my opinion, the ++name should move the name to the next string of characters. Can anybody explain me where is the lack in my understing?
When you write ++name, the array name is converted to a pointer to the first element of the array. The result of this conversion is not an lvalue, and it can't be modified with ++ or otherwise. You could instead write name+1, which would print the right thing. When name is an array, there is no way to modify it to refer to anything other than that array[*].
Consider also:
char **p = name; // OK, `name' converts to pointer
++p; // OK, `p' is an lvalue
++(p+1); // not OK, `p+1' is not an lvalue
++((char**)p); // not OK, `(char**)p' is not an lvalue
++*name; // OK, `*name' is an lvalue
Roughly speaking, an "lvalue" is an expression that refers to an object, whereas a "not an lvalue" is an expression that has a value. The difference between an object and a value, is that an object is a place for storing values (well, one value at a time). Values can never be modified, objects sometimes can.
Whenever you have a subexpression which is an lvalue but whose current value is needed, the object is read/loaded/whatever you want to call it. In C++ this is called an "lvalue to rvalue conversion", I can't remember whether it's called anything in C other than "evaluating the subexpression".
[*] you can shadow it with another variable name in an inner scope, that refers to something else. But that's still not modifying the outer name, just temporarily hiding it.
name is an array, so, except when you use it as operand of the sizeof or & operators, it is evaluated as a pointer to the initial member of the array objet and is not an lvalue.
Accordingly, you can't modify name directly, with an operator such as ++ (remember that the postfix increment operator need a modifiable lvalue as operand). Otherwise, you can use a temporary pointer (p in the following example).
#include <stdio.h>
const char *name[] = { "a1", "b2", "c3", "d4" };
const char **p = name;
printf("%s\n", *p); /* Output: a1 */
*++p; /* or *p++ */
printf("%s\n", *p); /* Output: b2 */
While name points to the address of the first element, name is not of type char *, but char *[4]. therefore, sizof(name) == sizeof(char *)*4
Incrementing a pointer always means to add the size of the data it points to. So, after incrementing, it points behind the whole array. Just like if you have
int i, a;
int *p = &i;
p++;
p will now point behind i. It will point to a, if the compiler decided to put a behind i.
Also note that your array only contains 4 pointers, not 4 strings. Like above, it is the compilers choice where those strings actually are. So, the end of the first string is not necessarily next to the beginning of the second string. Especially if you assign other values (string adresses) to name[1] later. Therefore, you may cast name to char **, but should not cast to char *. Incrementing the former will point to the second element (second char* pointer).
First off, make sure you're totally happy and confident with the following fact: An arrays is not a pointer.
Second, what's in a name? The array decays into a pointer to the first element. After decay, the expression name has type char ** (pointer to first element of an array of char*. However, the decayed expression is an rvalue. You cannot modify it! And naturally so, since it makes no sense to modify a pointer that's a pointer to a fixed array.
Therefore, you cannot directly increment the pointer which is the result of decaying name, no more than you can say ++5 or ++foo() (where foo returns a primitive type by value)[whoops, that was a concession meant for C++].
What you can say is this:
char ** np = name;
++np;
printf("%s", *np);
This has the same effect as printing name[1], but now you also have a variable that holds a pointer to the second array element.