Your first C program proves the toolchain works and introduces the minimal structure every C program shares.

Minimal Program

  #include <stdio.h>

int main(void) {
    printf("Hello, World!\n");
    return 0;
}
  

Save as hello.c. Every C program needs exactly one main function.

Compilation Steps

  # Preprocess only (see expanded source)
gcc -E hello.c -o hello.i

# Compile to assembly
gcc -S hello.c -o hello.s

# Assemble and link
gcc -c hello.c -o hello.o
gcc hello.o -o hello

# One-step build
gcc -std=c17 -Wall -Wextra hello.c -o hello
./hello
  

Return Codes

  #include <stdlib.h>
int main(void) {
    /* 0 = success, non-zero = error */
    return EXIT_SUCCESS;
}
  

Shell scripts check $? after your program exits.

Formatted Output

  #include <stdio.h>
int main(void) {
    char name[] = "Alice";
    int age = 30;
    printf("Name: %s, Age: %d\n", name, age);
    printf("Pi ≈ %.2f\n", 3.14159);
    return 0;
}
  

Common specifiers: %d int, %u unsigned, %ld long, %f float, %s string, %p pointer, %zu size_t.

Comments and Style

  /* Block comment — traditional C style */

// Line comment — C99 and later

/* K&R brace style (common in C):
 * if (x) {
 *     do_something();
 * }
 */
  

Common Pitfalls

  • Treating compiler warnings as optional rather than actionable feedback.
  • Skipping error checks on library and system calls.
  • Copy-pasting examples without adapting to your project’s conventions.

Best Practices

  • Enable strict compiler warnings and fix them before merging.
  • Write small, testable units with clear input/output contracts.
  • Document non-obvious invariants and preconditions.
  • Use version control and code review for every change.

Memory and Performance Notes

Each printf call has overhead. For high-throughput logging, consider write(2) or buffered I/O.

Exercise

Modify hello.c to print a formatted table of ASCII codes 32–126 (printable characters). Use a loop.

Hint: Use %c to print a character from an integer code.

Summary

Apply these concepts in small programs before moving to larger projects. Combine with adjacent topics in the learning path for deeper mastery.

Real-World Application

These concepts appear in production codebases — from operating system kernels to embedded firmware. Study open-source projects that use this topic extensively to see idiomatic patterns at scale.

Debugging Checklist

  1. Reproduce the issue with the smallest possible input.
  2. Enable compiler warnings and sanitizers.
  3. Use a debugger to inspect state at the failure point.
  4. Verify assumptions about types, sizes, and return values.
  5. Compare working and broken code paths side by side.
  6. Write a regression test once the bug is fixed.

Further Reading

Consult the ISO C standard, Effective C by Robert C. Seacord, and your compiler documentation for platform-specific behavior.

Quick Reference

Review the code examples on this page before starting the exercise. Type them manually to build muscle memory.

Additional Examples

Consider how this topic applies in a larger project:

  // Break the problem into smaller functions
// Test each function independently
// Integrate incrementally
  

Working through variations of the examples above builds deeper understanding than reading alone.