The code defines array like this-
#define N 100
long int mid[N+1]
Here whether mid[N+1]=mid[100+1] i.e mid[101]?
Also I want to know can we declare array of 2 elements as int n[1+1]?
starting from the second question , yes, you can declare something like mid[2+1] , because you are declaring an array of literal size (3 being the literal), and not a variable size.
that brings us to the first question. Yes, it's the same. at an early phase of the compilation, the compiler takes all the definitions in the code and "expands" them to the defined value or expression, so mid[N+1] turns literally into mid[100+1].
note that the N here, is a defined value and not a variable. you can't declare mid[N+1] if that N is a variable (not until C99 i think).
#define N 100
long int mid[N+1]
That's perfectly valid (apart from the missing semicolon), and equivalent to
long int mid[101];
The length of an array can be any integer constant expression with a positive value. It doesn't have to be an integer constant (literal).
Similarly,
int n[1+1];
is equivalent to
int n[2];
(At block scope, an array defined without the static keyword can have a variable length, which can be specified by any integer expression. (If the value of the expression is not positive, the behavior is undefined.) Variable length arrays are not permitted in C90; they were introduced in C99, and support for them was made optional by C11, so not all compilers support them.)
You can declare array like this,Array size should be positive.
#define N 100
long int mid[N+1]
if you want to use array of length N+1,
you can use malloc also
malloc();
eg,
#define N 100
long int* mid;
int main()
{
mid = malloc((N+1)*sizeof(long int));
return 0;
}
So you can access array mid of size 101.
Related
I am a bit confused about array declaration in C. I know that it's possible to do this:
int a[20]; // Reserved space for 20 int array
int b[] = {32, 431, 10, 42}; // Length in square brackets is auto-calculated
int *c = calloc(15, sizeof(int)); // Created a pointer to the dynamic int array
But is it possible to do this?:
int my_array[sizeof(int) * 5];
Is it a valid code, or an array length should be a constant expression (in ANSI C)?
This declaration
int my_array[sizeof(int) * 5];
does not declare a variable length array because the expression sizeof(int) * 5 is a constant integer expression. So even your compiler does not support variable length arrays you may use such a declaration.
From the C Standard (6.6 Constant expressions)
6 An integer constant expression117) shall have integer type and shall
only have operands that are integer constants, enumeration constants,
character constants, sizeof expressions whose results are integer
constants, and floating constants that are the immediate operands of
casts. Cast operators in an integer constant expression shall only
convert arithmetic types to integer types, except as part of an
operand to the sizeof operator.
and (6.7.6.2 Array declarators)
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; 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.)
A declaration of a variable length array can look like
const int n = 5;
int my_array[sizeof(int) * n];
The support of variable length arrays is optional in C11 and higher.
(This answer answers the question in the title, “Can array length in declaration be non-constant?” The example given in the body, int my_array[sizeof(int) * 5]; does not have a non-constant length.)
Variable length arrays are optional in the current C standard, 2018, meaning a C implementation may choose to support them or not. They were mandatory in the 1999 C standard and made optional in the 2011 standard.
Variable length arrays can be declared only inside functions or there parameters, not at file scope, and they cannot have static or thread storage duration.
sizeof(int) * 5 used in the example statement in your question: int my_array[sizeof(int) * 5];, is a constant expression, so although it does not serve as a good illustration of your primary question, it is legal syntax for C array declaration.
With the exception of C99, variable length arrays are optional in most recent C compiler implementations. (In C99 inclusion of VLA is mandated.)
So, if your compiler supports VLA, the following are an examples:
char string[100] = {0};
scanf("%99s", string);
int VLAarray1[strlen(string)+1];//per question in comments about functions to size array.
memset(VLA1array, 0, sizeof(VLAarray1));//see Note below for initialization
int arrayLen = 0;
scanf("%d", &arrayLen);
int VLAarray2[arrayLen];
memset(VLAarray2, 0, sizeof(VLAarray2));//see Note below for initialization
int nonVLAarray[100] = {0};//initialization during declaration of nonVLA
Note: that VLAs cannot be initialized in any form during its declaration. As with all variables though it is a good idea that it be initialized in subsequent statements by explicitly assigning values to its entire region of memory.
Passing VLAs as function arguments is not included within the scope of your question, but should it be of interest, there is a good discussion on that topic here.
#include <stdio.h>
int func()
{
int a = 3, b = 4;
int c = a * b;
return c;
}
int main()
{
const int N = 10;
int arr[N];
printf("size = %ld\n", sizeof(arr));
int x = 10;
const int SIZE = x;
int buf[SIZE];
printf("size = %ld\n", sizeof(buf));
const int FN = func();
int buf2[FN];
printf("size = %ld\n", sizeof(buf2));
return 0;
}
ubuntu 20 5.4.0-42-generic
gcc 9.3.0
compile:
gcc const_create_arr.c -Wall
show no warning
output:
size = 40
size = 40
size = 48
output corret
the last one FN is init by func(). we know that func() return vlaue should be computed in runtime. But an array definition should provide the true length of this array to compiler to help compiler allocate space. So I think the last one should not be passed at compiling. But it seems corret. I want to know how it works. Whether my gcc has optimise it and compute the func return when it compiling.
In all three cases you're creating a variable length array. For an array to not be a VLA the size needs to be an integer constant expression, and a variable with the const qualifier (no matter how it's initialized) does not qualify as one.
The definition of a VLA can be found in section 6.7.6.2p4 of the C standard regarding array declarators:
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; 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.
And the definition of an integer constant expression is given in section 6.6p6:
An integer constant expression shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, _Alignof expressions, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof or _Alignof operator.
There is nothing in this definition that qualifies a const qualified variable as an integer constant expression, so the sizeof operator in each of the three cases is being evaluated at runtime because the arrays are VLAs.
C has variable length arrays, so int x[y] is valid C provided y is defined in advance. It doesn't matter if y is const or not, it just needs to be > 0 to make any sense, as well as small enough that you don't use up the entire stack.
In this case y is 12, so you get a length 48 (12 * sizeof(int) where that's 4). This gets computed after the fact, not in advance like you might expect for something trivial like sizeof(int).
In C++ this is not the case as defined by the standard, however some compilers will still do it the C way.
Can sizeof safely be used on an array that has been declared without an explicit size specified inside the square brackets, but which gets initialised in the declaration?
Consider the following code:
unsigned int arr[] = { 1, 2, 3 };
size_t bytes = sizeof arr;
If compiled on macOS with clang-800.0.42.1 without any special compiler flags, this yields the expected result of 12.
But does the C standard (or any C standard, if they differ on this) guarantee this to be the case? Or do I have to declare it like unsigned int arr[3] in order for it to be "sane"?
Yes, the standard guarantees that the array element count will be equal to the number of elements in the array initializer in case no size is specified. See
C11 standard draft 6.7.9p22 and 6.7.9p25:
If an array of unknown size is initialized, its size is determined by
the largest indexed element with an explicit initializer. The array
type is completed at the end of its initializer list.
EXAMPLE 2 The declaration
int x[] = { 1, 3, 5 };
defines and initializes x as a one-dimensional array object that has three elements, as no size was specified and there are three initializers.
unsigned int arr[] = { 1, 2, 3 }; actually defines a complete array. The size of the array is known in this compilation unit and is n*sizeof(type) where n is the number of elements in the initialization list (here 3) and type is the underlying object type (here unsigned int).
That means that sizeof(arr) is defined in same scope as arr and has the expected value.
What would be completely different would be extern int arr[];. That would be a simple declaration that an array of that name will be provided in another compilation unit, but the compiler has no way to know its size. In that case using sizeof(arr) will be an error.
Another example of mere declaration is
void func(int arr[]) {
...
}
Here again the compiler only knows that the function will receive an int array, but again cannot know its size. But here the compiler generates a pointer that will receive the address of the array and sizeof(arr) is defined but is the size of that pointer and not the size of the original array.
I cannot understand why doing this is wrong:
const int n = 5;
int x[n] = { 1,1,3,4,5 };
even though n is already a const value.
While doing this seems to be right for the GNU compiler:
const int n = 5;
int x[n]; /*without initialization*/
I'm aware of VLA feature of C99 and I think it's related to what's going on but
I just need some clarification of what's happening in the background.
The key thing to remember is that const and "constant" mean two quite different things.
The const keyword really means "read-only". A constant is a numeric literal, such as 42 or 1.5 (or an enumeration or character constant). A constant expression is a particular kind of expression that can be evaluated at compile time, such as 2 + 2.
So given a declaration:
const int n = 5;
the expression n refers to the value of the object, and it's not treated as a constant expression. A typical compiler will optimize a reference to n, replacing it by the same code it would use for a literal 5, but that's not required -- and the rules for whether an expression is constant are determined by the language, not by the cleverness of the current compiler.
An example of the difference between const (read-only) and constant (evaluated at compile time) is:
const size_t now = time(NULL);
The const keyword means you're not allowed to modify the value of now after its initialization, but the value of time(NULL) clearly cannot be computed until run time.
So this:
const int n = 5;
int x[n];
is no more valid in C than it would be without the const keyword.
The language could (and IMHO probably should) evaluate n as a constant expression; it just isn't defined that way. (C++ does have such a rule; see the C++ standard or a decent reference for the gory details.)
If you want a named constant with the value 5, the most common way is to define a macro:
#define N 5
int x[N];
Another approach is to define an enumeration constant:
enum { n = 5 };
int x[n];
Enumeration constants are constant expressions, and are always of type int (which means this method won't work for types other than int). And it's arguably an abuse of the enum mechanism.
Starting with the 1999 standard, an array can be defined with a non-constant size; this is a VLA, or variable-length array. Such arrays are permitted only at block scope, and may not have initializers (since the compiler is unable to check that the initializer has the correct number of elements).
But given your original code:
const int n = 5;
int x[n] = { 1,1,3,4,5 };
you can let the compiler infer the length from the initializer:
int x[] = { 1,1,3,4,5 };
And you can then compute the length from the array's size:
const int x_len = sizeof x / sizeof x[0];
Why int x[n] is wrong where n is a const value?
n is not a constant. const only promise that n is a 'read-only' variable that shouldn't be modified during the program execution.
Note that in c, unlike c++, const qualified variables are not constant. Therefore, the array declared is a variable length array.
You can't use initializer list to initialize variable length arrays.
C11-§6.7.9/3:
The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.
You can use #define or enum to make n a constant
#define n 5
int x[n] = { 1,1,3,4,5 };
If you are exhaustively initialising an array, then it is easier, safer and more maintainable to let the compiler infer the array size:
int x[] = { 1,1,3,4,5 };
const int n = sizeof(x) / sizeof(*x) ;
Then to change the array size you only have to change the number of initialisers, rather than change the size and the initialiser list to match. Especially useful when there are many initialisers.
Even though n is a const, you cannot use it to define the size of an array unless you wish to create a VLA. However, you cannot use an initializer list to initialize a VLA.
Use a macro to create a fixed size array.
#define ARRAY_SIZE 5
int x[ARRAY_SIZE] = { 1,1,3,4,5 };
Is your code semantically different from myfunc() here:
void myfunc(const int n) {
int x[n] = { 1,1,3,4,5 };
printf("%d\n", x[n-1]);
*( (int *) &n) = 17; // Somewhat less "constant" than hoped...
return ;
}
int main(){
myfunc(4);
myfunc(5);
myfunc(6); // Haven't actually tested this. Boom? Maybe just printf(noise)?
return 0;
}
Is n really all that constant? How much space do you think the compiler should allocated for x[] (since it is the compiler's job to do so)?
As others have pointed out, the cv-qualifier const does not mean "a value that is constant during compilation and for all times after". It means "a value that the local code is not supposed to change (although it can)".
If in my program, I have this:
int arr[some_number];
What is the type of some_number?
Integer?
Unsigned integer?
Automatically determined (long, unsigned long etc.)
This might be a hypothetical question (assuming I can allocate as much memory as needed at compile time), just curious to know if type of some_number is always integer.
**EDIT
In case my language is not clear, on a system where sizeof(integer) is 2 bytes and I define array like:
int arr[65537] , will "65537" overflow and it is effectively, int arr[-1]?
some_number must either be an actual positive integer as in:-
int arr[1024]
or it can be a MACRO which resolves to a positive integer:-
#DEFINE some_number 1024
int arr[some_number]
As the interpretation is done at compile time and there are no program variable is used then there is no "type".
By default in C, the type of a number is int. You can use the suffix u to make it an unsigned integer, the suffix l to make it a long (and with some compiler the suffix ll to make it a long long, ie. a 64-bit integer).
Type of an expression doesn't depend on the context, so the type of some_number (some_expression actually) will be the same as if it was used not in the array definition. Another question is what types of expressions are allowed for designation of the array size.
I think it is of type size_t, which can differ from one platform to another. It's unsigned, that's for sure. Look at this.
some_number must be TRUE constant ,it cann't be variable.
for example
main()
{
int a=1;
int kk[a]={1};
}
It would result an error saying
variable-sized object may not be initialized
However we can not also use
int const a;
as array subscript beacuse const is not consider as true constant in C.
Supposing this is a definition inside a function, some_number can be any integral expression with a strictly positive value. If it is non-constant, the beast is called variable length array, VLA.
If you place it in outer scope or make it static, it has to evaluate to something that is constant.