suppose i have something like this
typedef char string[21]
struct planet_s
{
string name,orbits;
float distance;
string discoverer;
int yeardiscovered;
}one_planet;
next i need to initialize some information about the planet therefore my text book says
strcpy(one_planet.name, "Earth"); ?confused with these
strcpy(one_planet.orbits, "Sun"); ?
one_planet.distance = 150;
one_planet.mass = 6.00e+24;
strcpy(one_planet.discoverer, "me"); ?
one_planet.yeardiscovered = 1000;
my Confusion arises in the strcpy,let me put things in point form
Strcpy needs a pointer to a string as its first argument
does one_planet.name resolve into a pointer to the strcuts name array(does the dot operator resolve into an address)?
how come one_planet.distance =150 does not resolve into an address since we are assign it its value straight away? this is what i been taught, one_planet.distance directly access the struct element and assigns it. my confusion is with the strcpy, since it needs an address to store a string?
hope you understand where my confusion comes form thanks.
Except when it is the operand of the sizeof or unary & operator, or when it is a string literal being used to initialize another 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 the expression will be the address of the first element in the array.
In the line
strcpy(one_planet.name, "Earth");
the expression one_planet.name has type "21-element array of char"; since the expression is not the operand of the sizeof or unary & operators, it is converted to an expression of type "pointer to char", and the address of the first element of the array is passed to strcpy.
The . operator doesn't make a difference in this case; what matters is the type of the member, regardless of how that member is accessed.
The dot operator has nothing to do with this.
Compare your code to this:
int main(void)
{
char string[21];
strcpy(string, "Earth");
return 0;
}
the above is 100% natural and fine C code, and it relies on the fact that in some contexts, the name of an array (string) evaluates to just a pointer to the first argument.
In other words, string above is evaluated to the exact same address value as the expression &string[0].
The fact that your string is embedded inside a struct has nothing to do with this.
No it's not the "dot operator" . that creates a pointer, it's because e.g. the orbits member is an array. All arrays decays to pointers when passed as arguments.
Related
I want to understand where exactly in code an array gets converted to a pointer. For example:
void foo( int* pData, int len){}
int main(void){
char data[] = "Hello world";
foo( (int*)data, sizeof(data));
return 0;
}
I know that an array decays to a pointer to the first element if it is assigned to a pointer. However in the example above, I typecast the array data to int* first before passing it in function and assigning it to a pointer. Does the conversion/decay to pointer occurs at the typecasting point ? If so, isn't it true to say that the typecasting operation has the same effect as using the assignment operator with respect to array conversion/decay? Also would sizeof(data) be equal to the address length or array length?
Thank you for help!
The conversion of arrays to pointers in C is spelled out 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.
This means that the array is immediately converted to a pointer anywhere it is used except for the three cases listed above.
So applying the above to (int*)data, data is the operand of the typecast operator. Since this operator is not one of the ones listed above, data in this expression is converted from char [12] to char *, then the cast converts the char * to an int *.
Also, as mentioned above, the array is not converted when passed to sizeof. This means sizeof(data) evaluates to the size of char [12] which is 12.
Outwith the declaration, you can consider data to be equivalent to a pointer to the start of the array, but with the following exceptions:
sizeof(data) will give you the size of the array in bytes.
_Alignof(data) will be the same as _Alignof(*data) (and both give you the alignment of the type of the array elements)
&data has the same value as just data, but have a type of char (*)[sizeof(data] so arithmetic will use the full size of the array. Eg &data+1 will give you the address after the whole array rather than the address of the second element. See How come an array's address is equal to its value in C?
you can't change it's value (ie in this sense it is equivalent to a char *const).
When you call your function, you are taking the value of data (ie the address of the start of the array) and typecasting to an int *. The resulting int * behaves like any other int * and the exceptions don't apply, this is the 'decay'.
This question already has answers here:
problems with char array = char array
(2 answers)
Closed 7 years ago.
Well here is my first post. I've been trying to do this choice choosing thing and I want the user to choose only numbers instead of typing them down (easier) but when I want the numbers to equal a string, it says "array type char[30] is not assignable". Even if at the back I put semi-colon or not.
#include <stdio.h>
int main() {
int choice1;
char word[30];
printf("You have three choice.\n");
printf("[1] Jump [2] Run [3] Dance\n");
scanf("%d",&choice1);
if (choice1 == 1)
{
word = "Jump" //Error #1
}
else if (choice1 == 2)
{
word = "Eat" //Error #2
}
else if (choice1 == 3)
{
word = "Sleep"; //Error #3
}
printf("You will now be %sing",word);
}
You can't assign to an array, only copy to it.
Use strcpy instead, like
strcpy(word, "Jump");
TL;DR answer : An array name is not a modifiable lvalue. So, you cannot use the assignment operator (=) on that.
To copy the content into the array, you need to use strcpy() from string.h (char array) or memcpy() in general.
Now, to elaborate the actual reason behind the error message, quoting C11, chapter §6.5.16, Assignment operators
assignment operator shall have a modifiable lvalue as its left operand.
and then, quoting chapter §6.3.2.1 from the same standard,
A modifiable lvalue is an lvalue that does not have array type, [....]
So, an array name is not a modifiable lvalue hence, you cannot assign anything to it. This is the reason behind the error message.
The = operator cannot be used to copy the contents of one array to the other; you must use a library function like strcpy or strcat for strings, memcpy for non-strings (or assign array elements individually).
This is a consequence of how C treats array expressions. An array expression is defined by the language standard to be a non-modifiable lvalue; it's an lvalue because it refers to an object in memory, but it may not be the target of an assignment.
The array subscript operation a[i] is defined as *(a + i); that is, given the array address a, offset i elements from that address and dereference the result. Since the array expression a is treated as a pointer, most people think a variable stores a pointer to the first element of the array, but it doesn't. All that gets stored are the array elements themselves.
Instead, whenever the compiler sees an array expression in a statement, it converts that expression from type "N-element array of T" to "pointer to T", and the value of the expression becomes the address of the first element of the array (unless the expression is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration).
And this is why an array expression like word cannot be the target of an assignment; there's nothing to assign to. There's no object word that exists independently of word[0], word[1], etc.
When you write
word = "Jump";
the type of the expression "Jump" is converted from "5-element array of char" to "pointer to char", and the value of the expression is the address of the first element of the array. And you're trying to assign that pointer value to an array object, which a) isn't a pointer, and b) cannot be assigned to anyway.
Use strcpy from <string.h>-
strcpy(word,"Jump");
And similar for rest of them.
You just can't do word ="Jump". As the contents are modifiable, the arrays themselves are not.
This question already has answers here:
problems with char array = char array
(2 answers)
Closed 7 years ago.
Well here is my first post. I've been trying to do this choice choosing thing and I want the user to choose only numbers instead of typing them down (easier) but when I want the numbers to equal a string, it says "array type char[30] is not assignable". Even if at the back I put semi-colon or not.
#include <stdio.h>
int main() {
int choice1;
char word[30];
printf("You have three choice.\n");
printf("[1] Jump [2] Run [3] Dance\n");
scanf("%d",&choice1);
if (choice1 == 1)
{
word = "Jump" //Error #1
}
else if (choice1 == 2)
{
word = "Eat" //Error #2
}
else if (choice1 == 3)
{
word = "Sleep"; //Error #3
}
printf("You will now be %sing",word);
}
You can't assign to an array, only copy to it.
Use strcpy instead, like
strcpy(word, "Jump");
TL;DR answer : An array name is not a modifiable lvalue. So, you cannot use the assignment operator (=) on that.
To copy the content into the array, you need to use strcpy() from string.h (char array) or memcpy() in general.
Now, to elaborate the actual reason behind the error message, quoting C11, chapter §6.5.16, Assignment operators
assignment operator shall have a modifiable lvalue as its left operand.
and then, quoting chapter §6.3.2.1 from the same standard,
A modifiable lvalue is an lvalue that does not have array type, [....]
So, an array name is not a modifiable lvalue hence, you cannot assign anything to it. This is the reason behind the error message.
The = operator cannot be used to copy the contents of one array to the other; you must use a library function like strcpy or strcat for strings, memcpy for non-strings (or assign array elements individually).
This is a consequence of how C treats array expressions. An array expression is defined by the language standard to be a non-modifiable lvalue; it's an lvalue because it refers to an object in memory, but it may not be the target of an assignment.
The array subscript operation a[i] is defined as *(a + i); that is, given the array address a, offset i elements from that address and dereference the result. Since the array expression a is treated as a pointer, most people think a variable stores a pointer to the first element of the array, but it doesn't. All that gets stored are the array elements themselves.
Instead, whenever the compiler sees an array expression in a statement, it converts that expression from type "N-element array of T" to "pointer to T", and the value of the expression becomes the address of the first element of the array (unless the expression is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration).
And this is why an array expression like word cannot be the target of an assignment; there's nothing to assign to. There's no object word that exists independently of word[0], word[1], etc.
When you write
word = "Jump";
the type of the expression "Jump" is converted from "5-element array of char" to "pointer to char", and the value of the expression is the address of the first element of the array. And you're trying to assign that pointer value to an array object, which a) isn't a pointer, and b) cannot be assigned to anyway.
Use strcpy from <string.h>-
strcpy(word,"Jump");
And similar for rest of them.
You just can't do word ="Jump". As the contents are modifiable, the arrays themselves are not.
I thought when you try to get the address of an array, it returns the address of the first element it holds.
int *j;
int a[5]={1,5,4,7,8};
Now j=&a[0]; works perfectly fine.
Even j=a also does the same function.
But when I do j=&a it throws an error saying cannot convertint (*)[5]' to int*' in assignment
Why does it happen? &a should be the first element of the array a, so it should give &a[0].
But instead it throws an error. Can somebody explain why?
The C standard says the following regarding how arrays are used in expressions (taken from C99 6.3.2.1/3 "Lvalues, array, and function designators):
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
This is commonly known as "arrays decay to pointers".
So the sub-expression a in the following larger expressions evaluates to a pointer to int:
j=&a[0]
j=a
In the simpler expression, j=a, that pointer is simply assigned to j.
In the more complex expression, j=&a[0], the 'index' operator [] is applied to the pointer (which is an operation equivalent to *(a + 0)) and the 'address-of' operator is applied to that, resulting in another pointer to int that gets assigned to j.
In the expression j=&a, the address-of operator is applied directly to the array name, and we hit one of the exceptions in the above quoted clause: "Except when it is the operand of ... the unary & operator".
Now when we look at what the standard says about the unary & (address-of) operator (C99 6.5.3.2/3 "Address and indirection operators"):
The unary & operator returns the address of its operand. If the
operand has type "type", the result has type "pointer to type".
Since a has type "array of 5 int" (int [5]), the result of applying & to it directly has type "pointer to array of 5 int" (int (*)[5]), which is not assignable to int*.
The type of a and &a is not the same even though they contain the same value, i.e., base address of the array a.
j = a;
The array name a here gets converted to a pointer to its first element.
Try to see what values you get via these statements to understand where the difference lies:
printf("%p", a+1);
printf("%p", &a+1);
c is a strongly typed language. Assignment such as j=a; is allowed only if j and a are of the same type or the compiler can safely convert a to j. In your case, type of j is int * while the type of &a is int (*)[5]. The compiler does not know how to automatically convert an object of type int (*)[5] to an object of type int *. The compiler is telling you exactly that.
a is an array of 5 ints. The pointer to a is a pointer to an array of five integers, or int (*)[5]. This is not compatible with an int * because of pointer arithmetic: If you increment a variable of type int *, the address in the variable increases by 4 (assuming 4 byte integers), so that it points to the next integer. If you increment a variable that points to an array of 5 integers, the address in the variable increases by 20 (again assuming 4 byte integers), so that it points to the next array of five integers.
Perhaps what's confusing is that the value give by a and &a is the same, as you said. The value is the same but the type is different, and the difference is most obvious when you do arithmetic on the pointers.
I hope that helps.
For eg. I have an array of structs 'a' as below:
struct mystruct{
int b
int num;
};
struct bigger_struct {
struct my_struct a[10];
}
struct bigger_struct *some_var;
i know that the name of an array when used as a value implicitly refers to the address of the first element of the array.(Which is how the array subscript operator works at-least)
Can i know do the other way around i.e
if i do:
some_var->a->b, it should be equivalent to some_var->a[0]->b, am i right? I have tested this and it seems to work , but is this semantically 100% correct?
Is some_var->a->b equivalent to some_var->a[0]->b?
No, it is equivalent to some_var->a[0].b.
The exact specification of the array-to-pointer conversion is actually quite straightforward:
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 (C99 6.3.2.1).
some_var->a has the type my_struct[10], which is an array type, and since it is not the operand of the sizeof or unary & operator and is not a string literal, it is converted to a pointer to the initial element of the array.
Assuming that you have allocated memory for some_var, its safe to do some_var->a->b (as arrays decay into pointer).
Yes, _var->a[0]->b and _var->a->b are equivalent
Because a[0] and a is representing the base address of the structure.