c — consolidated language guide — DedSec Project
c — consolidated language guide C Typical use: Systems and low-level programming. Suggested file extension: .c . How to run / environment: cc main.c -o main && ./main. Starter example How…
C
Typical use: Systems and low-level programming.
Suggested file extension: .c.
How to run / environment: cc main.c -o main && ./main.
Starter example
#include <stdio.h>
void greet(const char *name) { printf("Hello, %s!\n", name); }
int main(void) { greet("Ada"); return 0; }
How to read it
Manage pointer lifetimes and check errors in real applications.
Common pitfall
Manage pointer lifetimes and check errors in real applications.
Learn memory layout through a bounded parser
In C, the programmer controls buffers and lifetimes. A string is a byte sequence ending in NUL, while a packet buffer is not automatically a C string. Never read a serialized multibyte integer by blindly casting arbitrary bytes to a struct pointer; alignment, padding and endianness can differ.
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
bool decode_u16_le(const uint8_t *data, size_t len, uint16_t *out) {
if (!data || !out || len < 2) return false;
*out = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
return true;
}
Compile your own code with diagnostics such as cc -std=c11 -Wall -Wextra -Wconversion -g -fsanitize=address,undefined test.c when supported. Contrast stack automatic storage and malloc allocations, and free exactly once along every owned path. A pointer plus length expresses a safer buffer contract than a bare pointer.
Lab: write a length-prefixed record parser with tests for empty data, short header, exact length and oversized count. Reference: https://en.cppreference.com/w/c and toolchain docs.
C memory safety: a bounded parser with real tests
C gives direct access to buffers; your code must maintain their bounds and lifetimes. A simple integer decoder demonstrates how to avoid reading beyond a binary input:
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
bool read_u16le(const unsigned char *p, size_t n, uint16_t *out) {
if (!p || !out || n < 2) return false;
*out = (uint16_t)p[0] | ((uint16_t)p[1] << 8);
return true;
}
Make an array with bytes 0x34, 0x12. The expected value is 0x1234 (4660). Then call with lengths 0, 1 and 2; only the third case may succeed. Verify that a null output pointer is rejected. Note that cast-before-shift avoids depending on the signedness of plain char.
Compile your own test program with warnings and, where supported, sanitizers: cc -Wall -Wextra -Wpedantic -g -fsanitize=address,undefined test.c -o test. Sanitizer availability varies by compiler and device. Never infer memory safety from “it didn't crash once”; run boundary tests and review pointer ownership.
Write down the buffer's allocated capacity, provided length and valid range. For any API accepting a pointer and size, treat size as part of the contract. Prefer size_t for array lengths and be careful when converting negative signed values to unsigned.
Passing result: correct little-endian interpretation and clean rejection of short/null inputs. Cross-check against a hex viewer on the same bytes.
C — Expanded practice workbook
Why atoi is insufficient
atoi does not report errors reliably; parsing invalid text as an integer may silently produce a misleading result. Prefer strtol with an end pointer, errno handling and an explicit range check. This function returns a success flag and writes to an output pointer only on success.
Build and observe
Save as main.c and run gcc -std=c11 -Wall -Wextra -pedantic main.c -o parser && ./parser. Expected C parser OK. Compile without defining NDEBUG during this test, because C assert calls are disabled with that macro.
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
static int parse_port(const char *s, int *out) {
if (s == NULL || out == NULL) return 0;
char *end;
errno = 0;
long n = strtol(s, &end, 10);
if (s == end || errno == ERANGE) return 0;
while (isspace((unsigned char)*end)) ++end;
if (*end != '\0' || n < 1 || n > 65535) return 0;
*out = (int)n;
return 1;
}
int main(void) {
int result = 0;
assert(parse_port(" 8080 ", &result) && result == 8080);
assert(!parse_port("abc", &result));
assert(!parse_port("65536", &result));
assert(!parse_port(NULL, &result));
puts("C parser OK");
return 0;
}
Read the safeguards
s==end identifies a missing numeric prefix. errno==ERANGE detects overflow/underflow in strtol. The while loop permits trailing whitespace but rejects trailing words; unsigned char casting protects the precondition of isspace. NULL input and output pointers are rejected before dereferencing.
Challenges and proof
Try empty text, only spaces, -1, +5, hexadecimal 0x10 under base 10, and very large integers. Add an alternative version that accepts only unsigned decimal digits (so even a leading + is rejected). Compile with sanitizers when available: -fsanitize=address,undefined -fno-omit-frame-pointer, and explain that sanitizer support varies across toolchains.
Troubleshooting
A segmentation fault is not a standard validation error. Compile warnings at maximum practical level and reproduce a minimal case. On Termux install a working C toolchain rather than assuming a desktop gcc package exists; clang may be the supplied compiler. Success: no invalid values accepted and no dereference of NULL. https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf.html
C — Practical runnable code lab
How to run the samples
These independent samples use the appropriate language toolchain. Representative command: cc -std=c11 -Wall -Wextra -pedantic {file} -o demo && ./demo. Replace placeholders with the actual filename, keep test data isolated, and do not interpret this as automatic installation.
C — Technical notes and common pitfalls
Core knowledge
- Array bounds are not automatically checked for ordinary pointer operations.
- Keep a single clear owner for allocated memory and release it exactly once.
- Check return values and lengths when reading external input; avoid unsafe unbounded string functions.
Ada
Typical use: Systems and low-level programming.
Suggested file extension: .adb.
How to run / environment: gnatmake hello.adb && ./hello.
Starter example
with Ada.Text_IO; use Ada.Text_IO;
procedure Hello is
begin
Put_Line("Hello, Ada!");
end Hello;
How to read it
Ada prioritizes strong types and clear contracts.
Common pitfall
Ada prioritizes strong types and clear contracts.
Ada — Expanded practice workbook
Read the baseline source
with Ada.Text_IO; use Ada.Text_IO;
procedure Hello is
begin
Put_Line("Hello, Ada!");
end Hello;
Relevant environment: gnatmake hello.adb && ./hello.. Verify that the matching compiler, host or simulator is available before treating output as authoritative. For scripts that can interact with personal files or systems, use a scratch workspace and read-only fixtures by default.
Detailed working objective
Define a constrained integer subtype and reject a value outside the range. Compare compile-time subtype rules with runtime Constraint_Error checks.
The failure that must be understood
Ada range checks can be affected by compiler settings and SPARK proof is distinct from plain Ada compilation. Keep exception boundaries explicit.
Odin
Typical use: Systems and low-level programming.
Suggested file extension: .odin.
How to run / environment: odin run hello.odin -file.
Starter example
package main
import "core:fmt"
main :: proc() { fmt.println("Hello, Ada!") }
How to read it
Odin is a compiled systems language with explicit procedures.
Common pitfall
Odin is a compiled systems language with explicit procedures.
Odin — Expanded practice workbook
Read the baseline source
package main
import "core:fmt"
main :: proc() { fmt.println("Hello, Ada!") }
Relevant environment: odin run hello.odin -file.. Verify that the matching compiler, host or simulator is available before treating output as authoritative. For scripts that can interact with personal files or systems, use a scratch workspace and read-only fixtures by default.
Detailed working objective
Allocate a slice and iterate it with bounds-aware indexing, then create a temporary arena allocation with a clear lifetime. Inspect context usage.
The failure that must be understood
Odin's allocator/context model is not C malloc by default. Be careful returning slices into temporary storage.
WebAssembly Text (WAT)
Typical use: Systems and low-level programming.
Suggested file extension: .wat.
How to run / environment: Validate via wat2wasm hello.wat.
Starter example
(module
(func (export "answer") (result i32)
i32.const 42))
How to read it
Exports a function; it requires a WebAssembly host to call it.
Common pitfall
Exports a function; it requires a WebAssembly host to call it.
WebAssembly_Text_WAT — Expanded practice workbook
Read the baseline source
(module
(func (export "answer") (result i32)
i32.const 42))
Relevant environment: Validate via wat2wasm hello.wat.. Verify that the matching compiler, host or simulator is available before treating output as authoritative. For scripts that can interact with personal files or systems, use a scratch workspace and read-only fixtures by default.
Detailed working objective
Implement a module with an exported add(i32,i32)->i32 and instantiate it in a local host. Compare stack instructions with source-language expressions.
The failure that must be understood
WAT is textual Wasm, not JavaScript; imports, exports and memory pages must match the embedding host. Validate with wat2wasm where available.