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:
- Command-line arguments (argc and argv)
- File I/O (open, read, write, close)
- Processes and fork()
- Signals
- Pipes
- Threads
- 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:
helloworld
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: 4argv[0] = ./argsargv[1] = appleargv[2] = bananaargv[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 Readw Writea 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:
HelloHello
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:
pstophtopkill
4. Signals
Signals are messages sent to processes.
Examples:
SIGINT Ctrl+CSIGTERM Request process exitSIGKILL 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 endfd[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 TCPSOCK_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.