Variables and Data Types

Variable Declaration
<type> variable_name;
Variable assignment
Using the assignment operator (=
)
variable_name = <value>;
By default, if no values are assigned to the variable, the variable value is the old content of the address now associated to variable_name
.
The assignment is from right to left:
var1=var2=value;
Simple Data types
Integer
char
The values of the char type can vary from computer to computer (different machines may be based on a different character set).
The most widely used character set is ASCII (often extended to Latin-1 with characters from Western Europe and Africa).
signed char
8-bit integer
unsigned char
8-bit unsigned integer
int

The integer ranges are listed in the following MACROs of the library <limits.h>
:
INT_MIN
INT_MAX
LONG_MIN
LONG_MAX
Number formats: If you prepend the following simbols to the integers, you can specify the numbers in a different format:
O
Octal
0X
Hexadecimal
Enum
Declaration of the enum without its name definition:
enum {VALUE0, VALUE1, ...} var1, var2, ...;
It defines a set of variables
var1
,var2
,...
that can have one of the valuesVALUE0
,VALUE1
,...
For example:
enum { FALSE,TRUE } b1, b2 ;
Declaration and definition of the enum
enum NOME_ENUM{VALORE0, VALORE1, ...} ; enum NOME_ENUM var1, var2, ..;
For example:
enum Bool{ FALSE,TRUE } ; enum Bool b1, b2 ;
Type definition for the enum
typedef enum {VALORE0, VALORE1, ...}nome_Tipo ; nome_Tipo var1, var2, …;
For example:
typedef enum {FALSE,TRUE}Bool; Bool b1,b2;
Integer association
By default, the values in the enum are associated in order to the integers
0
,1
,2
,...
For example:
enum Bool{ FALSE,TRUE }; enum Bool b1, b2; b1 = FALSE; b2 = TRUE;
Hence, the values are:
b1 = 0; b2 = 1;
the integers associated to the enum values can be modified as follows:For example:
enum Bool{ FALSE=13,TRUE=3 }; enum Bool b1, b2; b1 = FALSE; b2 = TRUE;
Hence, the values are:
b1 = 13; b2 = 3;
Floating point
float
1.17 × 10⁻³⁸ ÷ 3.4 × 10³⁸
6 digits
double
2.2 × 10⁻³⁰⁸ ÷ 1.8 × 10³⁰⁸
15 digits
Type conversion
Implicit conversion
logical or arithmetic expression with expressions of different types
var_Float+var_Int
The
int
variable is converted tofloat
in the sum, because thefloat
has a broader range thanint
.assignment conversion of the variable in the RIGHT side is converted to the type of the variable in the LEFT side
parameter of a function the variable passed as a parameter is converted to the one required
return statement if the return value of a function is different from the required one, the value is automatically converted to the defined one
Explicit conversion
(data_type) expression
The expression is forcibly cast to data_type
Variable Dimension
It returns the size (number of bytes)
sizeof(data_type)
sizeof variable_name
Type definition
#define
directive
#define
directiveDefinition of the new type
#define new_type type
Definition of the possible values
#define value_name value
For example:
#define BOOL int
#define TRUE 1
#define FALSE 0
typedef
typedef
typedef type new_type;
It creates a new data type (new_type
), that it is always a type
variable.
typedef float Dollars;
Dollars cash_in, cash_out;
Advantages:
Portability
Documentation & readability
Aggregate variables
Vector (Array)
It contains elements of the same type.
type vector_name[constant_integer_expression];
type
: type of the elements contained in the arrayconstant_integer_expression
: number of elements in the array This is usually specified by:MACROs (recommended practice)
Magic numbers, i.e., values written directly in the declaration, large enough to ensure the array is never full
C99: Variable Length Array (VLA)
type vector_name[expression];
The length of the array is defined at runtime (usually, the number inside the square brackets is a variable that is later provided as input).
Indexing operator (subscripting)
vector_name[i]
For example:
examples[3] = 2;
Sequential continuity
The elements of the array are stored sequentially in memory.
Note: C does not check array indices during read or write operations to be FASTER (to avoid wasting clock cycles).
If you write to an array using an invalid index, you might overwrite other data in memory.
type a[N];

Array size
sizeof(a)/sizeof(a[0])
sizeof(a)
– size in bytes of the array asizeof(a[0])
– size in bytes of the first element (i.e., the size of the element type)
Initialization
Explicit initialization of all elements
int a[10] = {1,2,3,…,10};
Explicit initialization of the first 3 elements and implicit initialization of the remaining elements to 0
int a[10] = {1,2,3};
Automatic assignment of the array length (# of initialized elements)
int a[] = {1,2,3,…,10};
C99:
int a[10] = {[1]=3,[5]=12};
Designators allow you to initialize specific elements or fields of arrays and structs by name or index, improving clarity and flexibility.
Management of Partially Filled Arrays
Arrays are usually created with larger sizes because continuous allocations would require more intervention from the operating system.
Resizing due to the insertion of a new element
If the space occupied by the array is full, a new memory area must be allocated using realloc():
If there is contiguous space after the array, the pointer to the same memory area is returned.
Otherwise, a copy of the array is made to a new memory area, and only then is the new element added.
Usually, very large arrays are defined to minimize the number of reallocations, and therefore reduce requests to the operating system.
Removing an element from the array without wasting memory
Structures
The components are called fields (members in C terminology)
The components can be simple types or other data structures
The components are defined by names, and you access them via these names (not by position as with arrays)
Declaration of a structure
You can declare it in a .h file, but I need to use macros to avoid multiple declarations, because a struct can only be declared once.
First method
struct structure_tag
{
field_type1 field_name1 ;
field_type2 field_name2 ;
…
};
In memory, the structure members are allocated contiguously in the same order they are declared.

Depending on the architecture, there may be gaps between fields to ensure memory alignment.
Padding If a field occupies less than the number of bits in which the architecture organizes memory (e.g., 32-bit or 64-bit), and the next field doesn’t fit in the remaining space, the compiler inserts uninitialized gaps between fields for alignment purposes.
These padding areas are sometimes called "dirty" memory from previous usage.
Padding bytes are not addressable — you can't access or use them directly.
For example:
struct test
{
short s;
int i;
};

Second method
Declaration of a new data type (new_type_name
):
typedef struct structure_tag
{
field_type1 field_name1 ;
field_type2 field_name2 ;
…
}new_type_name;
Declaration of a struct variable
First method:
struct structure_tag variable_name;
Second method:
new_type_name variable_name;
Access to the structure fields
variable_name.field_name
Example:
struct test t;
t.s = 10;
t.i = -15;

Initialization of the structure
First method
Each field that is not explicitly initialized is zeroed out bit by bit by the compiler.
List of fields separated by commas (traditional syntax)
struct structure_tag variable_name = {value1, value2, ...};
Field declarations using colons (Not Standard - GCC syntax before standardization)
struct structure_tag variable_name = {fieldName1:value1, ...};
Assignment using field names - designated initializers (C99 standard syntax, also supported by GCC)
struct structure_tag variable_name = {.fieldName1:value1, ...};
Examples:
struct item {int id; char name[20]; int value; int priv;};
Traditional syntax
struct item i1 = {3, "John", 45};
Not standard
struct item i2 = {id: 3, name: "John", value: 45};
C99 syntax
struct item i3 = {.id = 3, .name = "John", .value = 45};
Second method
new_type_name variable_name = {value1,value2,...};
Example:
typedef struct test {short s; int i;} test_t;
test_t t = {10, -15};
Assignment of the variable
variable_name1 = variable_name2;
A deep copy of the fields of variable_name2 is made into the fields of variable_name1 (if both are struct variables).
Comparison between structure variables
You cannot directly compare two structure variables in C (e.g., using the ==
operator).
If there is padding within the structure, the two variables will never be equal, even if the fields are the same. This is because the padding bytes are not initialized and can affect the overall memory representation of the struct.
Example:
struct test {short s; int i;} t1, t2;
t1 == t2
➡️ NO (due to padding)t1.s == t2.s && t1.i == t2.i
➡️ YES
Pointers to structures
Declaration of the pointer:
struct structure_tag *pointer_name;
Access to the structure fields:
(*pointer_name).field_name
pointer_name->field_name
Bit fields
A group of bits organized into fields.
Useful for making better use of hardware on systems with limited memory
You can define data types with sizes smaller than the smallest standard data type (usually char), by using bit fields.
Bit field declaration
struct structure_tag
{
unsigned field_name1:bit_size1;
unsigned field_name2:bit_size2;
…
}
Each field specifies the number of bits (bit_size
) that make up the field
A field can also be:
Anonymous (without
field_name
and:
) used for padding ofnumber_bit
bits (cannot be used to store values)Anonymous with zero size (without
field_name
and:
, but with size 0) forces the alignment of the following field to the next memory boundary (padding)
Example:
Union
Aggregate data type that can contain multiple fields as alternatives.
Declaration
In memory, space is allocated for the largest field
It is a kind of “variant record” where the fields overlap in memory, so only one is valid at a given time
First method
union union_tag
{
field_type1 field_name1;
field_type2 field_name2;
…
}
Example:
union datum
{
int i;
double d;
};

Second method
typedef union union_tag
{
field_type1 field_name1;
field_type2 field_name2;
…
} new_type_name;
Example:
typedef union datum
{
int i;
double d;
} datum_t;

Declaration of a struct variable
First method
union union_tag variable_name;
Second method
type_name variable_name;
Access to the union fields
variable_name.field_name
You can access a union member only if the last assignment to the union was made through that member. (C provides no way to determine which member of a union was last assigned)
Last updated