Variables, types, and values
Starting out12 min readLesson 3 of 5
3.1 A variable is a named box
A variable is a name for a storage location that holds a value of one type. C is statically typed: the type is fixed when you declare the variable, and it decides how many bytes the location uses and how those bytes are read.
int count; reserves space and leaves the value undetermined. int count = 0; also stores a zero.
The value of an uninitialised local variable cannot be predicted. The location holds whatever bytes were already there, and reading it is undefined behaviour: the C standard gives no rule for the result, so the compiler may do anything. Initialise a local variable at the point where you declare it.
3.2 The basic types
intholds a whole number. Most desktop compilers give it 4 bytes, with a range of about 2.1 billion in each direction.charholds one byte, most often a character code such as'A'.floatholds a single-precision real number.doubleholds a double-precision real number and is the usual choice for decimals.unsigned intholds only non-negative values and can store about twice the largestint.bool, from<stdbool.h>, holdstrueorfalse. In C23 it is a keyword and the header is optional.
Use double for money in practice programs. float keeps about seven significant digits, and double keeps about fifteen, which is enough for prices printed with two decimals.
#include <stdio.h>
int main(void)
{
int small = 42;
double price = 19.99;
char grade = 'A';
printf("int: %d, %zu bytes\n", small, sizeof small);
printf("double: %.2f, %zu bytes\n", price, sizeof price);
printf("char: %c, %zu byte\n", grade, sizeof grade);
return 0;
}Output
int: 42, 4 bytes double: 19.99, 8 bytes char: A, 1 byte
3.3 Declaring and initialising
A name may contain letters, digits, and underscores, and it cannot start with a digit. Names are case sensitive, so Total and total are different variables. Keywords such as int, return, and while are reserved and cannot be used as names.
C99 and later allow a declaration in the middle of a block, close to the first use. C89 required every declaration at the top of the block, and older code still follows that layout.
const int limit = 100; marks a value that cannot be changed after initialisation. A constant declared this way behaves like a variable in every other respect; the compiler refuses only the assignment that would modify it.
#include <stdio.h>
int main(void)
{
const int limit = 5;
int a = 2, b = 3;
int total = a + b;
printf("a = %d, b = %d\n", a, b);
printf("total = %d, limit = %d\n", total, limit);
printf("a + b + limit = %d\n", total + limit);
return 0;
}Output
a = 2, b = 3 total = 5, limit = 5 a + b + limit = 10
3.4 Matching types to format specifiers
Each type needs a matching conversion specifier. printf does not convert an argument to the type named in the format string; it reads the argument according to the specifier.
int:%dunsigned int:%ulong:%ldlong long:%llddouble:%fchar:%csize_t:%zu
scanf needs the address of the variable and a matching specifier: scanf("%d", &count);. The & is the address-of operator, which the pointers lesson explains. For now, remember that printf receives values while scanf receives addresses.
A wrong specifier is not always caught at compile time. Pay attention to the warning format '%d' expects argument of type 'int', which GCC and Clang print when the types are obviously wrong.
#include <stdio.h>
int main(void)
{
int age = 0;
printf("Enter your age: ");
scanf("%d", &age); /* sample input: 14 */
printf("Next year you will be %d.\n", age + 1);
return 0;
}Output
Enter your age: Next year you will be 15.
3.5 Integer division and mixed arithmetic
Division depends on the types of its operands. 7 / 2 with two int values gives 3, because C discards the fraction. 7.0 / 2 gives 3.5, because the int operand is converted to double first.
- when both operands are integers,
/truncates toward zero %gives the remainder and accepts integers only- mixing
intanddoublepromotes theinttodouble - assigning a
doubleto aninttruncates the fraction - a cast such as
(double) totalconverts one operand before the operation happens
-Wconversion reports some accidental conversions. It is noisy on large programs and useful on small exercises.
#include <stdio.h>
int main(void)
{
int total = 7;
int parts = 2;
printf("Integer division: %d\n", total / parts);
printf("Remainder: %d\n", total % parts);
printf("Real division: %.1f\n", (double) total / parts);
return 0;
}Output
Integer division: 3 Remainder: 1 Real division: 3.5
3.6 Characters and small integers
char stores a character code. On an ASCII system, 'A' is 65, 'B' is 66, and 'a' is 97. Printing a char with %c shows the character, and printing it with %d shows the code.
'A' is a character constant. "A" is a string literal with two bytes: the character 'A' and the terminating '\0'. Mixing the two up produces a warning from most compilers and strange output from the program.
#include <stdio.h>
int main(void)
{
char letter = 'C';
printf("letter: %c\n", letter);
printf("code: %d\n", letter);
printf("next: %c\n", letter + 1);
return 0;
}Output
letter: C code: 67 next: D
