In C, there is a small key set of types. The rest are variations, modifiers, arrays and other such low-level data structures. The keywords for these types are int, char and float.
Types in C
When we wish to store an integer, we use an integer type, usually int. ints have at least 16 bits. Many platforms have 32-bit ints. There is also long int, which is guaranteed to have at least 32 bits. short ints have at most 16 bits, just like regular ints. However, often int is made to be longer, so short int is used when conserving memory is important.
All these integer types are signed, meaning that they can hold both positive and negative values. There is an corresponding unsigned type that only holds nonnegative values. However, they can hold larger values in the same number of bits. Using the keyword unsigned yields an unsigned type. For example, unsigned int is a unsigned integer type of at least 16 bits. The keyword signed can also be used, but is redundant.
When conserving memory is even more important, we can pack an assortment of 1-bit, 2-bit, and 3-bit values into a structure using bit_fields. (Or we can use the bit-manipulation instructions to manually pack and unpack bit fields from a standard "char" or "int".)
When we wish to store a single character or byte, we use a character type. The C name for this type is called char. chars always use one byte each. char can also be used to store integers small enough to fit in a byte.
Since char is an integer type, it is important to know whether it is signed or unsigned. However, compilers are allowed to make them either. If you want to guarantee that your character variable is signed or unsigned, use the type signed char or unsigned char. Unlike char, these types are guaranteed to be either signed or unsigned, according to their names.
char arrays are often used to store human readable strings of alphabetic language like English; a common use is the filename, the user login name, and the password. char arrays are often used to store user input, which may need to be manipulated : the common expectation is that a character string ends with a null character which has a value of 0 or zero. Because arrays are either defined dynamically using malloc() , or more conveniently, in scope on the stack , with something like
where maxbuf is a constant or define of say, 512, a string of say 522 characters ending with a zero character on the 523rd character can write into 523-512=11 characters following the space allowed for buff on the stack, and if the stack grows backwards, so that before buff was allocated the program counter that stored the current address of the program before the function was called was pushed onto the stack, and this was going to be used at the end of the function to return to the instruction following the call to the function, an attacker could change the return address to a loader code within buff to load a malicious program and run it. This buffer overrun attack can usually be avoided if functions which copy buffers without a length limitation such as strcpy are replaced by functions which specify maximum buffer length like snprintf() , or any use of strcpy is preceded by a length check with strlen(), and strcpy not called if the length is greater than the allocated space minus 1 (for the null character to be stored ).
When we wish to store a floating-point (non-integer) value, we can use the types float, double, and long double. These differ only in the precision and range that they provide. A float generally has 32 bits and a double 64. long double might be bigger, but it could just be the same as double.
There is a special type called void. You are not allowed to have variables of type void. There are various uses of void, one of which is as a return type for functions that don't need to return an actual value. void did not exist before it was introduced in the 1989 ANSI C standard. However, there should be no need to worry about its not being available unless you use a really old compiler (in which case, upgrade).
There is no fundamental predefined string type in C. Strings in C are more complicated (they are arrays of chars), requiring manual handling, and we will deal with them later.
All type declarations using the above simple types follow a standard format
- type_name variable_name;
where type_name represents one of the C type names, and variable_name would be replaced by the programmer with a name for the variable. According to the C standards there are a few restrictions on variable names. A variable name:
- must be at least one character long
- must be less than some maximum character length. 32 on some systems, 256 on others, and probably everything in between on yet others.
- must start with a letter
- must be composed of letters, numbers and/or the underscore character
- must not contain spaces
- must not be equal to reserved words such as "int", "char", "float", et cetera. Any keyword used for the C language itself is off-limits.
- is case sensitive. This means that "NUMBER", "number", "Number", "numbeR", and "NuMbEr" are all different variables.
For example, if we want to declare a variable called number and of type int, we write
- int number;
In C, all declarations are terminated by semicolons just as if they were statements. If we wish to declare a number of variables of the same type, we can write a comma separated list of variable names after the type. For example:
- int variable1, variable2, variable3;
which declares all variable1, variable2, and variable3 to be of type integer.
Some C programmers use
enum to declare an enumerated type.
These enumerated types are useful when we build switch case statements.
Back to contents: C programming