A set of C example programs showing the basic usage of Unix system calls related to Filesystem, Processes and Threads to learn about Unix-like filesystem manipulation and C multiprocess and multithread programming.
This collection of examples demonstrates:
- Function pointers & generic programming – dynamic invocation and flexible code structures.
- File I/O with C Standard Library – byte-wise and stream-based file operations.
- Unix process management – creation, synchronization, and termination of child processes.
- Signals & IPC mechanisms – using
kill(),pause(),pipe(), andwait()for inter-process communication. - Multithreading & thread-safe operations – concurrent processing of data, file I/O, and sorting using
pthread_createandpthread_join.
This collection of examples demonstrates key concepts in C programming on a Unix-like operating system using standard tools and libraries. All examples were developed using:
- Language: C (C99/C11 standard)
- OS: Linux / Unix-like environments
- Toolchain: GCC, Make, POSIX-compliant libraries
- Techniques demonstrated: Process creation and management, inter-process communication (IPC), file I/O, signals, threading, synchronization, assertion-based error checking
- Libraries used:
<stdio.h>,<stdlib.h>,<unistd.h>,<fcntl.h>,<pthread.h>,<assert.h>,<string.h> - Programming techniques: Forking, wait/waitpid, pipes, signals, pause, kill, thread creation and joining, dynamic memory management, bubble sort in threads, concurrent file processing
Below is a comprehensive list of the examples included in this folder, grouped by topic, with direct links to their detailed sections:
- C-Func-pointer – Demonstrates function pointers in C, dynamic invocation, and generic programming using
void *.
- C-STD-File – Basic file input/output, copying files byte by byte, error handling, and EOF processing.
- C-Unix-STD-Basic-Fork – Basic process creation using
fork(). - C-Unix-STD-Fork – Process creation and simple child execution.
- C-Unix-STD-Fork-Sleep – Process sleeping and parent-child coordination.
- C-Unix-STD-Fork-Wait – Waiting for child processes using
wait(). - C-Unix-STD-Fork-Waitpid – Selective waiting with
waitpid(). - C-Unix-STD-Fork-Wait-Precedence – Controlling execution order of children.
- C-Unix-STD-Copy-DirectoryTree – Recursive directory copying using standard file I/O.
- C-Unix-STD-Execl – Executing external programs with
execl(). - C-Unix-STD-Execlp-System – Executing external programs using
execlp()andsystem(). - C-Unix-STD-Explore-File-Directories – Directory exploration using
opendir()andreaddir().
- C-Unix-STD-Kill – Sending signals to processes with
kill(). - C-Unix-STD-Signal – Signal handling and custom handlers with
signal(). - C-Unix-STD-Signal-Fork – Combining signals with child processes.
- C-Unix-STD-Signal-Fork-Kill – Parent-child signaling with
kill(). - C-Unix-STD-Signal-Fork-Pause – Synchronization using
pause(). - C-Unix-STD-Signal-Fork-Pause-Kill – Controlled signaling using
pause()andkill(). - C-Unix-STD-Signal-Fork-Pause-Kill-File-Wait – File reading, signaling, and parent-child synchronization.
- C-Unix-STD-Signal-Fork-Pause-Kill-Pipe – Parent-child IPC via pipes with file streaming to stdout.
- C-Unix-STD-Signal-Fork-Pause-Kill-Wait – Multi-child signaling with sequential wait synchronization.
- C-Unix-STD-Threads – Concurrent processing of file pairs using threads.
- C-Unix-STD-Threads-Files-Assert – Multithreaded file processing with bubble sort and assertion-based checks.
Each example includes detailed explanations of the system calls, functions, and programming techniques used. They serve as a reference for:
- Process creation and management
- Inter-process communication (pipes, signals)
- File I/O and directory exploration
- Threading and synchronization
- Assertion-based error checking and debugging
- Concurrent algorithms (sorting, data processing)
Let's start to see each example into detail.
Path: src/C-Func-pointer/main.c
This example demonstrates the use of function pointers in C, showing how functions can be assigned to variables, passed around, and invoked dynamically at runtime.
The goal is to understand:
- how to declare and use function pointers
- how to pass generic data using
void * - how to build flexible and reusable logic
The program manages an integer array of fixed size using a set of functions operating on generic pointers.
The execution flow is the following:
-
init()dynamically allocates and initializes an integer array of sizedimwith all values set to zero -
Two function pointers are declared:
add→ points toinc()dec→ points tosub()
-
inc()increments each element of the array by a given value -
sub()decrements each element of the array by a given value -
show()prints the content of the array
All data manipulation functions receive the array as a void *,
demonstrating a generic programming approach in C.
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Standard input/output operations | cppreference |
<stdlib.h> |
Dynamic memory allocation | cppreference |
<string.h> |
String manipulation utilities | cppreference |
| Function | Role | Reference |
|---|---|---|
malloc() |
Allocates memory dynamically | cppreference |
printf() |
Prints formatted output | cppreference |
- 🧷 Function pointers
- 🧬 Generic programming with
void * - 🧠 Indirect function invocation
- 📦 Dynamic memory allocation
- ♻️ Reusable and modular code
- 📘 Function Pointers in C: cppreference – Pointers
Path: src/C-STD-File/main.c
This example shows how to perform basic file input/output using the C standard library. The program copies the content of a source file into a destination file, byte by byte.
It introduces fundamental concepts such as file streams, error handling, and sequential file processing.
The program expects exactly two command-line arguments:
- the path of the source file to read
- the path of the destination file to write
The execution flow is the following:
- Checks the number of command-line arguments
-
Opens the source file in read mode using
fopen() - Opens (or creates) the destination file in write mode
-
Reads characters one by one from the source file using
fgetc() -
Writes each character to the destination file using
fputc()
The program stops copying when the EOF (End Of File) marker is reached.
This demonstrates a simple and classic file copy algorithm using standard I/O.
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Standard input/output and file streams | cppreference |
<stdlib.h> |
General utilities | cppreference |
<assert.h> |
Runtime assertions for error checking | cppreference |
| Function | Role | Reference |
|---|---|---|
fopen() |
Opens a file stream | cppreference |
fgetc() |
Reads a character from a file | cppreference |
fputc() |
Writes a character to a file | cppreference |
fprintf() |
Prints formatted output to a stream | cppreference |
assert() |
Checks runtime conditions | cppreference |
- 📂 File streams (
FILE *) - 📝 Character-based file I/O
⚠️ Basic error handling- 🧪 Runtime assertions
- 📄 End Of File (
EOF) handling
- 📘 C File I/O: cppreference – C Input/Output
Path: src/C-Unix-STD-Basic-Fork/main.c
This example demonstrates the basic behavior of the fork() system call
and how a process is duplicated into a parent and a child process.
The goal is to understand:
- how to distinguish parent and child processes
- how execution flow is duplicated
- how concurrent processes produce output
The program executes a decreasing for loop (i = 2 → 1).
At each iteration:
- the
fork()system call is invoked - the parent process receives a value greater than
0 - the child process receives
0 -
based on the return value:
- the parent prints
i - the child prints
-i
- the parent prints
Since fork() duplicates the current process:
- after the first iteration there are 2 running processes
- after the second iteration there are 4 running processes
The order of the printed output is non-deterministic, because it depends on the operating system scheduler.
| Header | Description | Reference |
|---|---|---|
<stdlib.h> |
Standard utility functions | cppreference |
<stdio.h> |
Standard input/output | cppreference |
<unistd.h> |
POSIX process control | Open Group |
| Function | Role | Reference |
|---|---|---|
fork() |
Creates a new process by duplicating the caller | man7.org |
printf() |
Writes formatted output to stdout | cppreference |
- 🔀 Process creation
- 👨👦 Parent vs child execution
- 🔁 Concurrent execution
- 🎲 Non-deterministic output
- 📈 Exponential process growth
- 📘 POSIX fork() Reference: Open Group Specification
Path: src/C-Unix-STD-Copy-DirectoryTree/main.c
This example demonstrates recursive copying of a directory tree using Unix system calls. It shows how to duplicate all files and subdirectories from a source directory to a destination directory.
The goal is to understand:
- how to traverse directories recursively
- how to handle files and directories differently
- how low-level file I/O works in Unix
- how to implement robust error handling
The program expects exactly two command-line arguments:
- the path of the source directory
- the path of the destination directory
Execution flow:
- Validate argument count using
assert(). - Retrieve file status of source and destination using
lstat(). - Check that both paths are directories using
S_ISDIR(). - Invoke the recursive
copia()function:- Open source and destination directories with
opendir(). - Iterate over directory entries using
readdir(), skipping.and... - Build full paths for each entry with
sprintf(). - Check entry type using
lstat():- If a file, copy its contents using
open(),read(), andwrite(). - If a directory, create it using
mkdir()and recursively callcopia().
- If a file, copy its contents using
- Close directory streams with
closedir().
- Open source and destination directories with
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Standard I/O for fprintf() |
cppreference |
<stdlib.h> |
Standard utilities, exit() |
cppreference |
<sys/types.h> |
Data types for system calls | man7.org |
<sys/stat.h> |
File status and mode macros (S_ISDIR) |
man7.org |
<unistd.h> |
Unix standard functions (read, write, close) |
man7.org |
<dirent.h> |
Directory handling (opendir, readdir, closedir) |
man7.org |
<fcntl.h> |
File control flags (O_RDONLY, O_WRONLY, O_CREAT) |
man7.org |
<assert.h> |
Runtime assertions | cppreference |
| Function | Role | Reference |
|---|---|---|
lstat() |
Retrieve file or directory status | man7.org |
S_ISDIR() |
Check if path is a directory | man7.org |
opendir() |
Open a directory stream | man7.org |
readdir() |
Read entries from a directory | man7.org |
closedir() |
Close a directory stream | man7.org |
open() |
Open a file descriptor | man7.org |
read() |
Read bytes from a file descriptor | man7.org |
write() |
Write bytes to a file descriptor | man7.org |
mkdir() |
Create a new directory | man7.org |
sprintf() |
Build full file paths as strings | cppreference |
assert() |
Runtime condition checks | cppreference |
fprintf() |
Print formatted error messages to stderr |
cppreference |
- 📂 Recursive directory traversal
- 📝 Low-level file I/O with
open/read/write ⚠️ Error handling withfprintf(),assert(), andexit()- 🔄 Preserving directory structure
- 🧪 Runtime validation of command-line arguments
- 🔁 Recursion for nested directories
- 📘 Unix Directory Handling: opendir/readdir/closedir
- 📘 Unix File I/O: read/write/open
- 📘 C File I/O: cppreference – C Input/Output
Path: src/C-Unix-STD-Execl/main.c
This example demonstrates the use of the execl() system call
to replace the current process image with a new program.
The goal is to understand:
- how
execl()replaces the current process - how execution flow stops after a successful
execl() - the effect on program output when
execl()fails
The program expects one command-line argument specifying the program to execute:
- Print the current process ID and increment a counter.
- Call
execl()with the provided program path. - If
execl()succeeds, the new program replaces the current process and the nextfprintf()is not executed. - If
execl()fails, an error message is printed and the program exits withreturn 1.
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Standard input/output functions | cppreference |
<stdlib.h> |
General utilities, exit() |
cppreference |
<unistd.h> |
POSIX system calls, execl(), getpid() |
man7.org |
| Function | Role | Reference |
|---|---|---|
execl() |
Replaces current process image with a new program | man7.org |
getpid() |
Returns the process ID of the current process | man7.org |
fprintf() |
Print formatted output to a stream (stdout or stderr) | cppreference |
- 🔁 Process replacement with
execl() - 👀 Execution flow stops after successful
execl() ⚠️ Handling execl failure- 📄 Process identification with
getpid()
- 📘 POSIX execl(): man7.org
Path: src/C-Unix-STD-Execlp-System/main.c
This example demonstrates process creation and execution using fork(), system(), and execlp().
The goal is to understand:
- how
fork()creates concurrent processes - how
system()can execute shell commands - how
execlp()replaces the process image - how parent and child processes interact
The program executes nested loops with process creation:
- Call
fork()to create the first child. - For
i = 0to1:- If in the parent process, build a command string and execute it using
system(). - If in the child process, build a string and execute it using
execlp()withecho.
- If in the parent process, build a command string and execute it using
- The
execlp()calls replace the child process image withecho, whilesystem()runs in the parent process. - This demonstrates concurrent execution and process replacement within the same loop.
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Standard input/output functions | cppreference |
<stdlib.h> |
General utilities, system() |
cppreference |
<unistd.h> |
POSIX system calls (fork(), execlp()) |
man7.org |
| Function | Role | Reference |
|---|---|---|
fork() |
Create a new child process | man7.org |
execlp() |
Replace current process image with a new program found in PATH | man7.org |
system() |
Execute shell command in a separate process | man7.org |
sprintf() |
Format string into buffer for command execution | cppreference |
- 🔀 Process creation and concurrency with
fork() - 🔁 Process replacement with
execlp() - 💻 Shell command execution with
system() ⚠️ Parent vs child process execution control- 📄 Demonstrates interaction between multiple processes in a loop
Path: src/C-Unix-STD-Explore-Directories/main.c
This example demonstrates recursive exploration of directories in a file system.
The goal is to understand:
- how to navigate directories using
opendir()andreaddir() - how to distinguish files and directories using
lstat() - how recursion can be applied to traverse an entire directory tree
The program expects a single command-line argument specifying the root directory:
- Check if the provided path exists and is a directory using
lstat(). - Call a recursive function
funzione()to explore the directory tree. - Inside the recursive function:
- Open the directory with
opendir(). - Iterate over all entries with
readdir(). - For files, print the full path.
- For directories, print the path and recursively explore its contents.
- Open the directory with
- Close the directory after traversal with
closedir().
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Input/output functions | cppreference |
<stdlib.h> |
General utilities, exit() |
cppreference |
<unistd.h> |
POSIX system calls (lstat()) |
man7.org |
<sys/stat.h> |
File status information | cppreference |
<dirent.h> |
Directory stream handling | man7.org |
<string.h> |
String manipulation functions | cppreference |
| Function | Role | Reference |
|---|---|---|
lstat() |
Get information about a file or directory | man7.org |
opendir() |
Open a directory stream | man7.org |
readdir() |
Read the next entry in a directory | man7.org |
closedir() |
Close a directory stream | man7.org |
fprintf() |
Print formatted output to stdout/stderr | cppreference |
- 📂 Directory traversal using
opendir()/readdir() - 📝 Differentiating files and directories
- 🔁 Recursive algorithms
⚠️ Basic error handling in file systems
- 📘 POSIX Directory Operations: man7.org
Path: src/C-Unix-STD-Fork/main.c
This example demonstrates process creation using fork() and semaphores to control output order.
The goal is to understand:
- how multiple child processes can be created concurrently
- how to use semaphores to synchronize process output
- how process execution order can be controlled
The program reads a string from stdin and creates one child process per character:
- Initialize a semaphore to zero.
- For each character, create a child process using
fork(). - Each child waits on the semaphore (
sem_wait()) before printing its character. - The parent posts to the semaphore (
sem_post()) sequentially to allow children to print in order. - Child processes exit after printing, ensuring ordered output.
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Standard input/output | cppreference |
<stdlib.h> |
General utilities, memory allocation, exit() |
cppreference |
<unistd.h> |
POSIX process control (fork()) |
man7.org |
<semaphore.h> |
POSIX semaphores for process synchronization | man7.org |
<string.h> |
String manipulation (strlen(), strdup()) |
cppreference |
| Function | Role | Reference |
|---|---|---|
fork() |
Create a new child process | man7.org |
sem_init() |
Initialize semaphore | man7.org |
sem_wait() |
Wait (decrement) on semaphore | man7.org |
sem_post() |
Signal (increment) semaphore | man7.org |
printf() |
Output character to stdout | cppreference |
- 🔀 Process creation with
fork() - 🔁 Process synchronization using semaphores
- 📝 Ordered output from concurrent processes
⚠️ Proper use ofexit()in child processes
Path: src/C-Unix-STD-Fork-Sleep/main.c
This example demonstrates nested process creation using fork() and controlled termination with sleep().
The goal is to understand:
- how multiple levels of processes can be spawned
- how to differentiate "leaf" processes
- how
sleep()can be used to control process timing and termination
The program expects two command-line arguments: number of iterations n and sleep time t:
- Loop
i = 0 → n-1, creating child processes withfork(). - Within the loop, if in the parent process, another
fork()may be called to create nested children. - After all forks, the process sleeps for
tseconds. - After waking, the leaf process prints a termination message.
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Input/output functions | cppreference |
<stdlib.h> |
General utilities, atoi(), exit() |
cppreference |
<unistd.h> |
POSIX system calls, fork(), sleep() |
man7.org |
<sys/wait.h> |
Waiting for process termination | man7.org |
<assert.h> |
Runtime assertions | cppreference |
| Function | Role | Reference |
|---|---|---|
fork() |
Create a new child process | man7.org |
sleep() |
Pause process execution for a specified time | man7.org |
printf() |
Output to stdout | cppreference |
assert() |
Verify runtime conditions | cppreference |
- 🔀 Nested process creation with
fork() - ⏳ Process timing control with
sleep() ⚠️ Parent vs leaf process identification- 📄 Controlled process termination
Path: src/C-Unix-STD-Fork-Wait/main.c
This example demonstrates process creation with fork() and parent-child synchronization using wait().
The goal is to understand:
- how the parent waits for child processes to complete before continuing
- how to pass data from the parent to children using memory arrays
- how sequential output can be enforced using
wait()
The program expects a single command-line argument n for the number of integers:
- Allocate an array of size
ndynamically usingmalloc(). - Read
nintegers from the user into the array. - Loop over the array, and for each element:
- Call
fork()to create a child process. - In the parent process:
- Call
wait(NULL)to wait for the child to finish. - Print the corresponding integer from the array.
- Exit with the child index as exit code.
- Call
- Call
- Child processes exit immediately after creation.
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Standard input/output | cppreference |
<stdlib.h> |
Memory allocation (malloc()), atoi(), exit() |
cppreference |
<unistd.h> |
Process creation (fork()) |
man7.org |
<sys/wait.h> |
Waiting for child process termination (wait()) |
man7.org |
<assert.h> |
Runtime assertions | cppreference |
| Function | Role | Reference |
|---|---|---|
fork() |
Create child processes | man7.org |
wait() |
Wait for a child process to terminate | man7.org |
malloc() |
Allocate dynamic memory for the integer array | cppreference |
exit() |
Terminate a process with a specific exit code | cppreference |
- 🔀 Process creation and parent-child hierarchy
- ⏳ Sequential execution of child processes using
wait() - 📝 Passing and printing data via shared memory arrays
⚠️ Proper termination of child processes
Path: src/C-Unix-STD-Fork-Wait-Precedence/main.c
This example demonstrates process creation with multiple fork() calls and wait() to enforce execution precedence.
The goal is to understand:
- how a complex tree of processes can be spawned
- how
wait()controls which child completes before the parent proceeds - how to trace parent-child relationships and execution order
The program creates a complex hierarchy of child processes:
- Parent creates child P1 with
fork(). P1 prints its PID and exits. - The parent waits for P1 to finish using
wait(). - Parent sequentially spawns P2, P3, … P12 with additional
fork()calls, sometimes nested. - Each child prints its PID, parent PID, and an iteration index, then exits.
- The use of
wait()ensures that the parent continues only after specific children terminate, enforcing precedence.
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Standard input/output | cppreference |
<stdlib.h> |
Utilities, exit() |
cppreference |
<unistd.h> |
Process creation (fork()) |
man7.org |
<sys/wait.h> |
Process termination synchronization (wait()) |
man7.org |
<assert.h> |
Runtime assertions | cppreference |
| Function | Role | Reference |
|---|---|---|
fork() |
Create child processes in sequence and nested hierarchies | man7.org |
wait() |
Wait for specific child process to terminate, enforcing execution order | man7.org |
printf() |
Print process information | cppreference |
exit() |
Terminate a process with a status code | cppreference |
- 🔀 Nested and sequential process creation
- ⏳ Controlling execution precedence using
wait() - 📄 Tracking PID and PPID relationships
⚠️ Proper child process termination to prevent zombies
Path: src/C-Unix-STD-Fork-Waitpid/main.c
This example demonstrates process creation using fork() and selective waiting using waitpid().
The goal is to understand:
- how to create multiple child processes
- how
waitpid()can wait for specific child processes instead of any child - how to handle process termination selectively
The program creates N child processes in a loop:
- For each child, call
fork()and store the child PID in an array. - In child processes, immediately exit with
EXIT_SUCCESS. - After creating children, the parent selectively waits for children with index >
Musingwaitpid(). - This demonstrates control over which child processes to wait for and allows partial concurrent execution.
| Header | Description | Reference |
|---|---|---|
<stdio.h> |
Standard input/output | cppreference |
<stdlib.h> |
General utilities, exit() |
cppreference |
<unistd.h> |
Process creation (fork()) |
man7.org |
<sys/wait.h> |
Selective waiting for child processes (waitpid()) |
man7.org |
| Function | Role | Reference |
|---|---|---|
fork() |
Create child processes | man7.org |
waitpid() |
Wait for a specific child process to terminate | man7.org |
exit() |
Terminate a process | cppreference |
- 🔀 Multiple child process creation
- 🧩 Selective waiting using
waitpid() ⚠️ Preventing zombie processes- ⏱️ Partial concurrency control
Path: src/C-Unix-STD-Signal-Fork-Pause-Kill-Pipe/main.c
This example demonstrates parent-child communication using a pipe, where the child reads a file and sends its content to the parent through the pipe.
The goal is to understand:
- How to create a pipe for IPC between parent and child
- How a child can write data to a pipe and parent can read it
- How to coordinate file I/O with process communication
- Create a pipe using
pipe()for IPC. - Fork a child process:
- Child closes the read-end of the pipe.
- Opens
testo.txtand reads its content. - Writes the content to the pipe.
- Parent process closes the write-end of the pipe.
- Parent reads from the pipe and writes the content to stdout.
| Header | Description | Reference |
|---|---|---|
<unistd.h> | fork, pipe, read, write | man7.org |
<fcntl.h> | File open/read | man7.org |
<stdlib.h> | Memory allocation, exit | cppreference |
<stdio.h> | File I/O and stdout | cppreference |
<assert.h> | Error checking | cppreference |
| Function | Role | Reference |
|---|---|---|
fork() | Create child process | man7.org |
pipe() | Create IPC pipe | man7.org |
read(), write() | Read/write through pipe and file | man7.org |
close() | Close pipe ends | man7.org |
exit() | Terminate a process | cppreference |
- 📡 Parent-child IPC via pipe
- 👨👦 Coordinated file read and stdout output
- 🔁 Streaming data between processes using pipe
⚠️ Ensuring proper pipe closure to prevent deadlocks
Path: src/C-Unix-STD-Signal-Fork-Pause-Kill-Wait/main.c
This example demonstrates two-child signal-based communication with parent synchronization using wait().
The goal is to understand:
- How to use signals (
SIGUSR1,SIGUSR2) for inter-process communication - How to synchronize parent with multiple children using
wait() - How to coordinate sequential execution of child processes
- Fork two child processes.
- Child processes pause until receiving their respective signal (
SIGUSR1orSIGUSR2). - Parent sends signals in a controlled order and waits for child termination using
wait(). - This ensures orderly execution and prevents zombie processes.
| Header | Description | Reference |
|---|---|---|
<stdio.h> | Standard input/output | cppreference |
<stdlib.h> | Exit, general utilities | cppreference |
<unistd.h> | fork(), pause() | man7.org |
<signal.h> | Signal handling | man7.org |
<sys/wait.h> | wait() for child processes | man7.org |
| Function | Role | Reference |
|---|---|---|
fork() | Create child processes | man7.org |
signal() | Install signal handlers | man7.org |
pause() | Wait for a signal | man7.org |
kill() | Send signal to child | man7.org |
wait() | Wait for child termination | man7.org |
- 🔀 Parent-child signaling with
SIGUSR1/SIGUSR2 - ⏱️ Synchronizing parent with children using
wait() ⚠️ Preventing zombie processes- 🧩 Coordinated sequential execution
Path: src/C-Unix-STD-Kill/main.c
This program demonstrates the use of the kill() system call
to send signals to a specific process based on command-line arguments.
The goal is to understand:
- how to target a process by PID
- how to send different signals (
SIGUSR1,SIGUSR2,SIGINT) - how command-line arguments can control signal behavior
- Expect exactly two command-line arguments: target PID and a command string.
- Compare the command string:
somma→ sendSIGUSR2differenza→ sendSIGUSR1fine→ sendSIGINT
- If the command is invalid, print an error message.
- Uses
kill(pid, signal)to notify the target process.
| Header | Description | Reference |
|---|---|---|
<signal.h> | Signal handling and sending (kill()) | man7.org |
<stdlib.h> | Conversion (atoi()) | cppreference |
<unistd.h> | Process primitives | man7.org |
<string.h> | String comparison (strcmp()) | cppreference |
<assert.h> | Runtime assertion to check argument count | cppreference |
| Function | Role | Reference |
|---|---|---|
kill() | Send a signal to a process by PID | man7.org |
atoi() | Convert string to integer (PID) | cppreference |
strcmp() | Compare command strings | cppreference |
- 🔀 Process targeting by PID
- ⚡ Sending signals to control remote process behavior
⚠️ Handling invalid commands safely
- 📘 kill() man page: man7.org
Path: src/C-Unix-STD-Signal/main.c
Demonstrates signal handling using signal() and pause().
The goal is to understand:
- how to handle multiple signals (
SIGUSR1,SIGUSR2,SIGINT) - how a process can react to external signals
- using
pause()to wait for signals
- Set up handlers for
SIGUSR1,SIGUSR2,SIGINTusingsignal(). - Read two integers from the user.
- Enter an infinite loop calling
pause()to wait for signals. - When a signal is received:
SIGUSR1: print the difference of the two integers.SIGUSR2: print the sum of the two integers.SIGINT: terminate the process.
| Header | Description | Reference |
|---|---|---|
<signal.h> | Signal handling (signal()) | man7.org |
<stdio.h> | Input/output | cppreference |
<stdlib.h> | General utilities (exit()) | cppreference |
<unistd.h> | Pause and process control | man7.org |
| Function | Role | Reference |
|---|---|---|
signal() | Install a handler for a specific signal | man7.org |
pause() | Wait until a signal is received | man7.org |
scanf() | Read integers from user | cppreference |
printf() | Print results | cppreference |
- ⚡ Signal handling
- ⏳ Waiting for signals using
pause() - 📝 Dynamic reaction to external events
⚠️ Graceful termination via signals
Path: src/C-Unix-STD-Signal-Fork/main.c
Demonstrates the combination of fork() and signal handling, showing how a parent can control child processes using signals.
The goal is to understand:
- creating multiple child processes with
fork() - sending signals to children to trigger handlers
- coordinating execution between parent and children
- Accept exactly one command-line argument
n, the number of child processes. - Install a signal handler
manager()forSIGUSR1in children. - Loop
ntimes:- fork a child process
- child calls
pause()and waits for a signal - parent sleeps 2 seconds, prints info, then sends
SIGUSR1to the child
- Children print a message when receiving
SIGUSR1and exit. - Parent continues to the next child.
| Header | Description | Reference |
|---|---|---|
<signal.h> | Signal handling | man7.org |
<unistd.h> | Process control and fork | man7.org |
<stdio.h> | Input/output | cppreference |
<stdlib.h> | Memory allocation, exit | cppreference |
<assert.h> | Runtime checks | cppreference |
| Function | Role | Reference |
|---|---|---|
fork() | Create a child process | man7.org |
signal() | Assign handler to SIGUSR1 | man7.org |
pause() | Wait until a signal arrives | man7.org |
kill() | Parent sends signal to child | man7.org |
printf() | Output messages to stdout | cppreference |
- 👶 Child processes with fork()
- ⚡ Signal communication parent → child
- ⏳ Synchronized execution using pause() and sleep()
- 📝 Process info reporting via signals
Path: src/C-Unix-STD-Signal-Fork-Kill/main.c
Demonstrates a bidirectional signal exchange between parent and child processes
combined with fork() and kill().
The goal is to understand:
- parent-child communication using signals
- how children can respond to signals and reply to parent
- looping signal interactions in a controlled sequence
- Parent sets up handlers for
SIGUSR1,SIGUSR2,SIGINT. - Parent forks a single child process.
- Child enters an infinite loop, waiting for signals using
pause()and reacts:SIGUSR1: sendSIGUSR2to parentSIGUSR2: sendSIGUSR1to parentSIGINT: sendSIGINTto parent and terminate
- Parent cycles through an array of signals, sending one to the child every second in a loop.
- Demonstrates bidirectional signaling, signal handling, and safe process termination.
| Header | Description | Reference |
|---|---|---|
<signal.h> | Signal handling | man7.org |
<unistd.h> | Process control and fork | man7.org |
<stdio.h> | Input/output | cppreference |
<stdlib.h> | Memory allocation, exit | cppreference |
| Function | Role | Reference |
|---|---|---|
fork() | Create child process | man7.org |
signal() | Install signal handlers in parent and child | man7.org |
kill() | Send signal to a process | man7.org |
pause() | Child waits for signals | man7.org |
malloc()/free() | Allocate/free memory for signal array | cppreference |
- 👨👦 Parent-child process communication
- 🔁 Bidirectional signaling
- ⏳ Synchronization using signals and pause()
- ⚡ Dynamic reaction to signal events
- 🛡️ Safe process termination via SIGINT
Path: src/C-Unix-STD-Signal-Fork-Pause/main.c
Demonstrates parent-child synchronization using signals and pause() with file I/O from child processes.
The goal is to understand:
- forking multiple child processes
- sending signals to children to trigger specific actions
- reading files in child processes and writing to stdout
- using pause() for waiting on signals
- Open two files for reading:
son1.txtandson2.txt. - Install a signal handler for
SIGUSR1andSIGCHLD. - Fork the first child:
- Child pauses until
SIGUSR1is received - Reads 50 bytes from
son1.txtand writes to stdout
- Child pauses until
- Fork the second child:
- Child pauses until
SIGUSR1is received - Reads 50 bytes from
son2.txtand writes to stdout - Child sleeps 5 seconds then exits
- Child pauses until
- Parent prints PIDs of both children, sends
SIGUSR1to each child in sequence, using pause() to synchronize. - After both children finish, parent closes file descriptors and exits.
| Header | Description | Reference |
|---|---|---|
| <signal.h> | Signal handling | man7.org |
| <unistd.h> | Process control, fork, pause | man7.org |
| <fcntl.h> | File I/O open/read/write | man7.org |
| <stdio.h> | Standard input/output | cppreference |
| <stdlib.h> | Exit, malloc | cppreference |
| Function | Role | Reference |
|---|---|---|
| fork() | Create child processes | man7.org |
| signal() | Install signal handlers | man7.org |
| pause() | Wait for a signal | man7.org |
| open(), read(), write() | File I/O in child processes | man7.org |
| kill() | Send signal to child | man7.org |
- 👨👦 Parent-child communication via signals
- ⏳ Process synchronization using pause()
- 📂 File reading in forked processes
- ⚡ Signal-triggered execution in children
- 🛡️ Handling child termination signals
Path: src/C-Unix-STD-Signal-Fork-Pause-Kill/main.c
Demonstrates signal handling and inter-process notification using a single child process.
- Child waits for
SIGINTsignal before executing - Parent can send
SIGINTto terminate the child - Shows basic pause-and-signal synchronization
- Install empty signal handlers for
SIGINTandSIGCHLD. - Fork a child process:
- Child pauses until
SIGINTis received - After signal, child prints a message and exits
- Child pauses until
- Parent pauses, sends
SIGINTto child, and waits for completion.
| Header | Description | Reference |
|---|---|---|
| <signal.h> | Signal handling | man7.org |
| <unistd.h> | Process control | man7.org |
| <stdlib.h> | Exit, memory allocation | cppreference |
| <stdio.h> | Standard I/O | cppreference |
| <assert.h> | Assertions for error checking | cppreference |
| Function | Role | Reference |
|---|---|---|
| fork() | Create child process | man7.org |
| signal() | Install signal handlers | man7.org |
| pause() | Wait for a signal | man7.org |
| kill() | Send signal to child | man7.org |
- 👨👦 Parent-child synchronization via signals
- ⏳ Using pause() for waiting signals
- ⚡ Sending SIGINT to terminate child process
- 🛡️ Signal handling to control execution flow
Path: src/C-Unix-STD-Signal-Fork-Pause-Kill-File-Wait/main.c
Demonstrates two-child process coordination using signals, pause(), and file I/O.
- Child processes read separate text files and print to stdout
- Synchronization between children using signals
- Parent controls execution flow
- Install signal handlers for
SIGUSR1andSIGCHLD. - Fork first child:
- Wait for signal from parent
- Read
testo_1.txtand print content - Send signal to second child after finishing
- Fork second child:
- Wait for signal from first child
- Read
testo_3.txtand print content - Send signal back to first child or exit
- Parent triggers first signal, then waits for both children to finish.
| Header | Description | Reference |
|---|---|---|
| <signal.h> | Signal handling | man7.org |
| <unistd.h> | fork, pause | man7.org |
| <fcntl.h> | File open/read | man7.org |
| <stdio.h> | File I/O and stdout | cppreference |
| <stdlib.h> | Exit, malloc | cppreference |
| <assert.h> | Error checking | cppreference |
| Function | Role | Reference |
|---|---|---|
| fork() | Create child processes | man7.org |
| signal() | Install handlers for inter-process signaling | man7.org |
| pause() | Wait for signals | man7.org |
| open(), read(), write() | File I/O for children | man7.org |
| kill() | Send signals between children | man7.org |
- 👨👦 Signal-based synchronization between sibling processes
- 📂 Coordinated file reading and stdout output
- ⏳ Using pause() for controlled execution flow
- ⚡ Signal-triggered child-to-child communication
Path: src/C-Unix-STD-Threads/main.c
This example demonstrates creating multiple threads to process pairs of files concurrently. Each thread reads integers from an input file, sorts them, and writes to an output file.
The goals are to understand:
- Thread creation, argument passing, and termination using
pthread_createandpthread_join - How to process independent data concurrently
- Memory management for thread arguments
- Sorting algorithms in a multithreaded environment
- Parse command-line arguments as
input_file output_filepairs. - Allocate memory for thread IDs and thread argument structures.
- Create one thread per file pair, passing a structure containing input/output filenames.
- Each thread executes the following steps:
- Opens the input file and reads integers into a buffer.
- Sorts the integers using bubble sort.
- Writes the sorted integers to the output file.
- The main thread waits for the last created thread using
pthread_jointo ensure completion.
| Header | Description | Reference |
|---|---|---|
<pthread.h> | POSIX threads API | man7.org |
<stdio.h> | File I/O and stdout | cppreference |
<stdlib.h> | Memory allocation, exit | cppreference |
<string.h> | String operations (strcpy, strlen) | cppreference |
| Function | Role | Reference |
|---|---|---|
pthread_create() | Create a new thread | man7.org |
pthread_join() | Wait for a thread to terminate | man7.org |
fopen(), fscanf(), fprintf() | File read/write operations | cppreference |
| Memory allocation (malloc/free) | Allocate memory for thread arguments and buffers | cppreference |
- ⚡ Concurrent execution using threads
- 📁 File I/O in multithreaded applications
- 🧮 Sorting algorithms executed in parallel
- 💾 Dynamic memory allocation for passing arguments safely to threads
- 🔄 Synchronization by joining threads to ensure completion
Path: src/C-Unix-STD-Threads-Files-Assert/main.c
This example demonstrates multithreaded file processing with bubble sort, using assert() to guarantee correctness of read/write operations.
The goals are to understand:
- Thread-safe processing of multiple input/output files concurrently
- Using assertions to ensure correct file read/write
- Implementing bubble sort algorithm inside threads
- Validate command-line arguments as
input_file output_filepairs (odd number of arguments, at least 3). - Allocate structures and thread IDs for all file pairs.
- Create one thread per file pair:
- Thread reads integers from input file.
- Thread sorts integers using bubble sort.
- Thread writes sorted integers to output file.
- Assertions (
assert()) verify that bytes read equal bytes written.
- Main thread waits for the last thread to finish (
pthread_join).
| Header | Description | Reference |
|---|---|---|
<pthread.h> | POSIX threads API | man7.org |
<stdio.h> | File I/O | cppreference |
<stdlib.h> | Memory allocation, exit | cppreference |
<assert.h> | Error checking | cppreference |
<string.h> | String operations | cppreference |
| Function | Role | Reference |
|---|---|---|
pthread_create() | Create thread for each file pair | man7.org |
pthread_join() | Wait for threads to finish | man7.org |
assert() | Verify correctness of read/write operations | cppreference |
fopen()/fscanf()/fprintf()/fclose() | File I/O operations | cppreference |
| Memory allocation (malloc/free) | Allocate thread arguments and buffers | cppreference |
- ⚡ Multithreading for concurrent file processing
- 📁 Safe file I/O with assertion checks
- 🧮 Bubble sort algorithm inside threads
- 💾 Dynamic memory management for thread arguments
- 🔄 Synchronization via
pthread_jointo ensure completion
Next step, start to use C_Linux examples by following this getting started guideline.
This section guides you through preparing your environment and running the C Unix & Standard Library examples presented in this collection. The steps are tailored to Linux/Unix hosts and assume a basic familiarity with compiling and executing C programs.
-
1 - Verify Prerequisites and Dependencies
Ensure your system has the necessary development tools and libraries:- GCC or Clang compiler (C99/C11 support)
- Make for build automation (optional but recommended)
- POSIX-compliant libraries (
<unistd.h>,<pthread.h>,<fcntl.h>) - Standard C libraries (
<stdio.h>,<stdlib.h>,<string.h>,<assert.h>)
Reading this carefully guarantees that each example can be compiled and executed without errors.
-
2 - Get the Source Code
Clone or download the repository containing the examples.
Ensure the folder structure under<code>src/</code>is preserved, as each example references specific file paths. -
3 - Build / Compile Examples
Compile each example individually using GCC or your preferred compiler:
gcc -o main main.c -lpthread
Some examples may require the<code>-lpthread</code>flag for thread support. Others rely on standard POSIX calls and do not require additional flags. -
4 - Run Examples
Execute each compiled binary from the command line.- Examples using fork(), exec(), or signals should be run in a terminal on a Unix-like system.
- File-based examples require input/output files to be placed in the expected paths (
<code>src/C-STD-File/file1.txt</code>, etc.). - Threaded examples may generate multiple output files concurrently; ensure write permissions in the folder.
-
5 - Explore and Modify
Feel free to adjust input files, function parameters, or the number of threads in examples to experiment and observe behavior. This is ideal for learning Unix process management, signals, and concurrent programming in C. -
6 - Clean Up / Uninstall
Remove compiled binaries and temporary files safely:
rm -f src//main
rm -f src//file*.out
This ensures your workspace remains clean while preserving the original source files.
Following these steps guarantees that you can successfully compile, run, and experiment with all examples, from **function pointers** and **file I/O** to **Unix processes**, **signals**, and **threaded programs**.
Before building or running the project, make sure you satisgy the prerequisites to run the project:
- Operating System: GNU/Linux, Windows
- Software Dependencies: GitHub, Doxygen, GNU Make, GNU C Compiler
Before building and generating documentation with C_Linux, make sure the following dependencies are installed on your system:
-
GitHub — Optional.
Even if you don’t have a GitHub account or Git installed, you can still generate documentation locally.
However, having a GitHub account and using Git is recommended for project deployment and version control. -
Doxygen — Mandatory.
Used to generate documentation from source code and Markdown files.
The project won’t build documentation without it. -
GNU Make — Mandatory.
Required to run automated build and documentation generation tasks.
Used in this project to simplify commands such as:make doc
and
make clean
-
GNU C Compiler (GCC) — Mandatory.
Required to compile all C examples in C_Linux.
Supports C99 standard and POSIX APIs.
sudo apt update sudo apt install git
After installation, verify that Git is available:
git --version
To link your project to GitHub, create a free account at:
👉 https://github.com/signup
Then configure Git with your account details:
git config --global user.name "Your Name" git config --global user.email "you@example.com"
-
Download Git for Windows from:
👉 https://git-scm.com/download/win -
Run the installer and follow the setup wizard (leave default options checked).
-
After installation, open Git Bash and verify:
git --version
-
Optionally create a GitHub account at
👉 https://github.com/signup
sudo apt update sudo apt install doxygen graphviz
Verify the installation:
doxygen --version
Optionally, you can generate a sample configuration file with:
doxygen -g
-
Download the Windows installer from:
👉 https://www.doxygen.nl/download.html -
Run the
.exefile and follow the setup wizard. -
After installation, open Command Prompt and check:
doxygen --version
-
To enable UML and graphs, install Graphviz as well:
👉 https://graphviz.org/download/
GNU Make is usually preinstalled. Check it with:
make --version
If missing, install it via:
sudo apt update sudo apt install make
You can install GNU Make in one of these ways:
- Download and install MinGW from:
👉 https://www.mingw-w64.org/ - During installation, select the “mingw32-make” package.
- Add MinGW’s
bindirectory to your system PATH. - Verify installation:
mingw32-make --version
You can then rename or alias it to make for convenience.
If you have Chocolatey package manager installed:
choco install make
Check if GCC is already installed:
gcc --version
If missing, install it via:
sudo apt update sudo apt install gcc build-essential
Verify installation:
gcc --version
- Download and install MinGW-w64 from:
👉 https://www.mingw-w64.org/ - During installation, select the gcc package.
- Add the
bindirectory of MinGW to your system PATH. - Verify installation:
gcc --version
- Install WSL with a Linux distribution, e.g., Ubuntu.
- Open WSL terminal and run:
sudo apt update sudo apt install gcc build-essential gcc --version
If you have Chocolatey installed:
choco install mingw
Verify installation:
gcc --version
After installing all dependencies, verify them with:
git --version doxygen --version make --version gcc --version
If all commands return valid version numbers, you’re ready to build and document your project 🎉
💡 Tip: You can also run the
doxygen.shscript from the root directory.
It will automatically:
- Check that Doxygen is installed. If not, the script will fail ❌
- Generate a base
Doxyfileif missing- Apply the custom configuration for C_Linux
To install the project follow this setps:
A. You can download the repository from GitHub: ⬇️ https://github.com/Unix69/README-Template/archive/refs/heads/main.zip
manually or by opening a terminal into your project destination directory, and running the following commands:
mkdir project-root #create the project root directory cd project-root #change to the project root directory wget https://github.com/Unix69/C_Linux/archive/refs/heads/master.zip #make an http get request to get the project repository ** zip file ** unzip master.zip #unzip the project master.zip file cp -R master/ ./ #copy all files recursively from the unziped master directory to your project root directory rm -rf master master.zip #remove the unziped master directory and master.zip file
B. You can clone the repository from GitHub if you have Git installed by running the following commands:
mkdir project-root #create the project root directory cd project-root #change to the project root directory clone https://github.com/Unix69/C_Linux.git #clone the project repository cp -R C_Linux/ ./ #copy all files recursively from the C_Linux directory to your project root directory rm -rf C_Linux #remove the C_Linux directory.
⬇️ Download ZIP
🐙 View on GitHub
To build C_Linux full project you have to build singularly:
- the example executables you want.
- the C_Linux project documentation.
To build the entire C Unix & Standard Library examples:
-
A. Using GNU Make
make build make link_all
Using
make buildandmake link_allallows compiling and linking all C examples insrc/automatically:make build– compiles all.cfiles insrc/into.oobject files.- Uses
$(CC) $(CFLAGS) -c $< -o $@to compile each source file individually. - Prints a message:
Compiling <file>...for each compilation. - Ensures that all object files are ready for linking in the next step.
- Uses
make link_all– links the object files in each subfolder ofsrc/into a single executable per folder.- Finds all
.ofiles in the folder usingfind $@ -maxdepth 1 -name "*.o". - Links them with
gcc $(CFLAGS) <objects> -o <folder_name>. - Prints a success message:
Executable created: <folder_name>if linking succeeds. - Creates one executable per example folder, mirroring the structure of
src/.
- Finds all
These targets provide a convenient alternative to using
find ... -exec gcc ..., as they automatically handle compilation and linking for all examples in the project. -
B. Using the GNU C Compiler
find src/ -name "main.c" -exec sh -c 'gcc -Wall -O2 "$1" -o "$(dirname "$1")/main" -lpthread && echo "$(dirname "$1")/main created" || echo "Compilation failed for $1"' _ {} \;This command recursively compiles all
main.cfiles undersrc/into executables:find src/ -name "main.c"– locate allmain.cfiles.-exec sh -c '...'– execute a shell command for each file, passing it as$1.gcc -Wall -O2 "$1" -o "$(dirname "$1")/main" -lpthread– compile with warnings, optimization, and pthread support; output in the same folder.&& echo "$(dirname "$1")/main created"– prints a success message if compilation succeeds.|| echo "Compilation failed for $1"– prints an error message if compilation fails.
If you want to compile only a single example (e.g., C-Func-pointer):
- Open a terminal in the example folder:
cd src/C-Func-pointer
- Compile using GCC (add
<code>-lpthread</code>if the example uses threads):
gcc -o main main.c -lpthread
- Run the compiled example:
./main
This approach is ideal for testing or debugging individual examples without rebuilding the entire project.
To build the project documentation, first of all you have to generate a proper Doxyfile. You have multiple ways to generate the documentation resources for the C Unix & Standard Library examples. Each approach below produces a configured Doxyfile.
./doxygen.sh(Custom Doxyfile) – Runs a setup script that:- Checks if
doxygenis installed and exits with an error message if not. - Creates a default
Doxyfileif one does not already exist in the project root. - Reads the project’s
doxygen.iniand applies tag settings intoDoxyfileautomatically. - Adds custom aliases and configuration if missing, ensuring output directory and options are set.
- Leaves you with a fully configured
Doxyfileready to generate docs via Doxygen.
- Checks if
make doc_build– Equivalent to running the setup script via the project’s Makefile:- Invokes the
doxygen.shscript using the Makefile ruledoc_build. - Prepares the
Doxyfileand applies configuration automatically without manual editing. - This approach is ideal if you already use
makefor building and want documentation integrated into the same workflow.
- Invokes the
doxygen -g Doxyfile(Standard Doxyfile):- Directly generates a **default Doxygen configuration file** named
Doxyfilewith all tags set to default values. - Useful if you prefer to edit the configuration manually, or want to start from a clean template.
- After adjustment, run
doxygen Doxyfileto generate the documentation without using the custom setup script.
- Directly generates a **default Doxygen configuration file** named
In summary:
- Use
doxygen.shormake doc_buildwhen you want an **automated, customized Doxyfile** based on your project settings; - Use
doxygen -g Doxyfilewhen you want to **manually edit a fresh configuration template** before generating docs.
Once the Doxyfile is generated and configured as you wish, to make the documentation use:
- Doxygen Open a terminal into the **root directory** and run the doxygen installed tool with your `Doxyfile`;
doxygen Doxyfile make doc– Generates documentation using the configuredDoxyfile:- Runs the
doxygencommand internally on the preparedDoxyfile. - Produces HTML output (and other formats if enabled) in the directory configured by
OUTPUT_DIRECTORY(default isdocs/html). - Copies optional assets (e.g., image resources) into the documentation output folder after generation.
- This target completes the documentation build process started by
doc_buildordoxygen.sh.
- Runs the
To configure the C_Linux project, before you generate the documentation, you can:
- Modify Doxygen's options by:
A. Doxygen: Changing/Adding manually a row in ./doxygen.ini before run it again, like:
<code>
DOXY_PARAMETER = "DOXY_PARAMETER-VALUE"
</code>
B. Doxyfile: Access the Doxyfile, generated by doxygen.sh script or run the
doxygen -g Doxyfilecommand, then change Doxygen's parameters manually.
-
Modify the default Makefile and make toolchain to customize and integrate your building behaviour.
-
You can change the default Markdown
.mdfiles to customize your project markdown documentation. The default Markdown project of C_Linux is structured as follow:
After building the project and/or the documentation, you can run both the generated documentation and the compiled examples.
-
✅ The HTML documentation is available in
./docs/html/or the path specified by theOUTPUT_DIRECTORYin yourDoxyfile. -
You can open it in a browser using a command like:
xdg-open ./docs/html/index.html
(Linux/Unix) -
Or, if on macOS:
open ./docs/html/index.html
-
📌 All documentation is also fully available on GitHub as linked
.mdfiles. This allows you to navigate the examples directly online or integrate them with the Doxygen-generated HTML documentation via GitHub Pages or a similar static site.
Using C-Func-pointer as an example:
-
Navigate to the folder where the executable was generated:
cd src/C-Func-pointer
-
Run the executable:
./main
-
If compilation was done via
make buildormake link_all, the executable is typically in the same folder as themain.cfile.
You can run all executables in the src/ tree using a one-liner shell command:
find src/ -mindepth 1 -type f -executable -name "main" -exec sh -c './{} || echo "Execution failed for {}"' \;
- This command:
- Searches for all
mainexecutables insidesrc/subfolders. - Executes each one sequentially.
- Prints an error message if the execution fails for a specific example.
- Searches for all
- Ensure you have built the examples first using
make buildand linked them withmake link_all. - The same approach works for all examples, just replace
C-Func-pointerwith the desired folder. - Documentation can be refreshed anytime with
make docafter any updates to the source code or comments. - GitHub provides a full integrated view of the documentation: both the Doxygen HTML pages and the
.mdfiles for examples are cross-linked, giving a convenient online browsing experience.
To uninstall the C_Linux project and all its generated artifacts, you have multiple options: you can use the make clean target, or remove files manually using shell commands.
The simplest way is to leverage the clean target from the Makefile:
make clean
- This command performs the following steps automatically:
- Removes all compiled object files (
*.o) insrc/. - Removes all executables created in the
src/subfolders. - Deletes the Doxygen documentation output directory (
docs/).
- Removes all compiled object files (
- It preserves your
main.c,.h,.mdand other source files, deleting only build artifacts and generated documentation.
If you prefer to remove everything manually without using Make, you can execute the following shell commands:
# Remove object files
find src/ -name "*.o" -type f -exec rm -f {} \;
# Remove compiled executables
find src/ -mindepth 1 -type f ! -name "*.c" ! -name "*.txt" ! -name "*.h" ! -name "*.hpp" -executable -exec rm -f {} \;
# Remove generated documentation
rm -rf docs/
rm -f Doxyfile
- The first command finds and deletes all object files (
*.o) insrc/subfolders. - The second command removes all executables in
src/except source, header, and text files. - The third command deletes the documentation directory and optionally the generated
Doxyfile.
- Using
make cleanis the recommended approach, as it ensures a consistent cleanup according to the Makefile rules. - Manual removal is useful if you want to selectively delete artifacts or do not have Make installed.
- After cleaning, you can safely rebuild the project or regenerate documentation from scratch.
This project is licensed under the Creative Commons Attribution 4.0 International License (CC BY 4.0) .
You are free to use, modify, and share this template — just give proper credit to Giuseppe Pedone.
© 2025 Giuseppe Pedone — GitHub: Unix69
Thank you for your interest in C_Linux!
You can freely download and use the C examples. To contribute, report bugs, or suggest improvements, follow the workflow below.
- Read the CODE_OF_CONDUCT.md
- Understand the project structure
- Ensure required tools are installed: GCC, Make, Doxygen
When contributing code:
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature) - Make changes and commit with clear messages (
git commit -m "Add feature X") - Push your branch to GitHub
- Open a Pull Request (PR)
Keep style consistent, update documentation, and run tests.
Roles: FO, CEO
Contributions: `FI`, `OP`, `DE`
Email: giuseppe.pedone.developer@gmail.com
Links:
- GNU C Compiler (GCC) – Compiler for C projects
- C Programming Language – Language reference
- Linux OS – Target OS for examples
- POSIX – Standard APIs
- GNU Make – Build automation
- Doxygen – Documentation generator
Q1: Which C standard is used?
A1: All examples are written in C99.
Q2: Supported OS?
A2: POSIX-compliant systems, mainly Linux.
Q3: Can I modify and redistribute examples?
A3: Yes! All code is under GNU GPL v3.
Q4: How to compile an example?
A4: Use gcc or run make in project root.
Q5: How to report a bug?
A5: Open a GitHub Issue describing the error, affected example, and steps to reproduce.
- Go to the main repository on GitHub
- Click Fork to create your personal copy
- Create a branch dedicated to your feature:
git checkout -b feature-new-functionality - Keep it synchronized with the main project
- Ensure your branch is updated with the main branch
- Confirm all tests and checks pass
- Open a PR with:
- Clear title (e.g., "Fix: memory leak in example")
- Summary of changes
- Related issue numbers (if any)
- Wait for maintainers review
- Apply requested changes and update PR if needed
PR Guidelines
- Use concise and descriptive titles
- Include examples or references if relevant
- Avoid committing unrelated files
- Issues are for reporting bugs, requesting features, or asking questions
- Use the Issue Template if available
- Clearly describe:
- Issue type: bug / feature / question
- Steps to reproduce
- Expected vs actual behavior
- Environment: OS, version, configuration
All issues are tracked in the Issues section on GitHub.
Special thanks to the Open Source Community for providing tools and frameworks such as GCC, Linux, GNU Make, and Doxygen.
Your work empowers projects like C_Linux to exist and evolve.