Declaring C arrays - c

int array[5][3];
(obviously) creates a multi-dimensional C array of 5 by 3. However,
int x = 5;
int array[x][3];
does not. I've always thought it would. What don't I understand about C arrays? If they only allow a constant to define the length of a C array, is there a way to get around this in some way?

In ANSI C (aka C89), all array dimensions must be compile-time integer constants (this excludes variables declared as const). The one exception is that the first array dimension can be written as an empty set of brackets in certain contexts, such as function parameters, extern declarations, and initializations. For example:
// The first parameter is a pointer to an array of char with 5 columns and an
// unknown number of rows. It's equivalent to 'char (*array_param)[5]', i.e.
// "pointer to array 5 of char" (this only applies to function parameters).
void some_function(char array_param[][5])
{
array_param[2][3] = 'c'; // Accesses the (2*5 + 3)rd element
}
// Declare a global 2D array with 5 columns and an unknown number of rows
extern char global_array[][5];
// Declare a 3x2 array. The first dimension is determined by the number of
// initializer elements
int my_array[][2] = {{1, 2}, {3, 4}, {5, 6}};
C99 added a new feature called variable-length arrays (VLAs), where the first dimension is allowed to be a non-constant, but only for arrays declared on the stack (i.e. those with automatic storage). Global arrays (i.e. those with static storage) cannot be VLAs. For example:
void some_function(int x)
{
// Declare VLA on the stack with x rows and 5 columns. If the allocation
// fails because there's not enough stack space, the behavior is undefined.
// You'll probably crash with a segmentation fault/access violation, but
// when and where could be unpredictable.
int my_vla[x][5];
}
Note that the latest edition of the C standard, C11, makes VLAs optional. Objective-C is based off of C99 and supports VLAs. C++ does not have VLAs, although many C/C++ compilers such as g++ which support VLAs in their C implementation also support VLAs in C++ as an extension.

int x = 5;
int array[x][3];
Yes, it does. It's a C99 variable length array. Be sure to switch to C99 mode and be sure to have array declared at block or function scope. Variable length arrays cannot be declared at file scope.

Try:
const int x=5;
int array[x][3];
As you said x has to be a constant or else think what would happen if in the middle of the program you changed the value of x,what would be the dimension of array:(
But by declaring it constan if you change the value of x you get a compile error.

Related

Can I use an integer variable to define an arrays length?

Can I use a variable to define an array's size?
int test = 12;
int testarr[test];
Would this work, I don't want to change the size of the array after initialization. The int test's value isn't known at compile time.
From C99 it is allowed but only for the automatic variables.
this is illegal:
int test = 12;
int testarr[test]; // illegal - static storage variable
int foo(void)
{
int test = 12;
static int testarr[test]; // illegal - static storage variable
}
the only valid form is:
int foo(void)
{
int test = 12;
int testarr[test]; // legal - automatic storage variable
}
can i use an variable to define an arrays size?
This is called Variable Length Arrays (VLA).
Read Modern C then the C11 standard n1570 (and see this reference). VLAs are permitted in §6.7.6; also read the documentation of your C compiler (e.g. GCC).
But you don't want to overflow your call stack, typically limited to a megabyte on laptops (and OS specific).
So you may prefer C dynamic memory allocation with e.g. malloc(3) (and free ...) or calloc.
Beware of memory leaks.
You might be interested by tools such as valgrind. You need to learn to use your debugger (e.g. GDB).
Can I use an integer variable to define an arrays length?
Yes, that is what is called a variable length array and is part of the C standard since C99. Note that an implementation does not need to support it. Therefore you may prefer dynamic memory allocation. Take a look at here:
malloced array VS. variable-length-array
To cite the C standard:
"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;146) 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.)"
"146) Thus, * can be used only in function declarations that are not definitions (see 6.7.6.3)."
Source: C18, 6.7.6.2/4
Also note:
"Array objects declared with the _Thread_local, static, or extern storage-class specifier cannot have a variable length array (VLA) type."
Source: C18, 6.7.6.2/10
VLAs cannot be used:
at file scope.
when qualified with _Thread_local, static, or extern storage-class specifier.
if they have linkage.
Which means that they can only be used at function-scope and when of storage-class automatic, which is done by default when omitting any explicit specifier.
Feel free to ask for further clarification if you don't understand something.
Without knowing much of the context, wouldn't it be easier to just do this?
#define TEST 12 //to ensure this value will not change at all
int testarr[TEST];
Technically your method should work too but the value of test may change later on depending on the piece of code you written
So, when you try this on C, as in this [https://onlinegdb.com/rJzE8yzC8][1]
It successfully compiles and you can also update the value of the variable int test
However, after the update of test, the size of array does not change since arrays are static-defined.
For guarantee, I suggest you to use either const int or macro variables for doing this.

Initialize array with size specified by a variable

I was writing the following code
#include<stdio.h>
void fun(int n) {
int a[n] = {0};
}
void main() {
int a[4] = {0};
int i = 0;
fun(3);
}
and got this error
test.c: In function 'fun':
test.c:5:5: error: variable-sized object may not be initialized
while if I change the function fun to:-
void fun(int n) {
int a[n], i = 0;
for(i = 0; i < n; i++) {
a[i] = 0;
}
}
it works fine.
I know that the error is occuring because it's not allowed in the compiler's specification but what i want to know is why is it not possible to be implemented?
Is it due to some compile time or run time evaluation issue?
I have seen the answer of other question but i need a more elaborated answer.
Variable Length Array cannot be initialized like this
int a[n]={0};
From C Standards#6.7.9p3 Initialization [emphasis added]
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.
Using loop is one way to initialize the variable length array's. You can also use memset like this:
memset(a, 0, sizeof a);
Additional:
The C99 compiler should support the Variable Length Array's but they were made optional in C11 compiler.
An easy way is to send the size of array along with other parameters
Remember that you should send size before an array with that size
void fun(int n,int a[n]){
}
Although you have other alternatives like sizeof()
As an addition to H.S. answer:
From C Standards#6.7.9p3 Initialization [emphasis added]
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.
This is probably because Initializers have to be constant expressions. Constant expression have a definite value at compile time.
A {0} is an incomplete Initializer and the compiler would fill up the remaining values with 0.
If you have a VLA the compiler does not know the length of the Array and thus can not generate the initializer for it.
This depends on your compiler actually.
In old C You couldn't have variable size arrays. In function fun you use a as an array with variable size n. This is not allowed in old C. However, C99 and C11 standards support variable size arrays, so perhaps you have an old compiler. (DevC?) If you want to use some type of variable arrays in older C compilers, you have to use malloc and free.
Perhaps you wanted to write this code in C++? C++ doesn't support variable size arrays also, but the gcc compiler can run this code.
Check this out:
Why aren't variable-length arrays part of the C++ standard?
If you are using DevC, I think that if you change your file from test.c to test.cpp this code will work.

initialize the array with pointers to ints

Hey I'm working on a problem and here is what I have to do:-
Write a function called initarray that takes an array of pointers to int and an int representing the size of the array, as arguments. The function should initialize the array with pointers to ints (use malloc) that have a value corresponding to the array indices at which a pointer to them are stored (the pointer stored at array index 2 should point to an integer with a value of 2).
So far I've written this, but It's giving me an error "[Error] variable-sized object may not be initialized"
Can you tell me what I'm doing wrong here?
#include<stdio.h>
void initArray(int **a, int sz){
int i;
for (i = 0; i < sz; i++) {
a[i] = calloc (1, sizeof **a);
*a[i] = i;
}
}
int main(){
const int Var = 10;
int *array[Var] = {NULL};
initArray(array,3);
}
For historical reasons, the value of a const variable is never considered a constant expression in C.
So if you use it as an array dimension, then the array is a variable-length array, and variable-length arrays are not allowed to have initializers.
One solution not mentioned yet is to use enum. Enumerators are in fact constant expressions, and they don't suffer from the same "bigger hammer" issue as preprocessor macros:
int main()
{
enum { Var = 10 };
int *array[Var] = {NULL};
initArray(array,3);
}
C has no symbolic constants with user-defined type. You encountered one of the differences to C++.
The const qualifier just is a guarantee you give to the compiler you will not change the variable(!) Var.
Arrays with initialiser and global arrays require a constant expressing which can be evaluated at compile-time. As Var is semantically still a variable, you cannot use it.
The C-way to emulate symbolic constants are macros:
#define ARRAY_SIZE 10
...
// in your function:
int *array[ARRAY_SIZE] = ...
Macros are handled by the preprocessor and are a textual replacement before the actual compiler sees the code.
Note I changed the name to a more self-explanatory one. The macro should also be at the file-level, typically near the beginning to allow easier modifications. Using the integer constant 10 directly in the code is a bad idea. Such magic numbers are often cause of errors when a modification is required.
The error would suggest that you can't use an initializer (the = {NULL} in your main function) on a variable-sized object. While it looks like it isn't variable (because of the const on Var, and because 10 is a constant) it sees it as variable because you're accessing it through a variable. If you use:
int *array[10] = {NULL}
I think your snippet will work fine.

Copying array in C v/s copying structure in C

Arrays and structures in C store data in memory which is contiguous. Then why is that C does not allow direct copying of arrays using "=" where as it is allowed for structure.
Example:
int a[3] = {1,2,3};
int b[3];
b = a; // why is this not allowed.
struct book b1, b2;
b1.page = 100;
b1.price = 10.0;
b2 = b1; // Why is this allowed
For the first question
You cannot directly write to an array, you can write only to the individual cells to an array.
You can use a for loop to initialize array b or memcpy(&b, &a, sizeof b);
And with the structs the compiler does the memcpy for you.
Correct me if I am wrong.
When you type : b=a , the compiler expects that you are assigning an array to b, but a is just a pointer to the location where the first element of the array is stored so there is a type mismatch.This is why printf("%d",*a); will print 1.
And as for why structures can be assigned, it is because b1 and b2 in the above example are basically variables of the datatype book and variables can be assigned.When variables are assigned the contents are copied and they don't refer to the same memory location.This example might explain what i am saying more clearly:
#include<stdio.h>
typedef struct{int a;}num;
int main()
{
num b,c;
b.a = 10;
c=b;
b.a =11;
printf("%d\n",(c.a));
return 0;
}
The output is 10. This proves that b and c in this example do not point to the same memory.hope this helps.
Assignment requires that the type and therefore size of whatever is being assigned is known to the compiler. So an assignment of form
a = b;
requires that the types of a and b are both known to the compiler. If the types are the same (e.g. both a and b are of type int) then the compiler can simply copy b into a by whatever instructions it deems are most efficient. If the types are different, but an implicit promotion or type conversion is allowed, then the assignment is also possible after doing a promotion. For example, if a is of type long and b is of type short, then b will be implicitly promoted to long and the result of that promotion stored in a.
This doesn't work for arrays, because the size of an array (calculated as the size of its elements multiplied by number of elements) is not necessarily known. One compilation unit (aka source file) may have a declaration (possibly by including a header file)
extern int a[];
extern int b[];
void some_func()
{
a = b;
}
which tells the compiler that a and b are arrays of int, but that they will be defined (which includes giving them a size) by another compilation unit. Another compilation unit may then do;
extern int a[];
int a[] = {3,1,4,2,3}; /* definition of a */
and a third compilation unit may similarly define b as an array of 27 elements.
Once the object files are linked into a single executable, the usages of a and b in all compilation units are associated, and all operations on them refer to the same definitions.
The problem with this comes about because the separate compilation model is a core feature of C. So the compiler, when chewing on the first compilation unit above, has no information about the size of the arrays since it has no visibility of other compilation units, and is required to succeed or diagnose errors without referring to them. Since there is no information about the number of elements in either array available to the first compilation unit, there is no way to work out how many elements to copy from one array to another. The handling of this in C is that the assignment a = b is a diagnosable error in the function some_func().
There are alternative approaches (and some other programming languages handle such cases differently) but they are generally associated with other trade-offs.
The considerations doesn't generally affect struct types, since their size is known at compile time. So, if a and b are of the same struct type, the assignment a = b is possible - and can be implemented by (say) a call of memcpy().
Note: I am making some deliberate over-simplification in the explanation above, such as not considering the case of structs with flexible array members (from C99). Discussing such cases would make the discussion above more complicated, without changing the core considerations.

array with constant size (global vs stack)

When I tried this code it works:
const int i = 5;
int main() {
int arry[i];
}
Even though this didn't work:
const int i = 5;
int arry[i];
int main() {
}
I have read all posts here about arrays with constant sizes, but I can't understand why when declaring arry in main it works.
The issue here is that const in C doesn’t result in a true constant.
When you write const int i = 5 what you have is a read-only variable and not a constant. In C99 an array dimensioned with i is a variable length array (VLA). VLAs are only available for stack allocated variables, hence the compilation error you see.
If you need an array with global scope you should switch to a macro.
#define ARRAY_SIZE 5
int arry[ARRAY_SIZE];
This is valid because 5 is a literal which is a true constant.
In fact, even for an array of automatic storage (i.e. stack allocated local variable) you should avoid a VLA since they incur a runtime overhead.
Version 2 is simply not valid C, since i is a read-only variable rather than a true compile-time constant. If you wanted to make it work, you could use malloc and free (or a #define for the size).
Version 1 uses a variable-length array, which is standard feature of C99. gcc supports this syntax in pre-C99 code as an extension. If you compiled your code as C90 and turned on -pedantic, you'd get a warning that ISO C90 forbids variable length array ‘arry’.

Resources