Are arrays variables or constants? - c

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'}

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.

Struct vs string literals? Read only vs read-write? [duplicate]

This question already has answers here:
Why are compound literals in C modifiable
(2 answers)
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 4 years ago.
Does the C99 standard permit writing to compound literals (structs)? It seems it doesn't provide writing to literal strings. I ask about this because it says in C Programming: A Modern Approach, 2nd Edition on Page 406.
Q. Allowing a pointer to a compound literal would seem to make it possible to modify the literal. Is that the case?
A. Yes. Compound literals are lvalues that can be modified.
But, I don't quite get how that works, and how that works with string literals which you certainly can't modify.
char *foo = "foo bar";
struct bar { char *a; int g; };
struct bar *baz = &(struct bar){.a = "foo bar", .g = 5};
int main () {
// Segfaults
// (baz->a)[0] = 'X';
// printf( "%s", baz->a );
// Segfaults
// foo[0] = 'a';
// printf("%s", foo);
baz->g = 9;
printf("%d", baz->g);
return 0;
}
You can see on my list of things that segfault, writing to baz->a causes a segfault. But, writing to baz->g does not. Why is that one of them would cause a segfault and not the other one? How are struct-literals different from string-literals? Why would struct-literals not also be put into read-only section of memory and is the behavior defined or undefined for both of these (standards question)?
First thing first: your struct literal has a pointer member initialized to a string literal. The members of the struct itself are writeable, including the pointer member. It is only the content of the string literal that is not writeable.
String literals were part of the language since the beginning, while struct literals (officially known as compound literals) are a relatively recent addition, as of C99. By that time many implementations existed that placed string literals in read-only memory, especially on embedded systems with tiny amounts of RAM. By then designers of the standard had a choice of requiring string literals to be moved to a writeable location, allowing struct literals to be read-only, or leaving things as-is. None of the three solutions was ideal, so it looks like they went on the path of least resistance, and left everything the way it is.
Does the C99 standard permit writing to compound literals (structs)?
C99 standard does not explicitly prohibit writing to data objects initialized with compound literals. This is different from string literals, whose modification is considered undefined behavior by the standard.
The standard essentially defines the same characteristics to string literals and to compound literals with a const-qualified type used outside the body of a function.
Lifetime
String literals: Always static.
§6.4.5p6 In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals. The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence.
Compound literals: Automatic if used inside a function body, otherwise static.
§6.5.2.5p5 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.
Possibly shared
Both string literals and const-qualified compound literals might be shared. You should be prepared for the possibility but cannot rely on it happening.
§6.4.5p7 It is unspecified whether [the arrays created for the string literals] are distinct provided their elements have the appropriate values.
§6.5.2.5p7 String literals, and compound literals with const-qualified types, need not designate distinct objects.
Mutability
Modifying either a string literal or a const-qualified compound literal is undefined behaviour. Indeed attempting to modify any const-qualified object is undefined behaviour, although the wording of the standard is probably subject to hair-splitting.
§6.4.5p7 If the program attempts to modify [the array containing a string literal], the behavior is undefined.
§6.7.3p6 If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.
A non-const-qualified compound literal can be freely modified. I don't have a quote for this, but the fact that modification is not explicitly prohibited seems to me to be definitive. It's not necessary to explicitly say that mutable objects may be mutated.
The fact that the lifetime of compound literals inside function bodies is automatic can lead to subtle bugs:
/* This is fine */
const char* foo(void) {
return "abcde";
}
/* This is not OK */
const int* oops(void) {
return (const int[]){1, 2, 3, 4, 5};
;
Does the C99 standard permit writing to compound literals (structs)?
By writing to compound literal if you mean modifying elements of a compound literal, then yes, it does if it is not a read only compound literal.
C99-6.5.2.5:
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.
It means, compound literals are lvalues like arrays, and elements of a compound literal can be modified, just like you can modify an aggregate type. For example
// 1
((int []) {1,2,3})[0] = 100; // OK
// 2
(char[]){"Hello World"}[0] = 'Y'; // OK. This is not a string literal!
// 3
char* str = (char[]){"Hello World"};
*str = 'Y'; // OK. Writing to a compound literal via pointer.
// 4
(const float []){1e0, 1e1, 1e2}[0] = 1e7 // ERROR. Read only compound literal
In your code what you are trying to do is modifying a compound literal element which is pointing to a string literal which is non-modifiable. If that element is initialized with a compound literal then it can be modified.
struct bar *baz = &(struct bar){.a = (char[]){"foo bar"}, .g = 5};
This snippet will work now
Segfaults
(baz->a)[0] = 'X';
printf( "%s", baz->a );
Further standard also gives an example, in the same section mentioned above, and differentiate between a string literal, compound literal and read only compound literal:
13 EXAMPLE 5 The following three expressions have different meanings:
"/tmp/fileXXXXXX"
(char []){"/tmp/fileXXXXXX"}
(const char []){"/tmp/fileXXXXXX"}
The first always has static storage duration and has type array of char, but need not be modifiable; the last two have automatic storage duration when they occur within the body of a function, and the first of these two is modifiable.

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

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);

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.

Why can´t we assign a new string to an char array, but to a pointer?

i was trying to reassign a string to a pre-initialized array a[], and all i could get was an error
main()
{
char a[] = "Sunstroke";
char *b = "Coldwave";
a = "Coldwave";
b = "Sunstroke";
printf("\n %s %s",a,b);
}
[Error]: incompatible types when assigning to type 'char[10]' from type 'char *'.. i searched for this but was unable to find any reason.. i also tried to re-assign it by redeclaration like
char a[] = "Sunstroke";
but it didnt worked...
but in case of a pointer it was possible as in above program..
To understand what's going on here, two language rules are important:
Arrays are not assignable.
An array can be converted to a pointer to its first element.
It's also important to understand what a string literal like "Sunstroke" is. It's a static array of constant characters, large enough to hold all the characters of a string with a terminator at the end. So in this case, it's a const char[10] array, containing the nine characters followed by the zero-valued terminator. Being static, the array is stored somewhere in memory for the lifetime of the program.
char a[] = "Sunstroke";
This creates a local array, and initialises it by copying the characters from the string literal.
char *b = "Coldwave";
This creates a pointer, and initialises it to point to the literal itself. Note that this is dangerous: the literal is const, but the pointer isn't, so you can write code that attempts to modify the literal, giving undefined behaviour. This conversion is deprecated (certainly in C++, I'm not sure about C), so the compiler should give you a warning. You have enabled all the compiler warnings you can, haven't you?
a = "Coldwave";
This attempts to reassign the array, but fails because arrays aren't assignable. There's no particularly good reason why they aren't; that's just the way the languages evolved.
b = "Sunstroke";
This reassigns the pointer to point to a different literal. That's fine (apart from the lack of const noted above).
If you need to manipulate strings, then:
in C you'll need to carefully create arrays large enough for your needs, and use the library functions in <string.h> (or your own handcrafted code) to manipulate the characters in those arrays;
in C++, use the std::string class to handle memory management, assignment, etc. for you.
Hard-coded string literals such as "Coldwave" are actually char[] (char array) types -- but it is undefined behavior to modify them (C99:6.4.5.6). Note that below, however, b is still a char* (char pointer):
char *b = "Coldwave";
To which a char[] has been assigned. That's okay. It is different than this though:
char a[] = "Coldwave";
Which is an initialization of a char[]. You can only initialize a variable once, when it is declared, and initialization is the only circumstance in which you can populate an array or other compound type (such as a struct) via assignment like this. You could not do this, however:
char c[] = a;
Because when used on the right hand side of an assignment, array variables function as pointers to the array they represent, which is why char *b = a works.
So the reason you can't do this with the variables from above:
a = b;
// or
a = "Sunstroke";
Is because that would be assigning a char* to a char[] -- no good; you can only do it the other way around.
In the case of C if we look at c99 draft standard section 6.5.16 Assignment operators paragraph 2 says:
An assignment operator shall have a modifiable lvalue as its left operand.
and section 6.3.2.1 Lvalues, arrays, and function designators paragraph 1 says:
[...]A modifiable lvalue is an lvalue that does not have array type[...]
So since arrays are not modifiable lvalues you can not assign to them. As for initialization section 6.7.8 Initialization paragraph 14 says:
An array of character type may be initialized by a character string literal[...]
In the C++ draft standard the relevant sections are 4.2 Array-to-pointer conversion paragraph 1 which says:
An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array.
a prvalue is a pure rvalue and section 5.17 Assignment and compound assignment operators paragraph 1 which says:
[...]All require a modifiable lvalue as their left operand[...]
Let me simplify the program to:
char a[] = "Sunstroke";
char *b = a;
Assume that the address of a is 100, then in memory, it looks like this (illustrating only the size of pointer and endian-ness etc. may vary):
[S] [u] [n] [s] [t] [r] [o] [k] [e] [\0] ... [0] [0] [0] [100]
100 101 102 103 104 105 106 107 108 109 200
^ ^
| |
a b
As long as the life cycle of the array, a will always be the same place, you can't modify it.
b, on the other hand, is a pointer that contains the address of the array, you can modify the value of b to point to other places.

Resources