Skip to content

Learn Operating Systems

Open Source Operating Systems and Development

  • Home
  • About
  • Privacy Policy

Learn Just Enough C for Linux Programming

Posted on June 19, 2026 By ron No Comments on Learn Just Enough C for Linux Programming
programming

If your goal is to learn Linux system programming, operating systems, networking, or kernel concepts, you do not need to master all of C first. You need a solid understanding of variables, loops, functions, arrays, pointers, and structs. This tutorial covers the essentials.

Your First C Program

Every C program starts execution in the main() function.

#include <stdio.h>

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

Compile it:

gcc hello.c -o hello

Run it:

./hello

Output:

Hello, World!

The #include line loads the standard input/output library. The printf() function prints text to the screen. The return 0 statement tells the operating system the program completed successfully.


Variables

Variables store data.

#include <stdio.h>

int main()
{
    int age = 55;
    float height = 5.9;
    char grade = 'A';

    printf("Age: %d\n", age);
    printf("Height: %.1f\n", height);
    printf("Grade: %c\n", grade);

    return 0;
}

Common data types include:

int – Whole numbers
float – Decimal numbers
double – Larger decimal numbers
char – Single characters

Examples:

int count = 10;
float pi = 3.14;
double balance = 1000.25;
char letter = 'R';

Making Decisions with if Statements

Programs often need to make decisions.

#include <stdio.h>

int main()
{
    int age = 20;

    if (age >= 18)
    {
        printf("Adult\n");
    }
    else
    {
        printf("Minor\n");
    }

    return 0;
}

Comparison operators:

== Equal to
!= Not equal to

Greater than
< Less than
= Greater than or equal
<= Less than or equal


Loops

Loops repeat code.

While Loop

#include <stdio.h>

int main()
{
    int i = 1;

    while (i <= 5)
    {
        printf("%d\n", i);
        i++;
    }

    return 0;
}

Output:

1
2
3
4
5

For Loop

The for loop is one of the most common loops in Linux source code.

#include <stdio.h>

int main()
{
    for (int i = 1; i <= 5; i++)
    {
        printf("%d\n", i);
    }

    return 0;
}

Output:

1
2
3
4
5


Functions

Functions allow you to organize and reuse code.

Simple Function

#include <stdio.h>

void sayHello()
{
    printf("Hello\n");
}

int main()
{
    sayHello();
    return 0;
}

Function with Parameters

#include <stdio.h>

void greet(char name[])
{
    printf("Hello %s\n", name);
}

int main()
{
    greet("Ron");
    return 0;
}

Output:

Hello Ron

Function Returning a Value

#include <stdio.h>

int add(int a, int b)
{
    return a + b;
}

int main()
{
    int result = add(5, 3);

    printf("%d\n", result);

    return 0;
}

Output:

8


Arrays

An array stores multiple values of the same type.

#include <stdio.h>

int main()
{
    int numbers[5] = {10, 20, 30, 40, 50};

    printf("%d\n", numbers[0]);
    printf("%d\n", numbers[4]);

    return 0;
}

Output:

10
50

Array indexes begin at zero.

Looping Through an Array

#include <stdio.h>

int main()
{
    int numbers[5] = {10, 20, 30, 40, 50};

    for (int i = 0; i < 5; i++)
    {
        printf("%d\n", numbers[i]);
    }

    return 0;
}

Strings

A string is simply an array of characters.

char name[] = "Linux";

Internally, C stores:

L i n u x \0

The \0 character marks the end of the string.

Example:

#include <stdio.h>

int main()
{
    char name[] = "Linux";

    printf("%s\n", name);

    return 0;
}

Understanding Pointers

Pointers are one of the most important concepts in C and Linux programming.

A pointer stores a memory address.

int age = 55;
int *ptr = &age;

Think of it this way:

age contains the value 55.

ptr contains the address where age is stored.

Viewing the Address

#include <stdio.h>

int main()
{
    int age = 55;

    int *ptr = &age;

    printf("%p\n", ptr);

    return 0;
}

Example output:

0x7ffe12345678

The exact address changes every run.

Dereferencing

The * operator retrieves the value stored at the address.

#include <stdio.h>

int main()
{
    int age = 55;

    int *ptr = &age;

    printf("%d\n", *ptr);

    return 0;
}

Output:

55

Remember:

ptr = address

*ptr = value at that address


Why Pointers Matter

Without pointers:

void changeValue(int x)
{
    x = 100;
}
int age = 55;

changeValue(age);

age remains 55 because only a copy was passed.

Using pointers:

void changeValue(int *x)
{
    *x = 100;
}
int age = 55;

changeValue(&age);

printf("%d\n", age);

Output:

100

This technique is heavily used throughout Linux programming.


Arrays vs Pointers

This topic confuses many beginners.

Consider:

int numbers[3] = {10, 20, 30};

The array name acts like a pointer to the first element.

numbers

is essentially:

&numbers[0]

These two statements are equivalent:

printf("%d\n", numbers[0]);
printf("%d\n", *numbers);

Output:

10

Pointer Arithmetic

printf("%d\n", *(numbers + 1));

Output:

20

The expression numbers + 1 means:

Move to the next integer in memory.

A useful rule:

numbers[2]

is equivalent to:

*(numbers + 2)

You will encounter this style often when reading Linux source code.


Structs

Structs allow multiple pieces of data to be grouped together.

Example:

struct Employee
{
    char name[50];
    int age;
};

Creating a struct:

#include <stdio.h>

struct Employee
{
    char name[50];
    int age;
};

int main()
{
    struct Employee emp;

    emp.age = 55;

    printf("%d\n", emp.age);

    return 0;
}

Output:

55


Pointers to Structs

Linux code frequently uses pointers to structs.

struct Employee emp;
struct Employee *ptr = &emp;

Accessing fields:

(*ptr).age

More commonly:

ptr->age

Example:

#include <stdio.h>

struct Employee
{
    int age;
};

int main()
{
    struct Employee emp;
    emp.age = 55;

    struct Employee *ptr = &emp;

    printf("%d\n", ptr->age);

    return 0;
}

Output:

55


Dynamic Memory Allocation

Sometimes you need memory while the program is running.

#include <stdlib.h>

int *numbers;

numbers = malloc(5 * sizeof(int));

When finished:

free(numbers);

Failing to free memory causes a memory leak.


What to Learn Next

Once you are comfortable with:

  • Variables
  • if statements
  • Loops
  • Functions
  • Arrays
  • Strings
  • Pointers
  • Arrays vs pointers
  • Structs
  • Struct pointers
  • malloc() and free()

you are ready to begin Linux system programming.

The next topics to study are:

  1. Command-line arguments (argc and argv)
  2. File I/O (open, read, write, close)
  3. Processes and fork()
  4. Signals
  5. Pipes
  6. Threads
  7. Sockets and TCP/IP networking

At that point, books such as Beginning Linux Programming and Advanced Linux Programming will make much more sense, and you’ll be able to read real Linux source code examples without getting lost in the C syntax.

C for Linux Programming: The Next 7 Topics

Once you understand variables, loops, functions, arrays, pointers, and structs, you’re ready to learn the C concepts that appear throughout Linux programming books and system administration tools.

These topics form the bridge between learning C and learning Linux system programming.


1. Command-Line Arguments (argc and argv)

Most Linux programs accept arguments from the command line.

For example:

./program hello world

The program receives:

hello
world

through argc and argv.

Example

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("Argument count: %d\n", argc);

    for (int i = 0; i < argc; i++)
    {
        printf("argv[%d] = %s\n", i, argv[i]);
    }

    return 0;
}

Compile:

gcc args.c -o args

Run:

./args apple banana orange

Output:

Argument count: 4
argv[0] = ./args
argv[1] = apple
argv[2] = banana
argv[3] = orange

Important:

argc = argument count

argv = argument vector (array of strings)

argv[0] is always the program name.

Linux utilities such as ls, cp, grep, cat, and ps all use command-line arguments.


2. File I/O

Programs often need to read and write files.

Opening a File

FILE *fp;

fp = fopen("data.txt", "r");

The “r” means read mode.

Other modes:

r  Read
w  Write
a  Append

Reading a File

#include <stdio.h>

int main()
{
    FILE *fp;
    char line[100];

    fp = fopen("data.txt", "r");

    if (fp == NULL)
    {
        printf("Cannot open file\n");
        return 1;
    }

    while (fgets(line, sizeof(line), fp))
    {
        printf("%s", line);
    }

    fclose(fp);

    return 0;
}

Writing a File

#include <stdio.h>

int main()
{
    FILE *fp;

    fp = fopen("output.txt", "w");

    fprintf(fp, "Hello Linux\n");

    fclose(fp);

    return 0;
}

Low-Level Linux File I/O

Linux system programming often uses:

open()
read()
write()
close()

instead of:

fopen()
fgets()
fprintf()
fclose()

Example:

#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd;

    fd = open("test.txt", O_RDONLY);

    close(fd);

    return 0;
}

These are system calls.


3. Processes and fork()

Every running program in Linux is a process.

When you run:

ls

Linux creates a process.

When you run:

firefox

Linux creates another process.


Creating a Process

Linux uses fork().

#include <stdio.h>
#include <unistd.h>

int main()
{
    fork();

    printf("Hello\n");

    return 0;
}

Output:

Hello
Hello

Why?

fork() duplicates the process.

After fork():

Parent process continues.

Child process continues.

Both execute the printf().


Parent and Child

#include <stdio.h>
#include <unistd.h>

int main()
{
    pid_t pid;

    pid = fork();

    if (pid == 0)
    {
        printf("Child process\n");
    }
    else
    {
        printf("Parent process\n");
    }

    return 0;
}

Process IDs

#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("PID: %d\n", getpid());

    return 0;
}

Useful commands:

ps
top
htop
kill

4. Signals

Signals are messages sent to processes.

Examples:

SIGINT   Ctrl+C
SIGTERM  Request process exit
SIGKILL  Force process termination

Catching Ctrl+C

#include <stdio.h>
#include <signal.h>

void handler(int sig)
{
    printf("\nCaught signal %d\n", sig);
}

int main()
{
    signal(SIGINT, handler);

    while (1)
    {
    }

    return 0;
}

Run it and press:

Ctrl+C

Instead of immediately terminating, the signal handler runs.


Sending Signals

Find process ID:

ps

Send signal:

kill PID

Force kill:

kill -9 PID

5. Pipes

Pipes allow processes to communicate.

Example shell pipeline:

ls | grep txt

Output from ls becomes input for grep.


Creating a Pipe

#include <stdio.h>
#include <unistd.h>

int main()
{
    int fd[2];

    pipe(fd);

    return 0;
}

pipe() creates:

fd[0] Read end
fd[1] Write end

Writing and Reading

#include <stdio.h>
#include <unistd.h>

int main()
{
    int fd[2];

    char buffer[100];

    pipe(fd);

    write(fd[1], "Hello", 5);

    read(fd[0], buffer, 5);

    buffer[5] = '\0';

    printf("%s\n", buffer);

    return 0;
}

Output:

Hello

Pipes are used heavily by shells and daemons.


6. Threads

Processes have their own memory.

Threads share memory within a process.

Threads are useful when multiple tasks need to run simultaneously.


Creating a Thread

#include <stdio.h>
#include <pthread.h>

void *worker(void *arg)
{
    printf("Worker thread\n");

    return NULL;
}

int main()
{
    pthread_t thread;

    pthread_create(
        &thread,
        NULL,
        worker,
        NULL
    );

    pthread_join(thread, NULL);

    return 0;
}

Compile:

gcc thread.c -o thread -pthread

Output:

Worker thread

Why Threads Matter

Examples:

Web servers

Database servers

Graphical applications

Network applications

Linux uses threads extensively.


7. Sockets and TCP/IP Networking

Sockets allow programs to communicate over networks.

Every web server uses sockets.

Every browser uses sockets.

SSH uses sockets.

FTP uses sockets.

DNS uses sockets.


Creating a Socket

#include <sys/socket.h>

int main()
{
    int sockfd;

    sockfd = socket(
        AF_INET,
        SOCK_STREAM,
        0
    );

    return 0;
}

Socket Types

SOCK_STREAM  TCP
SOCK_DGRAM   UDP

TCP:

Reliable

Connection-oriented

Used by:

HTTP
HTTPS
SSH

UDP:

Faster

Connectionless

Used by:

DNS
VoIP
Streaming


Simple TCP Client

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main()
{
    int sockfd;

    sockfd = socket(
        AF_INET,
        SOCK_STREAM,
        0
    );

    printf("Socket created\n");

    return 0;
}

Real clients additionally use:

connect()
send()
recv()
close()

Summary

Before beginning serious Linux system programming, make sure you understand:

C Fundamentals

Variables
Loops
Functions
Arrays
Pointers
Structs
Dynamic Memory

Linux Programming Fundamentals

argc and argv
File I/O
fork()
Processes
Signals
Pipes
Threads
Sockets

Once you are comfortable with these topics, you are ready to study:

  • Linux system calls
  • The POSIX API
  • Interprocess communication (IPC)
  • Network programming
  • Daemon programming
  • Kernel interfaces
  • Operating system internals

At that point books like Beginning Linux Programming, Advanced Linux Programming, and Linux System Programming become much easier to follow because you’ll understand the core tools Linux applications use every day.

Tags: C Programming

Post navigation

❮ Previous Post: Writing C Programs from the Command Line on a MacBook M1

You may also like

programming
Writing C Programs from the Command Line on a MacBook M1
June 18, 2026
programming
C Programming on FreeBSD vs Linux
June 18, 2026

Leave a Reply Cancel reply

You must be logged in to post a comment.

Recent Posts

  • Learn Just Enough C for Linux Programming
  • Writing C Programs from the Command Line on a MacBook M1
  • C Programming on FreeBSD vs Linux
  • UNIX’s Influence Today: The Operating System That Shaped Modern Computing
  • The Role of GNU: Building the Foundation of Free Software

Recent Comments

No comments to show.

Archives

  • June 2026
  • May 2026

Categories

  • History
  • Networking
  • Open Source Systems and Development
  • programming
  • Scripting

Copyright © 2026 Learn Operating Systems.

Theme: Oceanly News Dark by ScriptsTown