Chapter 03 of 24
3. Values, types, and variables
From a value to a variable
A value is information such as the number 12 or the character 'A'. A type tells C what kind of information a value represents and which operations make sense for it. A variable is a named place in which your program can store a value while it runs.
- Choose a type that matches the information, such as
intfor a whole-number count. - Give the storage a name and an initial value:
int count = 12;. - Use the name in an expression, and assign a new value when the program needs to update it.
Initializing a variable gives it a known starting value; reading an uninitialized local variable is not a safe way to get a meaningful result. Later sections explain type ranges, conversions, and formatting.
A variable is a named object that stores a value. Its type determines what
kind of value it can hold and how operations on it behave.
#include <stdbool.h>
int age = 20;
double temperature = 21.5;
char initial = 'A';
bool is_ready = true;
Common types
char: a small integer type, commonly used for character codes and bytes.int: an integer type.float,double,long double: floating-point types with increasing
minimum precision._Bool: the built-in Boolean type; include<stdbool.h>to usebool,
true, andfalsein C17.void: no value; also used to say a function accepts no parameters.
Integer types also include short, long, long long, and their unsigned
forms. Exact widths are not identical on every platform. Use types from
<stdint.h> such as int32_t when an exact-width type is available and
required.
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
int main(void)
{
int temperature = -3;
unsigned int flags = 0u;
double distance = 12.5;
char initial = 'M';
bool ready = true;
size_t count = 4;
int32_t protocol_value = 1200;
return (temperature < 0 && ready && count != 0 &&
flags == 0u && initial == 'M' && protocol_value == 1200 &&
distance == 12.5)
? 0
: 1;
}
Use signed types for values that can be negative, unsigned types for
well-defined nonnegative domains such as bit masks, and size_t for sizes.
Do not assume int32_t exists on every implementation; exact-width typedefs
are provided only when the implementation supports them.
Initialization and constants
Initialize local variables before reading them:
int main(void)
{
int count = 0;
const double tax_rate = 0.08;
return count == 0 && tax_rate > 0.0 ? 0 : 1;
}
const prevents modification through that name. It does not necessarily mean
the object is a compile-time constant in every context.
Conversions
Assignments and expressions can convert between types. Some conversions lose
information. For example, converting a floating-point number to an integer
discards the fractional part. Integer division also discards the remainder:
7 / 2 is 3, while 7.0 / 2.0 is 3.5.
Use explicit casts only when the conversion is intentional:
#include <stdio.h>
int main(void)
{
int total = 7;
int count = 2;
double average = (double)total / count;
return average == 3.5 ? 0 : 1;
}
Formatting values
printf uses format specifiers, and the specifier must match the argument's
type. Examples include %d for int, %f for double, %c for a character,
and %s for a null-terminated string. For fixed-width integer types, use the
macros in <inttypes.h>. A mismatched format specifier can cause undefined
behavior.
#include <stdio.h>
int main(void)
{
int count = 3;
double average = 7.5;
char grade = 'A';
const char *label = "score";
printf("%s: count=%d, average=%.1f, grade=%c\n",
label, count, average, grade);
return 0;
}
The conversion specifiers correspond to the argument types and order. The
precision in %.1f prints one digit after the decimal point.
Choosing and using a type
Use an integer type for counts and whole-number quantities, a floating-point
type for approximate real-number calculations, and a character type for a
single character code or byte. sizeof(type) reports storage size in bytes
for the current implementation; it is not a promise that a type has the same
size everywhere. <limits.h> and <float.h> describe implementation limits.
An object should be initialized before its value is read. A declaration such
as int total; reserves an object but does not give an automatic local
variable a useful initial value. Reading its indeterminate value is a bug.
Initialization can happen when declaring it or later through a definite
assignment before every possible read.
Floating-point values are approximations. A decimal such as 0.1 may not be
represented exactly in binary, so comparing calculated floating-point values
with == is often the wrong test. For measured quantities, compare whether
the difference is within an appropriate tolerance. For money, consider
storing the smallest whole unit (such as cents) when that fits the problem.
When converting values, decide what should happen to a fractional part or an
out-of-range value. A cast does not validate input; it only requests a
conversion. For example, validate a value before converting it to a smaller
integer type. Avoid integer division when a fractional answer is required:
make at least one operand floating point before division.
#include <stdbool.h>
#include <limits.h>
bool can_store_as_short(int value)
{
return value >= SHRT_MIN && value <= SHRT_MAX;
}
Use this kind of range check before a narrowing conversion; do not assume a
cast clamps an out-of-range value to the destination's minimum or maximum.
A worked calculation
Suppose total stores an integer sum and count stores the number of items.
This computes an integer average:
int main(void)
{
int total = 7;
int count = 2;
int average = total / count;
return average == 3 ? 0 : 1;
}
If total is 7 and count is 2, the result is 3 because both operands are
integers. To preserve the fraction, convert before dividing:
int main(void)
{
int total = 7;
int count = 2;
double average = (double)total / count;
return average == 3.5 ? 0 : 1;
}
The divisor must still be nonzero. A robust program checks that condition
before the calculation.
Checkpoint: Explain why 7 / 2 differs from 7.0 / 2.0, and why
initializing a variable to zero is different from merely declaring it.
Exercises: convert Celsius to Fahrenheit; calculate the area of a
rectangle; print an integer, a decimal, and a character with appropriate
format specifiers.