C Introduction

C is a general-purpose programming language used to write fast, portable programs that run close to the hardware. It matters because operating systems, embedded devices, databases, language runtimes, game engines, and performance-critical tools still rely on ideas that C made practical.

Learning C teaches you how programs really execute: how source code becomes machine instructions, how values live in memory, and why small details such as types and function signatures matter. This first lesson gives you the mental model you need before writing larger C programs.

Overview: How C Works

A C program begins as plain text in one or more source files, usually with the extension .c. A compiler reads that text, checks whether it follows the C language rules, translates it into object code for a particular machine, and then a linker combines that object code with library code to produce an executable program.

This makes C different from languages that are usually interpreted line by line. In C, many mistakes are caught before the program runs, but the compiled program itself normally runs directly as native machine code. That is one reason C programs can be small and fast.

C is also deliberately low-level. When you create an int, a double, an array, or a pointer, you are working with values that occupy real bytes in memory. The language does not automatically protect you from every mistake: using the wrong format specifier, reading outside an array, or using an invalid pointer can produce wrong results or undefined behavior. That responsibility is part of C’s power and part of why careful habits matter.

A typical C program has a function named main. When the operating system starts your program, control enters main. The statements inside main run in order unless control-flow statements such as if, loops, or function calls change that order. Returning 0 from main conventionally tells the operating system that the program succeeded.

Syntax

The smallest useful shape of a C program looks like this:

#include <stdio.h>

int main(void) {
    return 0;
}
  • #include <stdio.h> asks the preprocessor to include declarations from the standard input/output header.
  • int main(void) defines the program’s entry point. The int return type means the function returns an integer status code.
  • The braces { and } group the body of the function.
  • return 0; ends main and reports successful completion.
  • Most C statements end with a semicolon. Forgetting one is one of the first syntax errors beginners meet.
Term Meaning
Source file A text file containing C code, commonly named with .c.
Compiler The tool that translates C source into machine-specific object code.
Linker The tool that combines object code and libraries into an executable.
Header A file that provides declarations, such as printf from stdio.h.
Executable The program file the operating system can run.

Examples

A first visible program

#include <stdio.h>

int main(void) {
    printf("C is running.\n");
    printf("One source file became a program.\n");
    return 0;
}

Output:

C is running.
One source file became a program.

This program includes stdio.h so it can call printf. The \n sequence prints a newline, so the second message starts on the next line. The source code is text, but after compilation and linking it becomes a native program that prints these exact characters.

Using variables and arithmetic

#include <stdio.h>

int main(void) {
    int apples = 12;
    int box_size = 5;

    printf("Apples: %d\n", apples);
    printf("Boxes of 5: %d\n", apples / box_size);
    printf("Left over: %d\n", apples % box_size);

    return 0;
}

Output:

Apples: 12
Boxes of 5: 2
Left over: 2

Here, apples and box_size are integer variables. The division operator / performs integer division because both operands are integers, so 12 / 5 gives 2, not 2.4. The remainder operator % gives the leftover amount.

Defining and calling a function

#include <stdio.h>

double celsius_to_fahrenheit(double celsius) {
    return celsius * 9.0 / 5.0 + 32.0;
}

int main(void) {
    double morning = 21.5;
    double converted = celsius_to_fahrenheit(morning);

    printf("%.1f C is %.1f F\n", morning, converted);
    return 0;
}

Output:

21.5 C is 70.7 F

This example separates a calculation into its own function. The function receives a double, computes a new double, and returns it. The %.1f format tells printf to display each floating-point value with one digit after the decimal point.

How It Works Step by Step

  1. The preprocessor handles lines beginning with #, such as #include <stdio.h>. It effectively makes declarations available before the compiler checks calls such as printf.
  2. The compiler parses the C code, checks types, and translates each function into lower-level instructions for the target CPU.
  3. The assembler and linker produce the final executable. The linker resolves references to library functions, including standard library functions used by your program.
  4. When you run the executable, the operating system loads it into memory and calls startup code that eventually invokes main.
  5. Local variables such as apples or morning are created for the function call. Their bytes store the current values until the function returns.
  6. When main returns, the program’s exit status is passed back to the operating system.

This pipeline explains why C error messages often mention phases such as compilation or linking. A syntax error is found while compiling. A missing function definition may be found while linking. A logic error can still happen after the program successfully builds.

Common Mistakes

Forgetting that declarations matter

C needs to know about functions before you call them. If you call printf without including stdio.h, a modern compiler should warn or fail because it does not have the proper declaration. The corrected form includes the header:

#include <stdio.h>

int main(void) {
    printf("Headers provide function declarations.\n");
    return 0;
}

Output:

Headers provide function declarations.

Using the wrong format specifier

printf does not automatically inspect the types of its extra arguments at runtime. The format string must match the values you pass. Use %d for int and %f for double:

#include <stdio.h>

int main(void) {
    int age = 30;
    double height = 1.75;

    printf("Age: %d\n", age);
    printf("Height: %.2f m\n", height);

    return 0;
}

Output:

Age: 30
Height: 1.75 m

A mismatched format specifier is especially dangerous in C because it can lead to undefined behavior. Compiling with warnings enabled helps catch many of these mistakes before you run the program.

Best Practices

  • Compile early and often. A small error is easier to find when you added only a few lines since the last successful build.
  • Enable warnings, for example with -Wall -Wextra when using GCC or Clang.
  • Use int main(void) for programs that take no command-line arguments.
  • Include the correct headers for every standard library function you call.
  • Keep examples and functions small while learning; C rewards precise reasoning.
  • Read compiler messages from top to bottom. The first reported error is often the real cause.
  • Prefer clear names such as box_size over single-letter names except for very small loop counters.
  • Remember that C gives you control over memory, but it also expects you to respect array bounds, object lifetimes, and correct types.

Practice Exercises

  1. Write a program that prints your name on one line and the phrase I am learning C. on the next line.
  2. Create two int variables named width and height, then print the area of a rectangle.
  3. Write a function named minutes_to_seconds that accepts an integer number of minutes and returns the number of seconds. Call it from main and print the result.

Summary

  • C is a compiled, general-purpose language used heavily in systems and performance-sensitive software.
  • A C program is written as source code, compiled to object code, linked with libraries, and run as an executable.
  • main is the entry point of a hosted C program, and returning 0 indicates success.
  • Headers such as stdio.h provide declarations for standard library functions.
  • C exposes details such as types, memory, and object lifetimes, so careful code and compiler warnings are essential.