// does not accept any paramsint foo(void) { ... }// does accept an arbitrary number of parametersint foo() { ... }
Function Call
Function Call By Value
Function Call By Reference
Important Functions
String functions:
Function
Description
strlen
length of the string (excl. terminating \0)
strstr
locates a substring
strcpy
copies a string
strncpy
copies a string with a size limit (copies at most n bytes)
strdup
duplicates a string
strndup
duplicates a string with a size limit (copies at most n bytes)
strcmp
compares strings
strncmp
compares strings up to n characters
strtol
string→long conversion
strtoll
string→long long conversion
strtof
string→float conversion
strtod
string→double conversion
strtold
string→long double conversion
strerror
converts an error code into a human-readable string
IO functions:
Function
Description
open
opening (and possibly creating) a file
read
reading from a file
write
writing to a file
close
closing a file
Function
Description
fread
reads n elements, each s bytes long
fgets
reads a line (up to '\n')
fgetc
reads a character
fwrite
writes n elements, each s bytes long
fputs
writes a C-string
fputc
writes a character
fprintf
formatted printing
fseek
set the file position indicator
getline
reads a line into a dynamically allocated buffer
ferror
tests the error indicator of the stream (0 = no errors)
feof
tests if the stream reached end-of-file (0 = not reached)
clearerr
resets error and end-of-file indicators
fileno
returns the file descriptor of a stream e.g. fileno(stdout) = 1
fflush
enforces writing of buffered data to the file
fclose
flushes the stream and closes it
Keyword
static
#include <stdio.h>void counter() { // initialization happens only once at program start static int count = 0; // without 'static', 'count' would reset to 0 every time count++; printf("Function has been called %d times\n", count);}
volatile tells the compiler not to optimise anything that has to do with the volatile variable.
There are at least three common reasons to use it, all involving situations where the value of the variable can change without action from the visible code:
When you interface with hardware that changes the value itself
when there’s another thread running that also uses the variable
when there’s a signal handler that might change the value of the variable.
Let’s say you have a little piece of hardware that is mapped into RAM somewhere and that has two addresses: a command port and a data port:
// Source - https://stackoverflow.com/a/246148// Posted by Nils Pipenbrinck, modified by community. See post 'Timeline' for change history// Retrieved 2025-12-10, License - CC BY-SA 4.0typedef struct{ int command; int data; int isBusy;} MyHardwareGadget;
Now you want to send some command:
// Source - https://stackoverflow.com/a/246148// Posted by Nils Pipenbrinck, modified by community. See post 'Timeline' for change history// Retrieved 2025-12-10, License - CC BY-SA 4.0void SendCommand(MyHardwareGadget* gadget, int command, int data){ // wait while the gadget is busy: while (gadget->isBusy) { // do nothing here. } // set data first: gadget->data = data; // writing the command starts the action: gadget->command = command;}
Looks easy, but it can fail because the compiler is free to change the order in which data and commands are written. This would cause our little gadget to issue commands with the previous data-value. Also take a look at the wait while busy loop. That one will be optimised out. The compiler will try to be clever, read the value of isBusy just once and then go into an infinite loop. That’s not what you want.
The way to get around this is to declare the pointergadget as volatile. This way the compiler is forced to do what you wrote. It can’t remove the memory assignments, it can’t cache variables in registers and it can’t change the order of assignments either.
This is the correct version:
// Source - https://stackoverflow.com/a/246148// Posted by Nils Pipenbrinck, modified by community. See post 'Timeline' for change history// Retrieved 2025-12-10, License - CC BY-SA 4.0void SendCommand(volatile MyHardwareGadget* gadget, int command, int data){ // wait while the gadget is busy: while (gadget->isBusy) { // do nothing here. } // set data first: gadget->data = data; // writing the command starts the action: gadget->command = command;}
#include <stdio.h>int add(int a, int b) { return a + b;}int sub(int a, int b) { return a - b;}int main() { int (*f)(int, int); int ret; // --- Scenario A: Explicit Syntax --- // we explicitly take the address of the function using '&' f = &add; ret = f(42, 23); printf("Add result: %d\n", ret); // Output: 65 // --- Scenario B: Implicit Syntax (Decay) --- // function names 'decay' into pointers automatically, so '&' is optional. // the user snippet noted that explicit assignment is "better" (more readable). f = sub; ret = (*f)(42, 23); printf("Sub result: %d\n", ret); // Output: 19 return 0;}
#include <stdio.h>int main() { int a = 10; int b = 20; int result; // 1. 'a += 5' executes (a becomes 15). Result (15) is discarded. // 2. 'b + 10' executes (20 + 10 = 30). // 3. 'result' is assigned 30. result = (a += 5, b + 10); printf("a: %d (side effect applied)\n", a); printf("result: %d (value of second expression)\n", result); return 0;}
#include <stdio.h>#include <string.h>#include <signal.h>#include <unistd.h>void handle_signal(int signal) { const char msg[] = "\nCaught SIGINT! (Ctrl+C)\n"; write(STDOUT_FILENO, msg, sizeof(msg) - 1);}int main(int argc, char *argv[]) { // allocate the configuration structure on the stack struct sigaction sa; // initialize memory to zero // // This is vital as garbage in 'sa_mask' // or 'sa_flags' causes undefined bugs. memset(&sa, 0, sizeof(sa)); // configure the struct sa.sa_handler = handle_signal; // (optional) set flags here, e.g.: // sa.sa_flags = SA_RESTART; // register the action // // we map sigint (ctrl+c) to our // structure '&sa' // // we pass null for oldact because we don't // care about the previous state if (sigaction(SIGINT, &sa, NULL) == -1) { perror("Error configuring signal"); return 1; } printf("Program running. Press Ctrl+C to test the handler...\n"); // keep the program alive to receive signals while (1) { sleep(1); write(STDOUT_FILENO, ".", 1); // visual heartbeat } return 0;}
manpages
An async-signal-safe function is one that can be safely called from within a signal handler. Many functions are not async-signal-safe. […] In general, a function is async-signal-safe either because it is reentrant or because it is atomic with respect to signals (i.e., its execution can’t be interrupted by a signal handler).
Instead of exit(), call _exit() (exit immediately). Other signal-safe functions:
abort
exit
write
sigaction,
To avoid conflicts, you can do the following:
volatile sig_atomic_t quit = 0;void handle_signal(int signal) { quit = 1;}int main(int argc, char **argv) { ... // set up signal handler while (!quit) { /* main application loop */ } ... // additional cleanup return 0;}
Why volatile? To avoid optimisations
Why sig_atomic_t? So signals cannot interfere with read/write of the flag
Shared Memory
Initialisation:
int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);