Professional Documents
Culture Documents
C Variable Types and Declarations
C Variable Types and Declarations
C Variable Types and Declarations
The C programming language has an extensive system for declaring variables of different
types. The rules for the more complex types can be confusing at times, due to the decisions taken
over their design. The principal decision is that the declaration of a variable should be similar,
syntactically, to its use (declaration reflects use). This article presents a collection of variable
declarations, starting at simple types, and proceeding to more complex types. No attempt is made
to present code which actually uses the variables declared.
Contents
[hide]
1 Basic types
o 1.1 Signedness
o 1.2 Size
o 1.3 Type qualifiers
2 Pointer types
o 2.1 Pointers to pointers
3 Arrays
o 3.1 Arrays of arrays
o 3.2 Arrays of pointers
o 3.3 Pointers to arrays
o 3.4 Arrays are pointers
4 Functions
5 See also
Type
Meaning
name
char
The most basic unit addressable by the machine; typically a single octet(one byte).
This is an integral type.
int
The most natural size of integer for the machine; typically a whole 16, 32 or 64-bit(2,
4, or 8 bytes respectively) addressable word.
float A single-precision floating point value.
double A double-precision floating point value.
To declare a variable of any of these basic types, the name of the type is given first, then the
name of the new variable second.
char red;
int i;
Various qualifiers can be placed on these basic types, in order to further describe their type.
[edit] Signedness
unsigned int x;
signed int y;
int z; /* Same as "signed int" */
unsigned char grey;
signed char white;
If signed, the most significant bit designates a positive or negative value leaving the remaining
bits to be used to hold a designated value. Unsigned integers can only take non-negative values
(positive or zero), while signed integers (default) can take both positive and negative values. The
advantage of unsigned integers is to allow a greater range of positive values (e.g., 0 → +65535
depending on the size of the integer), whereas signed integers allow only up to half the same
number as positive integers and the other half as negative integers (e.g., −32768 → +32767).
An unsigned character, depending on the code page, might access an extended range of
characters from 0 → +255, instead of that accessible by a signed char from −128 → +127, or it
might simply be used as a small integer. The standard requires char, signed char, unsigned
char to be different types. Since most standardized string functions take pointers to plain char,
many C compilers correctly complain if one of the other character types is used for strings
passed to these functions.
[edit] Size
The int type can also be given a size qualifier, to specify more precisely the range of values
(and memory size requirements) of the value stored.
When declaring a short int or long int, it is permissible to omit the int, as this is implied.
The following two declarations are equivalent.
The standard does not require that any of these sizes be necessarily different. It is perfectly valid,
for example, if all four types are 64 bits long. In order to allow a simple and concise description
of the sizes a compiler will apply to each of the four types (and the size of a pointer type; see
below), a simple naming scheme has been devised; see 64-Bit Programming Models. Two
popular schemes are ILP32, in which int, long int and pointer types are 32 bits long; and
LP64, in which long int and pointers are 64 bits, and int are 32 bits. Most implementations
under these schemes use 16-bit short ints.
A double variable can be marked as being a long double, which the compiler may use to select
a larger floating point representation than a plain double. Again, the standard is unspecific on
the relative sizes of the floating point values, and only requires a float not to be larger than a
double, which should not be larger than a long double.
To help promote safety in programs, values can be marked as being constant with the const type
qualifier. Compilers must diagnose, usually with an error, attempts to modify such variables.
Since const variables cannot be assigned to, they must be initialized at the point of declaration.
The C standard permits arbitrary ordering of type qualifiers, such as const, and type specifiers,
such as int. Both of the following declarations are therefore equivalent:
While the former more closely reflects the use of const marking when used in pointer types, the
latter form is more natural and almost ubiquitous.
char *square;
long *circle;
K&R gives a good explanation for the slightly odd use of asterisks in this way, as well as a
motivation for why they attach the asterisk onto the name of the variable, when it might seem to
make more sense being attached to the name of the type. This is, that when the program
dereferences the pointer, it has the type of the object to which it points. In this case, *circle is a
value of type long. While this may be a subtle point to raise in this case, it starts to show its
worth when more complex types are used. This is the reason for C's slightly odd way of
declaring more complex types, when the name of the actual variable gets hidden within the type
declaration, as further examples will show. However, the standard also allows you to attach the
asterisk to the name of the type such as long* circle. This form is usually discouraged since it
can confuse the novice when multiple pointers are declared on the same line:
will result in first being a pointer to a long, but second being a long itself, which is likely not
what a beginner expects.
There is a special type of value which cannot be directly used as a variable type, but only as
pointed type in the case of pointer declarations.
void *triangle;
The pointed value here cannot be used directly; attempts to dereference this pointer will result in
a compiler error. The utility here is that this is a generic pointer; useful when the pointed type
does not matter, simply the pointer address is needed. It is usually used to store pointers in utility
types, such as linked lists, or hash tables, where the code using the utility will typecast it to a
pointer of some specific type (moreover, this casting may be implicit, meaning that the cast
operator isn't needed when the new type is obvious, for example in variable assignments).
The pointed type can take all of the usual markings given above; the following are all valid
pointer declarations.
Note specifically the use of const in this last case. Here, kite is a (non-const) pointer to a
const char. The value of kite itself is not a constant, only the value of the char to which it
points. The placement of const before the type, as noted above, gives motivation for the way a
constant pointer is declared. As it is constant, it must be initialised when it is declared.
Here, pentagon is a constant pointer, which points at a char. The value at which it points is not
a constant; it will not be an error to modify the pointed character; only to modify the pointer
itself. It is also possible to declare both the pointer and the pointed value as being constant. The
following two declarations are equivalent.
Because, for example, char * is itself a type, pointer variables can be declared which point at
values of such a type. These are pointers to pointers.
char **septagon;
As before, the usual type qualifiers and const marking can be applied.
This declares octagon as a pointer to a constant pointer to a constant unsigned long integer.
Pointer types can be arbitrarily nested below this, but with each level of indirection their use is
increasingly harder to think clearly about. Any code using more than two levels of pointer
probably requires a redesign, in terms of struct pointers, or the use of the typedef keyword.
[edit] Arrays
An array is a collection of values, all of the same type, stored contiguously in memory. In C,
arrays are implemented as pointers, with some syntactic sugar to simplify memory allocation.
Some C-like languages, such as Java or C#, separate their array declarations into a type followed
by a list of variable names. In these languages, an array of 10 integer values may be declared this
way:
However, as noted above, C's declaration syntax aims to make declarations resemble use.
Because an access into this array would look like cat[i], it is declared in a different syntax in C.
Since they are pointers, arrays can be nested. Because the array notation, using square brackets
([]), is a postfix notation, the size of the inner nested array types is given after the outer type.
double dog[5][12];
This declares that dog is an array containing 5 elements. Each element is an array of 12 double
values.
char *mice[10];
This declares mice to be a 10 element array, where each element is a pointer to a char.
As stated before, a bare array name (ie. without a subscription) is simply a pointer and can be
passed around as such:
double dbls[20];
...
myFunc(dbls);
...
To declare a variable as being a pointer to an array, we must make use of parentheses. This is
because in C brackets ([]) have higher precedence than the asterisk (*). So if we wish to declare a
pointer to an array, we need to supply parentheses to override this:
double (*elephant)[20];
This declares that elephant is a pointer, and the type it points at is an array of 20 double values.
int *(*crocodile)[15];
The square-bracket array subscription notation, such as my_array[5] can be thought of as "take
element number 5 from my_array", but it is also just as valid to think of this operation as
"dereference the pointer which is equal to 'my_array + 5'". In fact, the following is perfectly
valid code:
This shows how a pointer can be used as an array, although the memory allocation must be given
explicitly (and thus the memory must later be freed to prevent a memory leak). In a similar
fashion, dereferencing a pointer using *pointer_name can be done by asking for the "first
element of the array" (ie. treating a pointer as a 1-element array) like this pointer_name[0].
Both are valid, as long as C's precedence rules are followed.
[edit] Functions
A function is an example of a derived type. The type of each parameter to a function is ordinarily
specified, although strictly speaking it is not required for most functions. Specifying the name of
each parameter is optional in a function declaration without a function body. The following
declarations are equivalent:
While both forms are syntactically correct, it is usually considered bad form to omit the names of
the parameters when writing function declarations in header files. These names can provide
valuable clues to readers of such files, as to their meaning and operation.
Functions can take and return pointer types using the usual notation for a pointer:
The special type void is useful for declaring functions which do not take any parameters at all:
char *wicket(void);
This is quite different from the empty set of parentheses used in C to declare a function without
information on its parameter types:
double umpire();
This declaration declares a function called umpire which returns a double, but says nothing
about the parameters the function takes. (In C++, however, this declaration means that umpire
takes no parameters, the same as the declaration that uses void.)
In C, functions cannot directly take other functions as parameters, or return functions as results.
However, they can take or return pointers to them. To declare that a function takes a function
pointer as an argument, use the standard notation as given above:
Here, we have a function which takes two arguments. Its first argument, p1, is a plain char. Its
second argument, p2 is a pointer to a function. This pointed-to function should be given no
arguments, and will return an int.
As a special case, C implementations treat function parameters declared with a function type as
pointer-to-function types. Thus, the following declaration and the preceding declaration are
equivalent:
As there are two sets of argument lists, this declaration should be read carefully, as it is quite
subtle. Here, we are defining a function called boundary. This function takes two integer
parameters, height and width, and returns a function pointer. The returned pointer points at a
function that itself takes two integer parameters, x and y, and returns a long.
This type of marking can be arbitrarily extended, to make functions that return pointers to
functions that return pointers to functions, and so on, but it quickly gets very unreadable, and
prone to bugs. Use of a typedef improves readability, as shown by the following declarations
that are equivalent to the previous declaration:
[hide]
v • d • e
C programming language
LibrariesC standard library · glibc · dietlibc · uClibc · Newlib · EGLIBC
String · Syntax · Preprocessor · Variable types and declarations ·
Features
Functions
Select descendants C++ · C++0x · Objective-C · D · C# · Vala
C and other C and C++ (Compatibility · Operators) · Comparison of Pascal and
languages C · C to Java byte-code compiler
Category
Retrieved from "http://en.wikipedia.org/wiki/C_variable_types_and_declarations"
Categories: C programming language
Personal tools
New features
Log in / create account
Namespaces
Article
Discussion
Variants
Views
Read
Edit
View history
Actions
Search
Special:Search
Search
Navigation
Main page
Contents
Featured content
Current events
Random article
Interaction
About Wikipedia
Community portal
Recent changes
Contact Wikipedia
Donate to Wikipedia
Help
Toolbox
Print/export
Create a book
Download as PDF
Printable version
Languages
Tiếng Việt
Privacy policy
About Wikipedia
Disclaimers