C90 and C + + array object definitions are statically linked and must be given complete information about the object at compile time. However, in the process of programming, we often encounter the need to define the context of the array, in the run time to know the length of the array. In this case, C90 and C + + do not have a good way to solve (except for STL methods), only in the heap to create a memory image and a demand array of alternatives, this alternative does not have an array type, this is a pity. The variable-length array of C99 provides a partial solution to this problem.
Variable length in variable length arrays (variable length array, or VLA) refers to the variable length of the compile period, which can be an integer-type expression when the array is defined, and no longer must be an integer constant expression like c90/c++. In C99, you can define an array as follows:
int n = ten, M = 20;
Char A[n];
int b[m][n];
The type of a is char[n], the equivalent pointer type is CHAR*,B of type int[m][n], and the equivalent pointer type is int (*) [n]. Int (*) [n] is a pointer to VLA, which is a pointer type derived from int[n].
As a result, C99 introduces a new concept: variable type (variably modified type, short VM). A full declarator with a derived from VLA is called a variable change. The VM contains VLA and pointers to VLA, note that the VM type does not create a new kind of type, VLA and pointers to VLA still belong to the array type and pointer type, and are an extension of the array type and pointer type.
The declaration or definition of a VM entity must conform to the following three conditions:
1. The identifier representing the object belongs to the ordinary identifier (ordinary identifier);
2. Have a code block scope or function prototype scope;
3. No link.
Ordinary identifier refers to identifiers other than the following three cases:
1. tag (label);
2. Structure, union and enumeration tags (struct tag, uion tag, enum tag);
3. The structure, union member identifier.
This means that an entity of a VM type cannot be a member of a struct, union. The second condition restricts the VM from having a file scope, and storage continuity can only be auto, because the compiler usually stores the global object in the data segment, and the complete information for the object must be determined during the compilation period.
VLA cannot have a static storage cycle, but pointers to VLA can.
The compatibility of two VLA arrays, in addition to satisfying the type of element to be compatible, the value of the expression that determines the size of the two array is also equal, otherwise the behavior is undefined.
Here are some examples to illustrate the legality of the types of VMS:
#include <stdio.h>
int n = 10;
int a[n]; /* Illegal, VM type cannot have file scope */
int (*p) [n]; /* Illegal, VM type cannot have file scope */
struct test
{
int k;
int a[n]; /* Illegal, A is not an ordinary identifier */
int (*p) [n]; /* Illegal, p is not an ordinary identifier */
};
int main (void)
{
int m = 20;
struct TEST1
{
int k;
int a[n]; /* Illegal, A is not an ordinary identifier */
int (*p) [n]; /* Illegal, A is not an ordinary identifier */
};
extern int A[n]; /* Illegal, VLA cannot have link sex */
static int b[n]; /* Illegal, VLA cannot have a static storage cycle */
int c[n]; /* Legal, Auto vla*/
int d[m][n]; /* Legal, Auto vla*/
static int (*P1) [n] = D; /* Legit, static VM pointer */
n = 20;
static int (*P2) [n] = D; /* Undefined behavior */
return 0;
}
The size of a VLA object cannot be changed during its lifetime, even if the value of the expression that determines its size changes after the object definition. It is a misconception that some people see variable-length characters that associate the VLA array with the freedom to change size over the lifetime. VLA just compile time variable, once the definition can not be changed, not the runtime variable, the runtime variable array is called dynamic array, dynamic array in theory can be achieved, but the cost may be too large, not worth the candle. Consider the following code:
#include <stdio.h>
int main (void)
{
int n = ten, M = 20;
Char A[m][n];
char (*P) [n] = A;
printf ("%u%u", sizeof (a), sizeof (*P));
n = 20;
m = 30;
printf ("/n");
printf ("%u%u", sizeof (a), sizeof (*P));
return 0;
}
Although the values of N and M are changed in subsequent code, the size of the objects pointed to by a and P does not change.
The code above uses the operator sizeof, in c90/c++, sizeof deduces the result from the type of the operand, does not actually calculate the operand, and the result of the operator is an integer constant. When sizeof's operand is VLA, the situation is different. sizeof must calculate the VLA to get the size of the VLA, the result of which is an integer, not an integer constant.
A VM can also function as a formal parameter in addition to being an automatic object. As a VLA of a formal parameter, as with a non-VLA array, it is adjusted to the equivalent pointer, for example:
void func (int a[m][n]); Equivalent to void func (int (*a) [n]);
In a function prototype declaration, the VLA parameter can use the * tag, which is used in [] to indicate that a VLA object is declared here. If VLA in a function prototype declaration uses a length expression, the expression is ignored, as with the * tag, and the following function prototype declarations are the same:
void func (int a[m][n]);
void func (int a[*][n]);
void func (int a[][n]);
void func (int a[*][*]);
void func (int a[][*]);
void func (int (*a) [*]);
* Tags can only be used in function prototype declarations. Another example:
#include <stdio.h>
void func (int, int, int a[*][*]);
int main (void)
{
int m = ten, n = 20;
int a[m][n];
int b[m][m*n];
Func (M, N, a); /* Undefined behavior */
Func (M, n, b);
return 0;
}
void func (int m, int n, int a[m][m*n])
{
printf ("%u/n", sizeof (*a));
}
In addition to the * tag, the array in the formal parameter can also use the Type qualifier const, volatile, restrict, and static keywords. Because VLA in formal parameters are automatically adjusted to the equivalent pointers, these type qualifiers actually qualify a pointer, for example:
void func (int, int, int a[const][*]);
is equivalent to
void func (int, int, int (*const a) [*]);
It states that a is a const object and cannot modify its represented object directly within the Func by a. For example:
void func (int, int, int a[const][*]);
........
void func (int m, int n, int a[const m][n])
{
int b[m][n];
A = b; /* error, cannot modify the object it represents by a */
}
Static indicates that the value of the passed-in argument is at least as large as the value of the length expression to which it is decorated. For example:
void func (int, int, int a[const static 20][*]);
......
int m = A, n = 10;
int a[m][n];
int b[n][m];
Func (M, N, a);
Func (M, n, b); /* ERROR, the first-dimensional length of B is less than static 20*/
The type qualifier and the static keyword can only be used for the first dimension of a function parameter with an array type. The terms here are array types, meaning that they can be used not only for VLA, but also for general array parameters.
On the whole, although the definition of VLA is variable in length, it is not a dynamic array and cannot be changed during the run time, subject to other factors, it just provides a partial solution.
Nineth Chapter C99 Variable length array vla detailed