You are on page 1of 9

Every object has a storage class, which may be automatic, static, or allocated.

Variables
declared within a block by default have automatic storage, as do those explicitly declared
with the auto[2] or register storage class specifiers. The auto and register specifiers may
only be used within functions and function argument declarations; as such, the auto
specifier is always redundant. Objects declared outside of all blocks and those explicitly
declared with the static storage class specifier have static storage duration.

Objects with automatic storage are local to the block in which they were declared and are
discarded when the block is exited. Additionally, objects declared with the register
storage class may be given higher priority by the compiler for access to registers;
although they may not actually be stored in registers, objects with this storage class may
not be used with the address-of (&) unary operator. Objects with static storage persist
upon exit from the block in which they were declared. In this way, the same object can be
accessed by a function across multiple calls. Objects with allocated storage duration are
created and destroyed explicitly with malloc, free, and related functions.

The extern storage class specifier indicates that the storage for an object has been defined
elsewhere. When used inside a block, it indicates that the storage has been defined by a
declaration outside of that block. When used outside of all blocks, it indicates that the
storage has been defined outside of the file. The extern storage class specifier is
redundant when used on a function declaration. It indicates that the declared function has
been defined outside of the file.
[edit] Type qualifiers

Objects can be qualified to indicate special properties of the data they contain. The const
type qualifier indicates that the value of an object should not change once it has been
initialized. Attempting to modify an object qualified with const yields undefined
behavior, so some C implementations store them in read-only segments of memory. The
volatile type qualifier indicates that the value of an object may be changed externally
without any action by the program (see volatile variable); it may be completely ignored
by the compiler.
[edit] Pointers

In declarations the asterisk modifier (*) specifies a pointer type. For example, where the
specifier int would refer to the integer type, the specifier int * refers to the type "pointer
to integer". Pointer values associate two pieces of information: a memory address and a
data type. The following line of code declares a pointer-to-integer variable called ptr:

int *ptr;

[edit] Referencing

When a non-static pointer is declared, it has an unspecified value associated with it. The
address associated with such a pointer must be changed by assignment prior to using it. In
the following example, ptr is set so that it points to the data associated with the variable a:
int *ptr;

int a;

ptr = &a;
In order to accomplish this, the "address-of" operator (unary &) is used. It produces the
memory location of the data object that follows.
[edit] Dereferencing

The pointed-to data can be accessed through a pointer value. In the following example,
the integer variable b is set to the value 10:

int *p;
int a, b;

a = 10;
p = &a;
b = *p;

In order to accomplish that task, the dereference operator (unary *) is used. It returns the
data to which its operandwhich must be of pointer typepoints. Thus, the expression
*p denotes the same value as a.
[edit] Arrays
[edit] Array definition

Arrays are used in C to represent structures of consecutive elements of the same type.
The definition of a (fixed-size) array has the following syntax:

int array[100];

which defines an array named array to hold 100 values of the primitive type int. If
declared within a function, the array dimension may also be a non-constant expression, in
which case memory for the specified number of elements will be allocated. In most
contexts in later use, a mention of the variable array is converted to a pointer to the first
item in the array. The sizeof operator is an exception: sizeof array yields the size of the
entire array (that is, 100 times the size of an int). Another exception is the & (address-of)
operator, which yields a pointer to the entire array (e.g. int (*ptr_to_array)[100] =
&array;).
[edit] Accessing elements

The primary facility for accessing the values of the elements of an array is the array
subscript operator. To access the i-indexed element of array, the syntax would be array[i],
which refers to the value stored in that array element.

Array subscript numbering begins at 0. The largest allowed array subscript is therefore
equal to the number of elements in the array minus 1. To illustrate this, consider an array
a declared as having 10 elements; the first element would be a[0] and the last element
would be a[9]. C provides no facility for automatic bounds checking for array usage.
Though logically the last subscript in an array of 10 elements would be 9, subscripts 10,
11, and so forth could accidentally be specified, with undefined results.
Due to arraypointer interchangeability, the addresses of each of the array elements can
be expressed in equivalent pointer arithmetic. The following table illustrates both
methods for the existing array:
Array subscripts vs. pointer arithmetic Element index 1 2 3 n
Array subscript array[0] array[1] array[2] array[n-1]
Dereferenced pointer *array *(array + 1) *(array + 2) *(array + n-1)

Similarly, since the expression a[i] is semantically equivalent to *(a+i), which in turn is
equivalent to *(i+a), the expression can also be written as i[a] (although this form is
rarely used).
[edit] Dynamic arrays

A constant value is required for the dimension in a declaration of a static array. A desired
feature is the ability to set the length of an array dynamically at run-time instead:

int n = ...;
int a[n];
a[3] = 10;

This behavior can be simulated with the help of the C standard library. The malloc
function provides a simple method for allocating memory. It takes one parameter: the
amount of memory to allocate in bytes. Upon successful allocation, malloc returns a
generic (void *) pointer value, pointing to the beginning of the allocated space. The
pointer value returned is converted to an appropriate type implicitly by assignment. If the
allocation could not be completed, malloc returns a null pointer. The following segment
is therefore similar in function to the above desired declaration:

#include <stdlib.h> /* declares malloc */

int *a;
a = malloc(n * sizeof(int));
a[3] = 10;

The result is a "pointer to int" variable (a) that points to the first of n contiguous int
objects; due to arraypointer equivalence this can be used in place of an actual array
name, as shown in the last line. The advantage in using this dynamic allocation is that the
amount of memory that is allocated to it can be limited to what is actually needed at run
time, and this can be changed as needed (using the standard library function realloc).

When the dynamically-allocated memory is no longer needed, it should be released back


to the run-time system. This is done with a call to the free function. It takes a single
parameter: a pointer to previously allocated memory. This is the value that was returned
by a previous call to malloc. It is considered good practice to then set the pointer variable
to NULL so that further attempts to access the memory to which it points will fail. If this
is not done, the variable becomes a dangling pointer, and such errors in the code (or
manipulations by an attacker) might be very hard to detect and lead to obscure and
potentially dangerous malfunction caused by memory corruption.

free(a);
a = NULL;

Standard C-99 also supports variable-length arrays (VLAs) within block scope. Such
array variables are allocated based on the value of an integer value at runtime upon entry
to a block, and are deallocated at the end of the block.

float read_and_process(int sz)


{
float vals[sz]; // VLA, size determined at runtime

for (int i = 0; i < sz; i++)


vals[i] = read_value();
return process(vals, sz);
}

[edit] Multidimensional arrays

In addition, C supports arrays of multiple dimensions, which are stored in row-major


order. Technically, C multidimensional arrays are just one-dimensional arrays whose
elements are arrays. The syntax for declaring multidimensional arrays is as follows:

int array2d[ROWS][COLUMNS];

(where ROWS and COLUMNS are constants); this defines a two-dimensional array.
Reading the subscripts from left to right, array2d is an array of length ROWS, each
element of which is an array of COLUMNS i

You might also like