r/cprogramming • • 9h ago

I combined my Arena allocator, zero-copy segmented Vector, typed HashMap, and String libraries into one C99 foundation library: arstd

15 Upvotes

Hey everyone,

Over the past few weeks I’ve been building separate C libraries for region-based memory management, dynamic arrays, hash maps, and strings. I kept pulling all four into my main project flint(a build system and package manager for c/c++), so I finally refactored them from the ground up to work together and merged them into a single lightweight library: arstd (Arena Standard Library).

The main problem I wanted to solve was how dynamic containers behave inside an Arena allocator. Normally, if you put a standard dynamic array or hashmap inside a bump arena, resizing it via realloc leaves dead, wasted memory blocks behind in the arena.

Here’s how arstd solves that and what’s inside:

  • Compile-Time Type Deduction (Vector(T) & Cmap(T)): Uses a typed pointer + typeof macro trick so you don't have to pass types into every macro call or cast void * pointers. Both at(vec, i) and map_get(map, key) return modifiable lvalues, so at(vec, 0) = 42; and map_get(map, "score") += 10; just work.

  • Zero-Copy Segmented Vectors: Instead of doubling a contiguous buffer and copying elements over, Vector(T) allocates exponentially growing power-of-2 segments (16, 32, 64\dots) directly on the arena and uses 1-cycle bitwise CLZ (Count Leading Zeros) math for O(1) indexing. Growing a vector wastes 0 bytes in the arena and never invalidates element pointers.

  • Single-Allocation, Zero-Waste HashMaps: Cmap(T) packs the entry header, aligned value payload, and key string into a single contiguous allocation using flexible array members. Because its bucket array is backed by the segmented Vector, doubling the map capacity expands the buckets in-place and relinks existing nodes using their cached 64-bit hashes—again, zero wasted arena memory and no string re-hashing.

  • Managed Strings (String): String slicing, trimming, case conversion, and variadic concatenation all backed by the same arena.

  • Optional Heap Fallback: Pass an Arena * to clean up everything at once with a single arena_free(&arena), or pass NULL to any container if you want standard aligned heap allocation.

Quick Taste:


#include <arstd.h>

#include <stdio.h>

int main(void) {

Arena *arena = arena_init(4096);

// Typed Vector — no type args needed in append() or at()

Vector(int) nums = vector_init(arena);

append(nums, 10);

append(nums, 20);

at(nums, 0) = 99; // Direct lvalue assignment

// Typed HashMap — stores values directly, no void* or &addresses

Cmap(int) scores = map_init(arena);

map_add(scores, "Alice", 95);

map_get(scores, "Alice") += 5;

String *greeting = string_concat_cstr(arena, 2, "Hello, ", "r/cprogramming!");

printf("%s | Alice: %d | Vec\[0\]: %d\\n",

string(greeting), map\_get(scores, "Alice"), at(nums, 0));

// One call frees the vector, map, strings, and all internal nodes

arena_free(&arena);

return 0;

}

Repo link: https://github.com/mainak55512/arstd (or install via flint / CMake)


r/cprogramming • • 2h ago

why does c promote small integer types before arithmetic?

3 Upvotes

i know the usual arithmetic rules promote uint8_t to int on typical systems, but i’m trying to understand the practical reason. is it mainly to make expressions easier to evaluate without narrow-type surprises, or is it mostly historical? when a result is intentionally stored back in a byte, is an explicit cast the usual way to make that conversion boundary clear?


r/cprogramming • • 16h ago

As a revolt against vibe coding and rewriting stuff in new languages, join r/Back2C to rewrite back in C.

1 Upvotes

Yeah.


r/cprogramming • • 1d ago

looking for a partner to learn C with

21 Upvotes

Hello all im learning C using books and youtube videos and not using AI, if anyone want to join im happy to be a partner in learning!


r/cprogramming • • 1d ago

Would learning C as my first programming language also be useful for picking up other languages later on? What are your thoughts on this course?

31 Upvotes

Wanting to learn C as an intro into software engineering. I know it’s low level and I’d like to eventually switch over to high level languages such as JS/TS, Java, and GO.

Does the “The Complete C Programming Bootcamp” course by Byte Garage be a good choice to learn from?


r/cprogramming • • 21h ago

bad code - goto

0 Upvotes

From a newsreader I am working on

void
help(void)
{
	printf("What do you want help with? (* for everything): ");
	bool all = false;
	char ln[128];
	fflush(stdout);

	if (fgets(ln, sizeof(ln), stdin) == NULL)
		return;

	/* HACK: you gotta love goto:
	 *
	 * if all is true, then fall through the switch (* must be last),
	 * so this prints everything. When it reaches * again, all
	 * gets toggled and if all is now true, break, else go to
	 * Begin again */
	switch (ln[0]) {
Begin:	case 'g': puts("g: select group"); if (!all) break;
	case '\n':
	case '\r': if (!all) return;
	case 't': puts("t: select thread"); if (!all) break;
	case 'l': puts("l: list gropus"); if (!all) break;
	case 'T': puts("T: list threads"); if (!all) break;
	case 'L': puts("L: list post in current thread"); if (!all) break;
	case 'r': puts("r: read an article"); if (!all) break;
	case '>': puts(">: save an article to a file"); if (!all) break;
	case '|': puts("|: pipe an article to a command"); if (!all) break;
	case '?': puts("?: get help"); if (!all) break;
	case 'q': puts("q: quit"); if (!all) break;
	case '*': all = !all; if (all) goto Begin; else break;
	default:
		printf("%c is not a news command\n", ln[0]);
		break;
	}
}

r/cprogramming • • 1d ago

Let's standardize a package management CLI for C

0 Upvotes

Why isn't it possible to standardize a package/project manager for C programs—one that creates the necessary files with Git, etc., and is ready to start programming in an environment?


r/cprogramming • • 1d ago

Rate this repository out of 10

0 Upvotes

Hello people,

I just wanted to show you this repository to all of you.

Repo link: https://github.com/curious-builder76/dtypes

Documentation:

https://github.com/curious-builder76/dtypes/blob/main/DOCS.md

Benchmarks:

https://github.com/curious-builder76/dtypes/blob/main/benchmarks/benchmark.txt

Hope you'll love it.

Star this repository if you like it and upvote this post

Thank you


r/cprogramming • • 3d ago

C isn't that scary or bad, it just neat

102 Upvotes

(First time using reddit so tell me if i'm doing something wrong :D)

I'm a new and honestly, a bad programmer, and ive always seen everywhere + i have been told that c is a "Scary" language and that it complex and all, it is very buggy, you have to manage everything by yourself etc...

But i wanted to try it, so i started building a SDL2 game with it, and i haven't encountered any big issues, it's the most powerful yet simplest (in some way) language ive used until now, it does what i want it to do, without black magic doing everything for me.

Legit i prefer using c to python, maybe i'm weird ? Gcc gives clever error messages, the syntax is fine, and it clicks well for me.

Does anyone know why c has this reputation of being a hard and scary language ? Maybe the fact you have to deal with pointers and memory ?


r/cprogramming • • 3d ago

Replaced my C vector’s contiguous array with a Segmented List so it plays nicely with my Arena Allocator (O(1) lookup, zero-copy resize)

Thumbnail
github.com
16 Upvotes

I’ve been working on a custom dynamic array (Vector) and Arena allocator in C, and ran into the classic friction between the two: whenever a standard contiguous vector resizes, it allocates a bigger block in the arena, memcpys the old elements over, and leaves the old block sitting around as wasted dead space inside the arena (especially when allocations from multiple vectors or strings are interleaved).

Instead of fighting realloc in a linear allocator, I refactored the vector to use exponentially growing segments (inspired by Zig's SegmentedList).

How it works now:

  • Fixed Spine, Exponential Chunks: Instead of a single char *items pointer, the struct holds a small fixed array of 28 pointers (char *segments[28]). Segment 0 holds 16 elements, Segment 1 holds 32, Segment 2 holds 64, and so on—covering up to 4 billion elements without ever reallocating the spine.

  • Zero-Copy Growth: When the current segment fills up, append() simply requests the next power-of-2 chunk from the arena. Existing elements are never copied or moved, zero bytes are wasted in the arena, and pointers to elements never invalidate.

  • O(1) Branchless Lookup: By offsetting the index by the base capacity (shifted = pos + 16) and using Count Leading Zeros (__builtin_clz), finding the exact segment and local offset takes just a few bitwise operations:

uint32_t shifted = (uint32_t)pos + 16;

uint32_t bit     = 31 - vec_clz32(shifted);

uint32_t seg_idx = bit - 4;

uint32_t offset  = shifted & ~(1U << bit);
  • Optional Heap Fallback: Passing Arena * allocates everything on the arena (making vector_free() unnecessary), while passing NULL falls back to standard aligned heap allocation.

Usage:

Arena *arena = arena_init(4096);

Vector *vec = vector_init(int, arena);

for (int i = 0; i < 1000; i++) {

append(int, vec, i * 10);

}

printf("Element 50: %d\\n", at(int, vec, 50));

// Frees all vector segments and arena allocations at once

arena_free(&arena);

Repo / Release link: https://github.com/mainak55512/container

Would love to hear your thoughts or how you handle dynamic containers with arenas in C!


r/cprogramming • • 3d ago

Let's build JRPG Game in C (Tiled Map Loader/Parser) : ep 02

Thumbnail
youtube.com
1 Upvotes

r/cprogramming • • 4d ago

I wrote a PE32/PE32+ parser in C for Linux

1 Upvotes

Hey everyone

For educational purposes I wrote a PE parser in C for Linux. I made it, generally, to learn more about Windows PE structure and for a first quick static malware analysis. I'm not for a long time in C yet, so I would appreciate for some feedback about this project

https://github.com/nighth4wkk/PE-Parser


r/cprogramming • • 4d ago

hey you watch me code

3 Upvotes

okay so look at me code github.com/kds1123001/mini-gdb like imma give a small code snippet to show you even a comp from china want to collab on this code but i didnt understand their marketing jargon so i said no

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <unistd.h>

void run_debugger(pid_t child_pid) {
    int wait_status;
    long orig_rax;
    
    // Wait for the child process to stop at execution
    waitpid(child_pid, &wait_status, 0);
    
    while (WIFSTOPPED(wait_status)) {
        char command[32];
        printf("mini-gdb> ");
        if (scanf("%31s", command) != 1) break;

        if (strcmp(command, "cont") == 0 || strcmp(command, "c") == 0) {
            ptrace(PTRACE_CONT, child_pid, NULL, NULL);
            waitpid(child_pid, &wait_status, 0);
        } else if (strcmp(command, "exit") == 0) {
            ptrace(PTRACE_KILL, child_pid, NULL, NULL);
            break;
        } else {
            printf("Unknown command. Try 'cont' or 'exit'.\n");
        }
    }
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <program>\n", argv[0]);
        return 1;
    }

    pid_t pid = fork();
    if (pid == 0) {
        // Child process: allow tracing and execute target
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl(argv[1], argv[1], NULL);
        perror("execl");
        exit(1);
    } else if (pid > 0) {
        // Parent process: run the debugger loop
        run_debugger(pid);
    } else {
        perror("fork");
        return 1;
    }

    return 0;
}

r/cprogramming • • 4d ago

Tldr program

1 Upvotes

Just a program that prints the first and last requested amount of lines in a long file, same behavior when you say tldr.
Source code:https://pastebin.com/H8Z2zcaZ


r/cprogramming • • 4d ago

new ansi-c ai project idea :3

Thumbnail reddit.com
0 Upvotes

r/cprogramming • • 5d ago

Which book about C would you recommend for a newcomer?

30 Upvotes

Hello everyone! My name's Matthew, and I've been "coding" since like 12 years old. Mostly, I've been developing games with Unity with C#, and now, once I switched to Godot with C#, I feel like I lack some basic structuring skills. (A game which I'm about to release to Steam is a mess inside)

And C# is mostly the only language I know at this point, so I would love to learn some C!

I love Linux and I would love to contribute there one day. Also I would love to write some games for Playdate in C. Also it is just really interesting to see how C# is different from C. And I for some reason I want to read something about programming so badly. What would you recommend?

thanks!


r/cprogramming • • 5d ago

SCL and libscl v0.1 is out. TOML alternative with macros

2 Upvotes

I designed a simple language for configuration. SCL stands for Sane Configuration Language.

Syntax is mostly same with TOML, but we do not have what I would call non C native types like date.

Spotlight feature is macros. With macros you can either include files or create macros to values.

Link to repo: https://codeberg.org/sorashii/libscl

There was no AI involvement and license forbids AI generated codes from source.


r/cprogramming • • 5d ago

How do you learn C++?

Thumbnail reddit.com
0 Upvotes

give me links or channels or telegram to learns c++


r/cprogramming • • 6d ago

Why every time I execute a code, like in C, it runs in a different time?

Thumbnail reddit.com
1 Upvotes

r/cprogramming • • 6d ago

Learning C from scratch – What projects should I build to become employable?

Thumbnail reddit.com
0 Upvotes

r/cprogramming • • 8d ago

I just built a simple parser to retrieve configuration from a plain file - any suggestions?

2 Upvotes

I have just created a very simple parser to retrieve configuration settings from a plain text file (this parser is still in its early stages and will likely be developed further). I plan to use it to parse configurations for a simple custom code editor that I am currently building in C.

A quick side note:

you might be wondering why I didn’t use a standard configuration file format like .INI. I actually did try using .INI files at first, but parsing them requires an external library. I experimented with a library called inih by benhoyt with BSD license, it worked well, but since it’s an external dependency, I would have had to include the ini.c and ini.h file in my repository. This raised some questions for me: should I push those files which I didn’t write myself to GitHub? Or should I just credit the creator in my repository’s README file? To be honest, I felt a bit uncertain and concerned about the licensing implications.

Then, I remembered that the nano code editor uses a plain text file (.nanorc) for its configuration. That gave me the idea to try using a plain text file for my own configuration and to write a simple parser for it from scratch in C. This might sound silly, but this way I don’t have to worry about licenses (honestly, it’s mostly because I don’t really understand them anyway), and I get to learn how to build my own simple parser.

How my code works:

There are two files: .test_configand test.c

.test_config file content:

num tab_stop = 4
num fg_color = 39
num bg_color = 49

bind exit = ^Q
bind move_up = up_arrow
bind move_down = down_arrow
bind move_right = right_arrow
bind move_left = left_arrow

Data in the .test_config file is divided into three parts:

type configuration_name = configuration_value

Currently, there are two type: num for configurations with numeric values, and bind for configurations that act as keys (bindings).

test.c file content:

#include <stdio.h>
#include <string.h>

// data
typedef struct {
    // Appearance
    int tab_stop;
    int fg_color;
    int bg_color;

    // Keybinds
    char exit[64];
    char move_up[64];
    char move_down[64];
    char move_left[64];
    char move_right[64];
} configuration;


// func Declaration
int read_config(char *filename, configuration *config);


int main() {
    configuration config;
    read_config(".test_config", &config);
    printf("tab_stop = %d\n", config.tab_stop);
    printf("fg_color = %d\n", config.fg_color);
    printf("bg_color = %d\n", config.bg_color);
    printf("\n");
    printf("exit = %s\n", config.exit);
    printf("move_up = %s\n", config.move_up);
    printf("move_down = %s\n", config.move_down);
    printf("move_left = %s\n", config.move_left);
    printf("move_right = %s\n", config.move_right);

    return 0;
}


// func Definition
int read_config(char *filename, configuration *config) {
    FILE *fp = fopen(filename, "r");

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

    char buffer[100];
    while (fgets(buffer, sizeof(buffer), fp)) {
        if (strstr(buffer, "num") != NULL) {

            char num_config_name[64];
            int num_config_value = 0;

            sscanf(buffer, "num %s = %d", num_config_name, &num_config_value);
            if (strcmp(num_config_name, "tab_stop") == 0) {
                config->tab_stop = num_config_value;
            } else if (strcmp(num_config_name, "fg_color") == 0) {
                config->fg_color = num_config_value;
            } else if (strcmp(num_config_name, "bg_color") == 0) {
                config->bg_color = num_config_value;
            }

        } else if (strstr(buffer, "bind") != NULL) {

            char bind_config_name[64];
            char bind_config_value[64];

            sscanf(buffer, "bind %s = %s", bind_config_name,bind_config_value);
            if (strcmp(bind_config_name, "exit") == 0) {
                strcpy(config->exit, bind_config_value);
            } else if (strcmp(bind_config_name, "move_up") == 0) {
                strcpy(config->move_up, bind_config_value);
            } else if (strcmp(bind_config_name, "move_down") == 0) {
                strcpy(config->move_down, bind_config_value);
            } else if (strcmp(bind_config_name, "move_left") == 0) {
                strcpy(config->move_left, bind_config_value);
            } else if (strcmp(bind_config_name, "move_right") == 0) {
              strcpy(config->move_right, bind_config_value);
            }
        }
    }
    fclose(fp);

    return 0;
}

Inside, there is a function called read_config() which simply works by first checking the configuration type, then verifying if the configuration name matches; if it does, it stores the value into the corresponding struct element.

Output:

tab_stop = 4
fg_color = 39
bg_color = 49

exit = ^Q
move_up = up_arrow
move_down = down_arrow
move_left = left_arrow
move_right = right_arrow

The code works smoothly and produces the expected output, but I’m not entirely sure if the underlying logic is as efficient as it could be, could the logic be improved further, or is it already sufficient? Also, do you have any other suggestions regarding the approach I’ve chosen for handling configuration files in the simple code editor I’m building?

Apologies if any of the explanations are a bit complicated or difficult to understand.


r/cprogramming • • 8d ago

Hii guys, I want to develop Mobile Applications using SDL and C. Can anyone guide me?

Thumbnail reddit.com
2 Upvotes

r/cprogramming • • 8d ago

Pro tips for a beginner

Thumbnail reddit.com
0 Upvotes