You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

Traditionally C arrays are declared with an index that is either a fixed constant, or empty. An array with a fixed constant index indicates to the compiler how much space to reserve for the array. An array declaration with an empty index is considered an incomplete type, and indicates that the variable indicates a pointer to an array of indeterminite size.

The C standard, since 1999 has permitted array declarations to use extended syntax. The most well-known extension is for variable-length arrays (VLAs). In this case, the array index is a variable, and the size of the array is determined at run-time, rather than compile-time.

Section 6.7.6.1, paragraph 1, summarizes the array index syntax extensions:

In addition to optional type qualifiers and the keyword static, the [ and ] may delimit
an expression or *. If they delimit an expression (which specifies the size of an array), the
expression shall have an integer type. If the expression is a constant expression, it shall
have a value greater than zero. The element type shall not be an incomplete or function
type. The optional type qualifiers and the keyword static shall appear only in a
declaration of a function parameter with an array type, and then only in the outermost
array type derivation.

By the way, one thing that came up for me last week was that we probably ought to mention conformant array parameters. For example,

int f(size_t n, int a[n])

is a handy way to document the size of an array parameter.

Standard Examples

Section 6.7.6.3 of C11 has several examples of conformant array parameters. Example 4 illustrates a variably modified parameter:

void addscalar(int n, int m,
               double a[n][n*m+300], double x);

int main()
{
  double b[4][308];
  addscalar(4, 2, b, 2.17);
  return 0;
}

void addscalar(int n, int m,
               double a[n][n*m+300], double x)
{
  for (int i = 0; i < n; i++)
  for (int j = 0, k = n*m+300; j < k; j++)
    // a is a pointer to a VLA with n*m+300 elements
    a[i][j] += x;
}

Example 5 illustrates a set of compatible function prototype declarators

double maximum(int n, int m, double a[n][m]);
double maximum(int n, int m, double a[*][*]);
double maximum(int n, int m, double a[ ][*]);
double maximum(int n, int m, double a[ ][m]);

These prototype declarators are also compatible:

void f(double (* restrict) a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);
void f(double a[restrict static 3][5]);

C11 concludes with the following note regarding example 5:

Note that the last declaration also specifies that the argument corresponding to a in any call to f must be a
non-null pointer to the first of at least three arrays of 5 doubles, which the others do not.

Noncompliant Code Example

void my_memset(char* p, size_t n, char v) {
  memset( p, v, n);
}

Noncompliant Code Example

This doesn't compile because n is used before being declared.

void my_memset(char p[n], size_t n, char v) {
  memset( p, v, n);
}

Compliant Solution

void my_memset(size_t n, char p[n], char v) {
  memset( p, v, n);
}

Bibliography

C99, section 6.7.6.3 (see example 4)

  • No labels