Why is not possible to assign a pointer to an array? [duplicate] - c

This question already has answers here:
Why can´t we assign a new string to an char array, but to a pointer?
(4 answers)
Closed 6 years ago.
In C, I'm coding this
char * real = strdup("GEORGE");
char one[1024];
one = real;
and it gives error:
invalid initializer
any suggestions?
is there any chance I can make array of chars equal to char pointer?

In your code, one is a variable of type array. Thus,
one = real;
is attempt to assign to an array type, which is not allowed.
To elaborate, array names are no modifiable lvalues and assignment operator only works on modifiable lvalues as the LHS operand.
Quoting C11, chapter §6.5.16
An assignment operator shall have a modifiable lvalue as its left operand.
and then, chapter §6.3.2.1, (emphais mine)
A modifiable lvalue is an lvalue that
does not have array type, does not have an incomplete type, does not have a const qualified
type, and if it is a structure or union, does not have any member (including,
recursively, any member or element of all contained aggregates or unions) with a const qualified
type.
You need to use strcpy() to copy the content to the array.

C requires constants in array initializers. You are allowed to do this:
char one[1024] = "GEORGE";
or this
char one[1024] = {'G','E','O','R','G','E'};
but assigning a pointer to an array is not allowed under any circumstances, initializer or not.
On the other hand, you can copy a content of a char pointer into an array. Depending on whether your source array is null-terminated or not, you can use strcpy or memcpy, like this:
strcpy(one, real);
or
memcpy(one, real, 7);

Related

Why I need different declarations for **ptr and *ptr[]? [duplicate]

This question already has answers here:
C difference between *[] and **
(8 answers)
Closed 2 years ago.
I thought that char *ptrs[]; and char **strs; should be the same thing.
At least I can use both as string arrays.
When I try to compile char **strs, it's fine, but *ptrs[] want to be initialized or at least it want a fixed size for some reason.
char ptrs[];
char **strs;
I get the error:
gcc: "error: array size missing in ‘ptrs’"
I thought that char *ptrs[]; and char **strs; should be he same thing.
You thought wrong. First is an array of unspecified size of pointers. The second is a pointer to a pointer. An array is not a pointer and a pointer is not an array.
You may have been confused by function parameters. Function parameters cannot be arrays and if you write an array parameter, it is adjusted to be a pointer to an element of such array. As such, in a parameter declaration the first is adjusted to be the same as the second. This adjustment only occurs in parameter declarations and nowhere else.
Arrays and pointers are two different derived types.
If you declare an object with automatic storage duration then it shall have a complete type. For arrays it means that the number of elements in the array shall be known (either explicitly specified or calculated according to provided initializes).
So the compiler issue the error
gcc: "error: array size missing in ‘ptrs’"
for this declaration of an array with the automatic storage duration
char *ptrs[];
(I think you mean the type specifier char * instead of char when you are comparing these two declarations char *ptrs[]; and char **strs;) because it is unable to determine how much memory to allocate for the array.
On the other hand, pointers are always complete object types. From the C Standard (6.2.5 Types, p.#20)
A pointer type is a complete object type.
As a result the compiler always knows the size of a pointer.
If this declaration
char *ptrs[];
has file scope then such an incomplete declaration is allowed and is named as a tentative definition. the compiler will interpret it like this declaration
char *ptrs[1];
is present at the end of a translation unit.
Arrays used in expressions are implicitly (with rare exceptions) are converted to pointers to their first elements. So this array designator ptrs used in expressions as for example a function argument is converted to rvalue of the type char **.
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.
I thought that char *ptrs[]; and char **strs; should be the same thing. At least I can use both as string arrays.
Your assumption is not true and neither of those two can be used as "arrays of strings". An array of strings (if this term is anyhow in any manner appropriate) is after my opinion, an array of array of chars, where a string can be stored in each array of chars which is therefore again an element of the array of arrays. A pointer cannot store a string. It can only point to one.
char **strs; - strs is a pointer to pointer to char.
char *ptrs[]; - ptrs is an array of pointer to char with unspecified amount of elements. That is not permissible anywhere else than as function parameter.
As function parameter char *ptrs[] is equal to char **ptrs and denotes a pointer to pointer to char, but again it stores no strings itself.
If you use char *ptrs[] as usual declaration, the compiler needs to know the amounts of pointer elements in the array.
This is why you get the error message
"error: array size missing in ‘ptrs’"
with GCC.
The two declarations are equivalent only as function parameter declarations:
void foo( char *ptrs[], char **strs ) { ... }
because any parameter of type T a[N] or T a[] is "adjusted" to T *a. This is due to the fact that array expressions "decay" to pointer expressions under most circumstances - when you pass an array expression as a function argument, what the function actually receives is a pointer expression.
As regular variable declarations, however, the two are not equivalent. An array definition must either specify a size or have an initializer:
char *ptrs[] = {"foo", "bar", "bletch", "blurga", ... };
In this case, the array size will be taken from the number of elements in the initializer.

Are arrays variables or constants?

I just want to know: Are arrays in C variables or constants?
I am specially confused about char arrays.
According to the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
1 An lvalue is an expression (with an object type other than void)
that potentially designates an object;64) if an lvalue does not
designate an object when it is evaluated, the behavior is undefined.
When an object is said to have a particular type, the type is
specified by the lvalue used to designate the object. A modifiable
lvalue is an lvalue that does not have array type, does not have an
incomplete type, does not have a constqualified type, and if it is a
structure or union, does not have any member (including, recursively,
any member or element of all contained aggregates or unions) with a
constqualified type.
So arrays are non-modifiable lvalues. that is you may not write for example
char s1[] = "hello";
char s2[] = "hello";
s1 = s2;
The compiler will issue a diagnostic message that the code is invalid.
As for string literals then they have static storage duration and any attempt to modify a string literal results in undefined behavior.
From the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
Compare these two code snippets.
char s[] = "hello";
s[0] = 'H';
and
char *s = "hello";
s[0] = 'H';
In the first code snippet there is declared a character array that is initialized by a string literal. That is the characters of the string literal are used to initialize the elements of the array. And you may to change the created array.
In the second code snippet there is declared a pointer to a strig literal. And in the second statement there is an attempt to change the string literal using the pointer that results in undefined behavior.
As for qualifiers like the const qualifier then (6.7.3 Type qualifiers)
9 If the specification of an array type includes any type
qualifiers, the element type is so qualified, not the array type. If
the specification of a function type includes any type qualifiers, the
behavior is undefined
So this declaration
const char s[] = "hello";
means that each element of the array has the qualifier const in its type specification that is each element has the type const char.
Array Definition:
Like any other variables, uninitialized array elements contain garbage values.
An array is a group of contiguous memory locations that all have the same type.To refer to a particular location or element in the array, we specify the array’s name and the position number of the particular element in the array.
"C How To Program _ Deitel" book.
So as you can see arrays are memory location, thus you can initialize them and make them constants or you can use them as variables.
Array Specifying:
Are like variables definition. You should specify their type and their name and their length(in this case they are different from variables) e.g. int average[10] are sequence of memory that store 10 variable in it.
Character arrays:
In C are null_terminated and always end with '/0' or simply 0. For instance if you want to enter a name with 5 character you must define an array with length 5 + 1('\0'). If you don't you'll encounter an undefined behavior(UB).
You can initialize array in these ways:
char string[] ="computer"
char string[12]="algorthm"
char string[]={'s','t','a','c','k','/0'}

Why am I unable to store the return value of the function? [duplicate]

This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed 5 years ago.
I am trying to return the value of a string from another function and store it as a variable. This is what I have written but I am having trouble resolving the issue.
#include "stdio.h"
void main()
{
printf("Hello World\n");
char result[60];
result = menuFunction();
}
const char* menuFunction()
{
return "Hello Again";
}
In your code, result is array type, which is not a modifiable lvalue, hence cannot be used as LHS of assignment operator.
Quoting C11, chapter §6.5.16
An assignment operator shall have a modifiable lvalue as its left operand.
and chapter §6.3.2.1, (emphasis mine)
An lvalue is an expression (with an object type other than void) that potentially
designates an object; 64) if an lvalue does not designate an object when it is evaluated, the
behavior is undefined. When an object is said to have a particular type, the type is
specified by the lvalue used to designate the object. A modifiable lvalue is an lvalue that
does not have array type, does not have an incomplete type, does not have a const-qualified
type, and if it is a structure or union, does not have any member (including,
recursively, any member or element of all contained aggregates or unions) with a const-qualified
type.
Solution: Define result as a pointer instead.
That said,
for a hosted environment, void main() is pretty much disallowed. You should be using int main(void) to conform to the standard.
using a function (call) before the function definition or a forward declaration in place, is also disallowed. You need to define the function beforehand or have a forward declaration of the same before you use it.

Is there a reason why an array name is not an lvalue?

For example,
int x[10];
int i = 0;
x = &i; //error occurs!
According to C - A Reference Manual, an array name cannot be an lvalue. Thus, x cannot be an lvalue. But, what is the reason the array name cannot be an lvalue? For example, why does an error occur in the third line?
Your reference is incorrect. An array can be an lvalue (but not a modifiable lvalue), and an "array name" (identifier) is always an lvalue.
Take your example:
int x[10];
int i = 0;
x = &i; //error occurs!
Apply C11 6.5.1, paragraph 2:
An identifier is a primary expression, provided it has been declared
as designating an object (in which case it is an lvalue) ...
We see that x is a primary expression and is an lvalue, because it has previously been declared as designating an array object.
However, the C language rules state that an array expression in various contexts, including the left-hand-side of an assignment expression, are converted to a pointer which points at the first element of the array and is not an lvalue, even if the array was. Specifically:
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.
(C11 6.3.2.1 paragraph 3).
The pointer which is the result of the conversion specified above is not an lvalue because an lvalue designates an object, and there is no suitable object holding the pointer value; the array object holds the elements of the array, not a pointer to those elements.
The example you use in your question implies that you understand that an array expression decays (is converted to) a pointer value, but I think you are failing to recognize that after the conversion, the pointer value and the array are two different things. The pointer is not an lvalue; the array might be (and in your example, it is). Whether or not arrays are lvalues in fact has no bearing on your example; it is the pointer value that you are trying to assign to.
If you were to ask instead: Why do arrays decay to pointers when they are on the left-hand-side of an assignment operator? - then I suspect that there is no particularly good answer. C just doesn't allow assignment to arrays, historically.
Array names are non-modifiable lvalues in C.:)
Arrays are named extents of memory where their elements are placed. So you may not substitute one extent of memory for another extent of memory. Each extent of memory initially allocated for an array declaration has its own unique name. Each array name is bounded with its own extent of memory.
An array is an lvalue, however it is a non-modifiable lvalue.
It most likely has to do with compatibility of types. For example, you can do this:
struct ss {
char c[10];
};
...
struct ss s1 = { { "hello" } };
struct ss s2 = s1;
But not this:
char s1[10] = "hello";
char s2[10] = s1;
It's true that array names yield pointer values in many contexts. But so does the & operator, and you don't expect that to be assignable.
int i = 42;
int *j = malloc(sizeof *j);
&i = j; /* obviously wrong */
int a[] = {1,2,3};
&a[0] = j; /* also obviously wrong */
a = j; /* same as the previous line! */
So when learning the relationship between arrays and pointers, remember that a is usually the same as &a[0] and then you won't think lvalue-ness is an exception to the rule - it follows the rule perfectly.

Array as compound literal [duplicate]

This question already has answers here:
Why are compound literals in C modifiable
(2 answers)
Closed 4 years ago.
In C99 we can use compound literals as unnamed array.
But are this literals constants like for example 100, 'c', 123.4f, etc.
I noticed that I can do:
((int []) {1,2,3})[0] = 100;
and, I have no compilation error and is guessable that the first element of that unnamed array is modified with 100.
So it seems as array as compound literal are lvalue and not constant value.
It is an lvalue, we can see this if we look at the draft C99 standard section 6.5.2.5 Compound literals it says (emphasis mine):
If the type name specifies an array of unknown size, the size is
determined by the initializer list as specified in 6.7.8, and the type
of the compound literal is that of the completed array type. Otherwise
(when the type name specifies an object type), the type of the
compound literal is that specified by the type name. In either case,
the result is an lvalue.
If you want a const version, later on in the same section it gives the following example:
EXAMPLE 4 A read-only compound literal can be specified through
constructions like:
(const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}
We can find an explanation of the terminology in this Dr Dobb's article The New C: Compound Literals and says:
Compound literals are not true constants in that the value of the
literal might change, as is shown later. This brings us to a bit of
terminology. The C99 and C90 Standards [2, 3] use the word “constant”
for tokens that represent truly unchangeable values that are
impossible to modify in the language. Thus, 10 and 3.14 are an integer
decimal constant and a floating constant of type double, respectively.
The word “literal” is used for the representation of a value that
might not be so constant. For example, early C implementations
permitted the values of quoted strings to be modified. C90 and C99
banned the practice by saying that any program than modified a string
literal had undefined behavior, which is the Standard’s way of saying
it might work, or the program might fail in a mysterious way. [...]
As far I remeber you are right, compound literals are lvalues*, you can also take pointer of such literal (which points to its first element):
int *p = (int []){1, 2, 3};
*p = 5; /* modified first element */
It is also possible to apply const qualifier on such compound literal, so elements are read-only:
const int *p = (const int []){1, 2, 3};
*p = 5; /* wrong, violation of `const` qualifier */
*Note this not means it's automatically modifiable lvalue (so it can used as left operand for assignment operator) since it has array type and refering to C99 draft 6.3.2.1 Lvalues, arrays, and function designators:
A modifiable lvalue is an lvalue that does not have array type, [...]
Referring to the C11 standard draft N1570:
Section 6.5.2.5p4:
In either case, the result is an lvalue.
An "lvalue" is, roughly, an expression that designates an object -- but it's important to note that not all lvalues are modifiable. A simple example:
const int x = 42;
The name x is an lvalue, but it's not a modifiable lvalue. (Expressions of array type cannot be modifiable lvalues, because you can't assign to an array object, but the elements of an array may be modifiable.)
Paragraph 5 of the same section:
The value of the compound literal is that of an unnamed object
initialized by the initializer list. If the compound literal occurs
outside the body of a function, the object has static storage
duration; otherwise, it has automatic storage duration associated with
the enclosing block.
The section describing compound literals doesn't specifically say that whether the unnamed object is modifiable or not. In the absence of such a statement, the object is taken to be modifiable unless the type is const-qualified.
The example in the question:
((int []) {1,2,3})[0] = 100;
is not particularly useful, since there's no way to refer to the unnamed object after the assignment. But a similar construct can be quite useful. A contrived example:
#include <stdio.h>
int main(void) {
int *ptr = (int[]){1, 2, 3};
ptr[0] = 100;
printf("%d %d %d\n", ptr[0], ptr[1], ptr[2]);
}
As mentioned above, the array has automatic storage duration, which means that if it's created inside a function, it will cease to exist when the function returns. Compound literals are not a replacement for malloc.
Compound literals are lvalues and it's elements can be modifiable. You can assign value to it. Even pointer to compound literals are allowed.

Resources