thecodingidiot.com

Writing CVariables and Types

Variables and Types

A variable is a named location in memory. A type tells the compiler how much memory to allocate and how to interpret the bits stored there.

The basic types

int    n = 123;      /* integer: typically 4 bytes, range ±2 billion  */
char   c = 'A';      /* character: 1 byte, stores a small integer     */
float  x = 3.14f;    /* floating-point: 4 bytes, approximate          */
double d = 3.14159;  /* double-precision float: 8 bytes               */

int is the type you will use most. char stores a single character but is also a small integer — 'A' is the integer 65, the ASCII code for the letter A. float and double store real numbers approximately; they cannot represent most decimal values exactly.

Check the size of any type with sizeof:

#include <stdio.h>
 
int main(void)
{
    printf("int:    %zu bytes\n", sizeof(int));
    printf("char:   %zu bytes\n", sizeof(char));
    printf("float:  %zu bytes\n", sizeof(float));
    printf("double: %zu bytes\n", sizeof(double));
    return (0);
}

%zu is the format specifier for size_t, the type sizeof returns.


Printf format specifiers

printf does not know what type you are passing — you tell it with a format specifier in the string:

SpecifierTypeExample
%dintprintf("%d", 123)
%ccharprintf("%c", 'A')
%ffloat, doubleprintf("%f", 3.14)
%.2ffloat, doubleprintf("%.2f", 3.14)
%sstring literalprintf("%s", "hi")
%zusize_tprintf("%zu", sizeof(int))

Passing the wrong type for a specifier is undefined behaviour. The compiler will warn you with -Wall if it can catch it.


Arithmetic

int a = 10;
int b = 3;
 
printf("%d\n", a + b);   /* 13 */
printf("%d\n", a - b);   /* 7  */
printf("%d\n", a * b);   /* 30 */
printf("%d\n", a / b);   /* 3  — integer division truncates */
printf("%d\n", a % b);   /* 1  — remainder                  */

Integer division truncates toward zero: 10 / 3 is 3, not 3.333. The remainder operator % gives the leftover: 10 % 3 is 1.

If you need the decimal result, use float or double — which one depends on the precision you need. Precision is the number of significant digits a value carries. float gives you roughly 6–7; double gives you 15–16. For most programs double is the right default: it is no slower on modern hardware and rounding errors are less likely to accumulate over long calculations.

float  a = 10.0f;
double b = 10.0;
printf("float:  %.10f\n", a / 3.0f);   /* 3.3333332539 — imprecise */
printf("double: %.10f\n", b / 3.0);    /* 3.3333333333 — closer    */

The calculator skeleton

This is the data layer of calculator.c. Two numbers, four operations, all results printed. No user input yet — that comes in the next page.

#include <stdio.h>
 
int main(void)
{
    int a;
    int b;
 
    a = 10;
    b = 3;
    printf("%d + %d = %d\n", a, b, a + b);   /* addition       */
    printf("%d - %d = %d\n", a, b, a - b);   /* subtraction    */
    printf("%d * %d = %d\n", a, b, a * b);   /* multiplication */
    printf("%d / %d = %d\n", a, b, a / b);   /* division       */
    printf("%d %% %d = %d\n", a, b, a % b);  /* remainder      */
    return (0);
}

%% in a format string prints a literal % — the % character is the escape character for format specifiers, so it must be doubled to print it.

Compile and run it. Change a and b. Observe what integer division does with 7 / 2, 1 / 3, -7 / 2.

The next page adds control flow: reading the operator from the user and choosing which operation to perform.