lvalue : array and structure [duplicate] - c

This question already has answers here:
Why do C and C++ support memberwise assignment of arrays within structs, but not generally?
(5 answers)
Closed 6 years ago.
An lvalue is defined as an expression to which a value can be assigned.
And it is illegal to assign and array with a array value. E.g.:
int x[2],y[2];
x = y;
Whereas structures can be treated as lvalues. Below structure assignment is valid.
typedef struct car {
char color[20];
int price;
} CAR;
CAR audi, bmw;
audi = bmw;
What is the difference?

There are historic reasons why arrays are not assignable on themselves, but are assignable inside structs. There is really no technical reason for this discrepancy.
Anecdottal heresay is that when C was designed, it was based on a certain language (don't remember which one!) which didn't have array assingment, so this feature was exluded from C as well - to preserve compatibility. However, this language didn't have structs, so array assingment inside structs was OKayed.

Related

Determining offset of a struct member via casting NULL to a struct pointer [duplicate]

This question already has answers here:
Does &((struct name *)NULL -> b) cause undefined behaviour in C11?
(6 answers)
Getting the offset of a variable inside a struct is based on the NULL pointer, but why?
(5 answers)
Closed 6 months ago.
Consider the following code:
#include <inttypes.h>
struct test {
int a;
long b;
};
int main(void){
intptr_t ptr = (intptr_t) &(((struct test *)NULL)->b);
printf("%"PRIiPTR"\n", ptr); //prints 8
//...
}
I've been using this sort of construction for pretty long time to determine offset of struct member, but now questioned if this construction a well defined in terms of the Standard standpoint.
The thing that's not clear to me is why is it legitimate to perform indirection on a NULL pointer with later taking address?
This is not valid code, as it dereferences a NULL pointer and attempts to obtain an lvalue for a non-existent object.
There is a language construct that gives the offset of a struct member, namely the offsetof macro.
Although it is possible that such a macro could expand to an expression similar to what you have, that macro is considered part of the implementation, and such code can do things that "user" code is not allowed to do

Does this code have a valid declaration for the size of the array? [duplicate]

This question already has an answer here:
Declaring an array with a non-constant size variable [duplicate]
(1 answer)
Closed 5 years ago.
I am learning how to program arrays in C. I have a question about the following code regarding size of array. In the below code, is it a valid declaration of size of an array? Please explain me if it is either valid or invalid.
#include<stdio.h>
#define SIZE 10
int main(void) {
int size=12;
float salary[size];
salary[0]=890.54;
printf("%f",salary[0]);
return 0;
}
To support the other answer, if variable length arrays (VLA) are supported then yes — the declaration in the question is valid and defines a VLA. VLAs made their debut in C99 and then in C11 they are made optional. A conforming C11 compiler that does not support VLAs defines __STDC_NO_VLA__.
From §6.7.6.2¶4
If the size is not present, the array type is an incomplete type. If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations or type names with function prototype scope;143) such arrays are nonetheless complete types. If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type. (Variable length arrays are a conditional feature that implementations need not support; see 6.10.8.3.)
from §6.10.8.3¶1
__STDC_NO_VLA__
The integer constant 1, intended to indicate that the implementation does not support variable length arrays or variably modified types
It's valid size value (only with C99). You can refer from this URL for more detail:
https://www.cs.uic.edu/~jbell/CourseNotes/C_Programming/Arrays.html

"Arrays = Pointers" *mind blown*. Many years later: "Actually, they don't" *mind blown again* [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Context:
I programmed in C on and off for about 2 years before discovering that a[i] is just syntax sugar for *(a + i) and was therefore equivalent to *(i + a) and i[a]. My reality was turned upside down and many a "AHA!" revelationary moment followed in the following few days of study and reading up ("So THAT's why arrays are always passed by reference!" etc). Since then I've internalised the pointer/array equivalence and held it close to my heart, so imagine what a rude shock it was when I stumbled upon this thing called "Array decay". Here's the typical example:
Code:
#include <stdio.h>
int Length(int*);
int main () {
int arr[100];
printf("Length of array: %d\n",(int)(sizeof(arr)/sizeof(arr[0])));
printf("Length of array: %d\n",Length(arr));
return 0;
}
int Length(int arr[]) {
return sizeof(arr)/sizeof(arr[0]);
}
Result:
Length of array: 100
Length of array: 2
Question:
So it turns out that C has some recognition of arrays after all! In main where the array was declared, the program is able to correctly report on it's size. Now I'm wondering just how much of array syntax is only syntax sugar for pointer operations (previously I had assumed: All of it). C actually does have arrays, what are their limitations? The example shows that it is possible to get their length as long as you're in the same function, what other cool stuff can you do? How far can you go before this decay thing kicks in?
There are two operators in "old" C language that do not trigger array type decay: sizeof operator and unary & operator. sizeof evaluates to the size of the entire array (not to pointer size), while & returns a pointer of pointer-to-array type (not of pointer-to-pointer type). C99 added _Alignof, as Eric noted in the comments.
One more context is mentioned sometimes as well: initialization of char array with string literal (i.e. string literal does not decay to pointer).
One can also put it that way: in object contexts (AKA lvalue contexts) arrays retain their "arrayness", while in value contexts (AKA rvalue contexts) they immediately decay to pointers.
P.S. As a historical remark: one of the ancestors of C language - B language - did actually implement arrays as physical pointers, meaning that each array in B was actually a pointer pointing to an independently allocated memory block. Originally it was assumed that this implementation will carry over to C as well. However, C had to have struct types. And B-style arrays created unnecessary complications with having arrays as members of struct objects. They would've made initialization of struct objects non-trivial, struct object would become non-copyable by raw memcpy etc. This was deemed unacceptable in C. So, arrays were redesigned into their current form. C arrays are not pointers, but they still emulate the pointer-like behavior of their grandparents from B language, which often confuses people learning C.
(See here http://cm.bell-labs.com/cm/cs/who/dmr/chist.html for the full story.)
The size of an array is "lost" when it is passed to a function. As you point out, sizeof, being a compile-time thing, sees the "real" size. This can work because sizeof is not a function at all, as you can demonstrate by using it without parentheses (e.g. sizeof arr, though bizarrely sizeof some_type is not legal C).
Saying that arrays and pointers are "equivalent" means neither that they are identical nor even interchangeable. What it means is that it's pointer arithmetic and array indexing that are equivalent in C, pointers and arrays are different.
A reference to an object of type array-of-T which appears in an expression decays into a pointer to its first element; the type of the resultant pointer is pointer-to-T. That is, whenever an array appears in an expression, the compiler implicitly generates a pointer to the array's first element, just as if the programmer had written &a[0].
sizeof or & operator are the exceptions to this rule.
Also, I recommend the book Expert C Programming, which uses a whole chapter to explain the difference and confusions about pointers and arrays.
Declaring an array as a local or global variable is where it differs from pointers. int arr[100]; allocates 400 bytes of space, whereas int *p only allocates 4. You can use an int *p local variable similarly to an array if you malloc some space for it, like
int *p = (int *)malloc(100 * sizeof(int));
You also have to remember to free that memory later, of course. You can also feel free to pass a local variable that was declared as int arr[100] to a function whose formal parameter has type int *. When it comes to function arguments, arrays and pointers are a little more equivalent.
i[a]
No, that won't work, if i is an int. But the other three forms are equivalent.

C programming: arrays and pointers [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is array name a pointer in C?
If I define:
int tab[4];
tab is a pointer, because if I display tab:
printf("%d", tab);
the code above will display the address to the first element in memory.
That's why i was wondering why we don't define an array like the following:
int *tab[4];
as tab is a pointer.
Thank you for any help!
tab is a pointer
No, tab is an array. An int[4] to be specific. But when you pass it as an argument to a function (and in many other contexts) the array is converted to a pointer to its first element. You can see the difference between arrays and pointers for example when you call sizeof array vs. sizeof pointer, when you try to assign to an array (that won't compile), and more.
int *tab[4];
declares an array of four pointers to int. I don't see how that is related to the confusion between arrays and pointers.
tab is not a pointer it's an array of 4 integers when passed to a function it decays into a pointer to the first element:
int tab[4];
And this is another array but it holds 4 integer pointers:
int *tab[4];
Finally, for the sake of completeness, this is a pointer to an array of 4 integers, if you dereference this you get an array of 4 integers:
int (*tab)[4];
You are not completely wrong, meaning that your statement is wrong but you are not that far from the truth.
Arrays and pointers under C share the same arithmetic but the main difference is that arrays are containers and pointers are just like any other atomic variable and their purpose is to store a memory address and provide informations about the type of the pointed value.
I suggest to read something about pointer arithmetic
Pointer Arithmetic
http://www.learncpp.com/cpp-tutorial/68-pointers-arrays-and-pointer-arithmetic/
Considering the Steve Jessop comment I would like to add a snippet that can introduce you to the simple and effective world of the pointer arithmetic:
#include <stdio.h>
int main()
{
int arr[10] = {10,11,12,13,14,15,16,17,18,19};
int pos = 3;
printf("Arithmetic part 1 %d\n",arr[pos]);
printf("Arithmetic part 2 %d\n",pos[arr]);
return(0);
}
arrays can behave like pointers, even look like pointers in your case, you can apply the same exact kind of arithmetic by they are not pointers.
int *tab[4];
this deffinition means that the tab array contains pointers of int and not int
From C standard
Coding Guidelines
The implicit conversion of array objects to a
pointer to their first element is a great inconvenience in trying to
formulate stronger type checking for arrays in C. Inexperienced, in
the C language, developers sometimes equate arrays and a pointers much
more closely than permitted by this requirement (which applies to uses
in expressions, not declarations). For instance, in:
file_1.c
extern int *a;
file_2.c
extern int a[10];
the two declarations of a are sometimes incorrectly assumed by
developers to be compatible. It is difficult to see what guideline
recommendation would overcome incorrect developer assumptions (or poor
training). If the guideline recommendation specifying a single point
of declaration is followed, this problem will not 419.1 identifier
declared in one file occur. Unlike the function designator usage,
developers are familiar with the fact that objects having an array
function designator converted to typetype are implicitly converted to
a pointer to their first element. Whether applying a unary & operator
to an operand having an array type provides readers with a helpful
visual cue or causes them to wonder about the intent of the author
(“what is that redundant operator doing there?”) is not known.
Example
static double a[5];
void f(double b[5])
{
double (*p)[5] = &a;
double **q = &b; /* This looks suspicious, */
p = &b; /* and so does this. */
q = &a;
}
If the array object has register storage class, the behavior is undefined
Under most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type, and the value of the expression will be the address of the first element in the array. The exceptions to this rule are when the array expression is an operand of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration.
int tab[4];
defines tab as a 4-element array if int. In the statement
printf("%d", tab); // which *should* be printf("%p", (void*) tab);
the expression tab is converted from type "4-element array of int" to "pointer to int".

Why array assignment operation doesn't exist but structure assignment does in C language?

int a[10];
int b[10];
a = b; // illegal
typedef struct {
int real;
int imag;
} complex;
complex c,d;
c = d; //legal
[I realize that a and b are addresses in 1st case,but symbols in 2nd case]
For historical info, this may be interesting: http://cm.bell-labs.com/who/dmr/chist.html
In B, declaring an array would set aside memory for the array, just as C does, but the name supplied for the variable was used to define a pointer to the array. Ritchie changed this in C, so that the name "is" the array but can decay to a pointer when used:
The rule, which survives in today's C, is that values of array type
are converted, when they appear in expressions, into pointers to the
first of the objects making up the array.
This invention enabled most existing B code to continue to work,
despite the underlying shift in the language's semantics. The few
programs that assigned new values to an array name to adjust its
origin—possible in B and BCPL, meaningless in C—were easily repaired.
If at that very early stage, Ritchie had defined a = b to copy the array, then the code he was trying to port from B to C would not have been as easily repaired. As he defined it, that code would give an error, and he could fix it. If he'd made C copy the array, then he would have silently changed the meaning of the code to copy the array rather than reseating the name being used to access an array.
There's still the question, "why hasn't this feature been added in the 40 years since", but I think that's why it wasn't there to start with. It would have been effort to implement, and that effort would actually have made that early version of C worse, in the sense of being slightly harder to port B and BCPL code to C. So of course Ritchie didn't do it.
Because C says you can't, it says "A modifiable lvalue is an lvalue that does not have array type, does
not have an incomplete type", so an array can't be assigned to.
Moreover,
When you use the name of an array in a value context likea = b; , both the names a and b mean
&a[0] and &b[0]. Often referred to as an array "decaying" to a pointer.
However, arrays are not pointers, so trying to assign an array by using pointers wouldn't make sense.
The main reason is of course the Standard. On the assignment operator constraint it says:
(C99, 6.5.16p2) "An assignment operator shall have a modifiable lvalue as its left operand"
where it defines a modifiable lvalue as
(C99, 6.3.2.1p1) "A modifiable lvalue is an lvalue that does not have array type, [...]".
So assigning to arrays is not permitted.
But the main reasons are historical reasons at the times where array copy was considered not appropriate for the hardware (the old PDP systems). Not that also in the first versions of C, the assignment of structure types objects was also not allowed. It was later added to the language but for the array to many parts of the language would have been needed to be changed to allow to assign to arrays.
The first thing to understand is that arrays are not pointers. Read section 6 of the comp.lang.c FAQ. I'll wait.
...
Ok, done? No, go back and read the whole thing.
...
Great, thanks.
Generally speaking, arrays in C are second class citizens. There are array types, and array objects, and even array values, but arrays are almost always manipulated via pointers to their elements.
This requires a bit more work for the programmer (as you've seen, you can't just assign arrays), but it also gives you more flexibility. Programs that deal with arrays usually need to deal with arrays of different sizes, even sizes that can't be determined until execution time. Even if array assignment were permitted, an array of 10 ints and an array of 20 ints are of different and incompatible types. If you have a fixed-size array, as in the code in your question, it's common for only some of the elements to be currently relevant; you might have a 10-element array, but you're only currently using the first 5 elements. Processing such an array element-by-element makes it easier to process only the elements that are currently active (something you have to keep track of yourself).
For a struct, on the other hand, the number and types of the members are determined when you define the type. You can't traverse the members of a struct by advancing a pointer, as you would for an array, since the members are typically of different types. Arrays and structures are different things, and they have different sets of operations that make sense for them.
There are a couple of rules in the language that try to make it easier to do this, namely:
An array expression, in most but not all contexts, is implicitly converted to a pointer to the array's first element. The exceptions are:
When the array expression is the operand of the & (address) operator;
When it's the operand of sizeof; and
When it's a string literal in an initializer, used to initialize an array object.)
A declared array parameter, as in int func(char s[]); is adjusted to a pointer parameter: int func(char *s);.
(One could argue that these rules cause more confusion than they prevent, but that's the way the language is defined.)
Now I suppose the language could have been defined, or could be redefined, so that array assignment is permitted in cases where it makes sense:
int a[10];
int b[10];
/* ... */
a = b; /* Why not? */.
Perhaps such a change could even be made without breaking existing code. But that would require another special case for the array-to-pointer conversion rule. And it would only be useful in the case of fixed-size arrays like a and b, which though they're quite common in introductory programming exercises, are not as common in production code.
An array name is a const pointer so you can't change what it is pointing to.
Assuming that you meant c = d on the last line is legal, it's simply copying a non-const variable to another non-const variable, which is perfectly legal.
a is actually the "pointer" to the first element of array and it's a constant "pointer",
so you are trying to assign an l-"pointer".
you can achieve what are you trying to do by :
struct arraystruct
{
int t[10];
};
struct arraystruct a,b;
a=b;
EDIT:well i forgot to mention that there are a few exceptions where an array should not be considered as a pointer:
-you can use sizeof(array) but you cannot use sizeof(pointer)
-array of literal string
-a and &a are the same
That is because the kind of array you are using is a so-called static array, ie. the memory for it is on the stack.
If you would use dynamic arrays (with pointers) your assignment would be legal (but a memory leak would be possible). This would be a shallow copy.
See also Static array vs. dynamic array in C++

Resources