453 words
2 minutes
memory_layout_c_rust_vector_array

link#


C언어부터 알아보자#

  • Sure. Assuming len = 10, this:
uint8_t *my_vec = calloc(len, sizeof(*my_vec));

allocates 10 bytes of heap memory, all initialized to zero.

CLI memory layout#

Stack
┌─────────────────────────────┐
│ my_vec                      │
│                             │
│ pointer ───────────────────────┐
└─────────────────────────────┘  │
                                 │
                                 ▼
Heap
┌─────────┬─────────┬─────────┬─────────┬─────────┐
│ byte 0  │ byte 1  │ byte 2  │ byte 3  │ byte 4  │
│   0     │   0     │   0     │   0     │   0     │
├─────────┼─────────┼─────────┼─────────┼─────────┤
│ byte 5  │ byte 6  │ byte 7  │ byte 8  │ byte 9  │
│   0     │   0     │   0     │   0     │   0     │
└─────────┴─────────┴─────────┴─────────┴─────────┘
   1 byte    1 byte    1 byte    1 byte    1 byte

Because:

sizeof(uint8_t) == 1

we get:

len                  = 10
sizeof(*my_vec)      = 1
calloc(10, 1)        = 10 bytes

With hypothetical addresses#

Suppose calloc() returns address 0x1000:

my_vec
   │
   │  0x1000
   ▼
Heap

Address       Value       my_vec[i]
───────────────────────────────────
0x1000        0           [0]
0x1001        0           [1]
0x1002        0           [2]
0x1003        0           [3]
0x1004        0           [4]
0x1005        0           [5]
0x1006        0           [6]
0x1007        0           [7]
0x1008        0           [8]
0x1009        0           [9]

So:

my_vec[0]

means:

*(my_vec + 0) → memory at 0x1000

and:

my_vec[5]

means:

*(my_vec + 5) → memory at 0x1005

Important distinction#

my_vec itself is not the array.

Stack                         Heap

my_vec
┌──────────────┐
│ 0x1000       │──────────────► ┌───┬───┬───┬───┬───┐
└──────────────┘                 │ 0 │ 0 │ 0 │ 0 │ 0 │
   pointer                       ├───┼───┼───┼───┼───┤
                                 │ 0 │ 0 │ 0 │ 0 │ 0 │
                                 └───┴───┴───┴───┴───┘
                                  10 bytes

This is one of the key differences from Rust’s Vec<u8>: the C pointer only tells you where the allocation begins. C does not automatically store the len alongside my_vec, which is why your code separately keeps:

size_t len = 10;

So conceptually you have:

my_vec ──► [ 0 ][ 0 ][ 0 ][ 0 ][ 0 ][ 0 ][ 0 ][ 0 ][ 0 ][ 0 ]
            └──────────────── 10 bytes ────────────────┘
len = 10

The closest C23 equivalent is a dynamically allocated array initialized to 10 zero bytes.#

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    size_t len = 10;

    unsigned char *my_vec = calloc(len, sizeof(*my_vec));

    if (my_vec == NULL) {
        return EXIT_FAILURE;
    }

    printf("my vec : [");

    for (size_t i = 0; i < len; ++i) {
        printf("%u", my_vec[i]);

        if (i + 1 < len) {
            printf(", ");
        }
    }

    printf("]\n");

    free(my_vec);

    return EXIT_SUCCESS;
}

Rust → C23 mapping#

RustC23
let my_vecunsigned char *my_vec
vec![0_u8; 10]calloc(10, sizeof(*my_vec))
u8unsigned char
my_vec.len()len
println!printf
automatic Vec cleanupfree(my_vec)

The important part is:

let my_vec = vec![0_u8; 10];

which creates a Vec<u8> containing:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

In C23:

size_t len = 10;
unsigned char *my_vec = calloc(len, sizeof(*my_vec));

calloc() is particularly appropriate here because it allocates memory and initializes all bytes to zero.

If you want the C version to be closer to Rust’s Vec abstraction (pointer + length + capacity), I can also show a C23 struct Vec implementation.

memory_layout_c_rust_vector_array
https://younghakim7.github.io/blog/posts/memory_layout_c_rust_vector_array/
Author
YoungHa
Published at
2026-09-11