United States |
Previous | Contents | Index |
Character objects are declared with the char keyword. The following example shows a character declaration with the initialization of a character object:
char ch = 'a'; /* Declares an object ch with an initial value 'a' */ |
In C, character string literals are stored in arrays of type
char
. See Section 4.7 for more information on arrays.
4.4.4 Declaring Floating-Point Variables
When declaring floating-point objects, determine the amount of precision needed for the stored object. Single-precision or double-precision objects can be used. For single precision, use the float keyword. For double precision, use the double or long double keywords. For example:
float x = 7.5; double y = 3.141596; |
See your platform-specific Compaq C documentation for specific
information on the range and precision of floating-point types.
4.5 Declaring Enumerations
An enumerated type is a user-defined integer type. An enumerated type defines enumeration constants, which are integral constant expressions with values that can be represented as integers. An enumerated type declaration follows this syntax:
enum-specifier:
enum identifieropt { enumerator-list} |
enumerator-list:
enumerator |
enumerator:
enumeration-constant |
In Compaq C, objects of type
enum
are compatible with objects of type
signed int
.
The following example shows the declaration of an enumeration type and an enumeration tag:
enum shades { off, verydim, dim, prettybright, bright } light; |
This declaration defines the variable light to be of an enumerated type shades . light can assume any of the enumerated values.
The tag shades is the enumeration tag of the new type. off through bright are the enumeration constants with values 0 through 4. These enumeration constants are constant values and can be used wherever integer constants are valid.
Once a tag is declared, it can be used as a reference to that enumerated type, as in the following declaration, where the variable light1 is an object of the enumerated data type shades :
enum shades light1; |
An incomplete type declaration of an enumerated type is illegal; for example:
enum e; |
An enum tag can have the same spelling as other identifiers in the same program in other name spaces. However, enum constant names share the same name space as variables and functions, so they must have unique names to avoid ambiguity.
Internally, each enumeration constant is associated with an integer constant; the compiler gives the first enumeration constant the value 0 by default, and the remaining enumeration constants are incremented by 1 for each succeeding value. Any enumeration constant can be set to a specific integer constant value. The enumeration constants following such a construct (unless they are also set to specific values) then receive values that are one greater than the previous value. Consider the following example:
enum spectrum { red, yellow = 4, green, blue, indigo, violet } color2 = yellow; |
This declaration gives red , yellow , green , blue ,..., the values 0, 4, 5, 6,... Assigning duplicate values to enumeration constants is permitted.
The value of
color2
is an integer (4), not a string such as "red" or "yellow".
4.6 Declaring Pointers
Pointers are variables that contain the memory addresses of objects or functions. Pointer variables are declared as a pointer type by using the asterisk punctuator and the data type of the object pointed to, as shown in the following syntax:
pointer:
* type-qualifier-listopt |
type-qualifier-list:
type-qualifier |
By default, Compaq C pointers are 32 bits long on OpenVMS
systems and 64 bits long on Tru64 UNIX systems. Although their
defaults are different, both OpenVMS Alpha and Tru64
UNIX systems support 32-bit (short) and 64-bit (long) pointers.
Compaq C provides qualifiers/switches and
#pragma
preprocessor directives to control pointer size.
The type-qualifier is either const , volatile , __unaligned (ALPHA), __restrict , or any combination thereof.
An object of pointer type is declared as in the following example:
char *px; |
In this example, identifier px is declared as a pointer to an object of type char . No type-qualifier is used in this example. The expression *px yields the char that px points to.
The following declarations show the difference between a variable pointer to a constant, a constant pointer to a variable, and a constant pointer to a constant object.
const int *ptr_to_constant; /* pointer variable pointing to a const object */ int *const constant_ptr; /* constant pointer to a non-const object */ const int *const constant_ptr; /* Const pointer to a const object */ |
The contents of an object pointed to by ptr_to_constant cannot be modified through that pointer, but ptr_to_constant itself can be changed to point to another const -qualified object. Similarly, the contents of the integer pointed to by constant_ptr can be modified, but constant_ptr itself will always point to the same location.
The declaration of the constant pointer constant_ptr can be clarified by including a definition for the type pointer to int . The following example declares constant_ptr as an object with type const-qualified pointer to int . The pointer's value (an address) is constant:
typedef int *int_ptr; const int_ptr constant_ptr; |
The __unaligned data-type qualifier can be used in pointer definitions on Alpha systems. to indicate to the compiler that the data pointed to is not properly aligned on a correct address. (To be properly aligned, the address of an object must be a multiple of the size of the type. For example, 2-byte objects must be aligned on even addresses.) (ALPHA)
When data is accessed through a pointer declared __unaligned , the compiler generates the additional code necessary to copy or store the data without causing alignment errors. It is best to avoid use of misaligned data altogether, but in some cases the usage may be justified by the need to access packed structures, or by other considerations. (ALPHA)
The __restrict data-type qualifier is used to designate a pointer as pointing to a distinct object, thus allowing compiler optimizations to be made (see Section 3.7.4).
Unless an
extern
or
static
pointer variable is explicitly initialized, it is initialized to a null
pointer. A null pointer is a pointer value of 0. The contents of an
uninitialized
auto
pointer are undefined.
4.6.1 Declaring void Pointers
A void pointer is a pointer without a specified data type to describe the object to which it points. In effect, it is a generic pointer. (Before the ANSI C standard, char * was used to define generic pointers; this practice is now discouraged by the ANSI standard because it is less portable.)
A pointer to any type can be assigned to a void pointer without a cast, and vice versa. See Section 6.4.6 for more information on the cast operation. The following statements show how a void pointer can be assigned to other typed pointers, without explicit casts:
float *float_pointer; void *void_pointer; . . . float_pointer = void_pointer; /* or, */ void_pointer = float_pointer; |
A void pointer is often used in function calls, function arguments, or function prototypes when a parameter or return value is a pointer of an unknown type. Consider the following example, where a void pointer is used as a generic return value:
void *memcpy (void *s1, const void *s2, size_t n); { void *generic_pointer; . . . /* The function return value can be a pointer to many types. */ generic_pointer = func_returning_pointer( arg1, arg2, arg3 ); . . . /* size_t is a defined type */ } |
See Section 5.3 for further information about using
void
in function declarations.
4.6.2 Initializing Pointers
The pointer object can be initialized with a single expression. For example:
int i = 10; int *p = &i; /* p is a pointer to int, initialized */ /* as holding the address of i */ |
Without an initializer, the values of static and extern pointers are automatically initialized to null pointers (pointers to memory location 0).
The following declaration defines p with type pointer to char , and initializes p to point to an object of type array of char with length 4, whose elements are initialized by a character string literal. (The null character is the fourth member of the array.) If an attempt is made to use p to modify the contents of the array, the behavior is undefined.
char *p = "abc"; |
Arrays are declared with the bracket punctuators [ ], as shown in the following syntax:
storage-class-specifieropt type-specifier declarator [* or constant-expression-listopt] |
The following example shows a declaration of a 10-element array of integers, a variable called table_one :
int table_one[10]; |
The type-specifier shows the data type of the elements. The elements of an array can be of any scalar or aggregate data type. The identifier table_one specifies the name of the array. The constant expression 10 gives the number of elements in a single dimension. Arrays in C are zero-based; that is, the first element of the array is identified with a 0 subscript, such as the one shown in the following example:
int x[5]; x[0] = 25; /* The first array element is assigned the value 25 */ |
The expression between the brackets in the declaration must be either the ( * ) punctuator or an integral constant expression with a value greater than zero.
If * is specified between the brackets, then the array type is a variable-length array type of unspecified size, which can be used only in declarations with function prototype scope.
If the size expression 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, it is a variable-length array type. The size of each instance of a variable-length array type does not change during its lifetime. For more information on variable-length arrays, see Section 4.7.3.
Omitting the * or the constant expression creates an incomplete array declaration, which is useful in the following cases:
extern int array1[]; int first_function(void) { . . . } |
int array1[10]; int second_function(void) { . . . } |
char array_one[] = "Shemps"; char array_two[] = { 'S', 'h', 'e', 'm', 'p', 's', '\0' }; |
main() { /* Initialize array */ static char arg_str[] = "Thomas"; int sum; sum = adder(arg_str); /* Pass address of first array element */ . . . } |
/* adder adds ASCII values of letters in array */ int adder( char param_string[]) { int i, sum = 0; /* Incrementer and sum */ /* Loop until NULL char */ for (i = 0; param_string[i] != '\0'; i++) sum += param_string[i]; return sum; } |
Array members can also be pointers. The following example declares an array of floating-point numbers and an array of pointers to floating-point numbers:
float fa[11], *afp[17]; |
When a function parameter is declared as an array, the compiler treats the declaration as a pointer to the first element of the array. For example, if x is a parameter and is intended to represent an array of integers, it can be declared as any one of the following declarations:
int x[]; int *x; int x[10]; |
Note that the specified size of the array does not matter in the case of a function parameter, since the pointer always points to only the first element of the array.
C supports arrays declared as an array of arrays. These are sometimes called multidimensional arrays. Consider the following example, where variable table_one is a two-dimensional array containing 20 integers:
int table_one[10][2]; |
Arrays are stored in row-major order, which means the element
table_one[0][0]
(in the previous example) immediately precedes
table_one[0][1]
, which in turn immediately precedes
table_one[1][0]
.
4.7.1 Initializing Arrays
Arrays are initialized with a brace-enclosed list of constant expressions. A list of initializers for an incomplete array declaration completes the array's type and completely defines the array size. Therefore, when initializing an array of unknown size, the number of initializers in the initializer list determines the size of the array. For example, the following declaration initializes an array of three elements:
int x[] = { 1, 2, 3 }; |
If the array being initialized has a storage class of static , the initializers must be constant expressions.
Initializers for an array of a given size are assigned to array members on a one-to-one basis. If there are too few initializers for all members, the remaining members are initialized to 0. Listing too many initializers for a given size array is an error. For example:
int x[5] = { 0, 1, 2, 3, 4, 5 }; /* error */ |
String literals are often assigned to a char or wchar_t array. In this case, each character of the string represents one member of a one-dimensional array, and the array is terminated with the null character. When an array is initialized by a pointer to a string literal, the string literal cannot be modified through the pointer.
When initializing an array with a string literal, use quotation marks around the initializing string. For example:
char string[26] = { "This is a string literal." }; /* The braces above are optional here */ |
The terminating null character is appended to the end of the string if the size permits, as it does in this case. Another form for initializing an array with characters is the following:
char string[12] = {'T', 'h', 'i', 's', ' ', 'w', 'a', 'y' }; |
The preceding example creates a one-dimensional array containing the string value " This way ". The characters in this array can be freely modified. Remaining uninitialized array members will be automatically initialized to zero.
If the size of the array used for a string literal is not explicitly stated, its size is determined by the number of characters in the string (including the terminating null character). If the size of the array is explicitly stated, initializing the array with a string literal longer than the array is an error.
There is one special case where the null character is not automatically appended to the array. This case is when the array size is explicitly specified and the number of initializers completely fills the array size. For example:
Here, the array c holds only the four specified characters, a , b , c , and d . No null character terminates the array. |
Using the following rules, you can omit braces when initializing the members of a multidimensional arrays:
Consider the following example:
float x[4][2] = { { 1, 2 } { 3, 4 } { 5, 6 } }; |
In this example, 1 and 2 initialize the first row of the array x , and the following two lines initialize the second and third rows, respectively. The initialization ends before the fourth row is initialized, so the members of the fourth row default to 0. Here is the result:
x[0][0] = 1; x[0][1] = 2; x[1][0] = 3; x[1][1] = 4; x[2][0] = 5; x[2][1] = 6; x[3][0] = 0; x[3][1] = 0; |
The following declaration achieves the same result:
float x[4][2] = { 1, 2, 3, 4, 5, 6 }; |
Here, the compiler fills the array row by row with the available initial values. The compiler places 1 and 2 in the first row ( x[0] ), 3 and 4 in the second row ( x[1] ), and 5 and 6 in the third row ( x[2] ). The remaining members of the array are initialized to zero.
|
Previous | Next | Contents | Index |
|