<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Impletaph</title><link>https://blogsite-91e549.gitlab.io/posts/</link><description>Recent content in Posts on Impletaph</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>&lt;a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener"&gt;CC BY-NC 4.0&lt;/a&gt;</copyright><lastBuildDate>Tue, 29 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blogsite-91e549.gitlab.io/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>A Typesafe Dynamic std::vector equivalent in C</title><link>https://blogsite-91e549.gitlab.io/posts/2026/09/a-typesafe-dynamic-stdvector-equivalent-in-c/</link><pubDate>Tue, 29 Sep 2026 00:00:00 +0000</pubDate><guid>https://blogsite-91e549.gitlab.io/posts/2026/09/a-typesafe-dynamic-stdvector-equivalent-in-c/</guid><description>&lt;p&gt;I&amp;rsquo;m writing a game in c, and inevitably in c, you have to deal with the fact that c doesn&amp;rsquo;t have &lt;code&gt;std::vector&lt;/code&gt; or anything like it. If you want to store like items in a dynamically resizing container, you do have a few options. Let&amp;rsquo;s go on a tour.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you&amp;rsquo;re coming here from non c/c++ land, we&amp;rsquo;ll also be talking about the c-preprocessor a bit. c macros through the preprocessor perform naive text substitutions, with some limits on recursive substitutions we have to work around.&lt;/p&gt;</description><content type="html"><![CDATA[<p>I&rsquo;m writing a game in c, and inevitably in c, you have to deal with the fact that c doesn&rsquo;t have <code>std::vector</code> or anything like it. If you want to store like items in a dynamically resizing container, you do have a few options. Let&rsquo;s go on a tour.</p>
<blockquote>
<p><strong>NOTE:</strong> If you&rsquo;re coming here from non c/c++ land, we&rsquo;ll also be talking about the c-preprocessor a bit. c macros through the preprocessor perform naive text substitutions, with some limits on recursive substitutions we have to work around.</p>
</blockquote>
<h1 id="prior-art">Prior Art</h1>
<h2 id="stretchy-buffer">Stretchy Buffer</h2>
<p>Sean Barret&rsquo;s <a href="https://github.com/nothings/stb/blob/master/deprecated/stretchy_buffer.h">stretchy_buffer.h</a> is a good contender.</p>
<blockquote>
<p><strong>NOTE:</strong> Sean Barret has since deprecated stretch_buffer.h and replaced it with <a href="https://github.com/nothings/stb/blob/master/stb_ds.h#L407">stb_ds.h</a> which contains a dynamic array implementation that is more full-featured, but operates under similar principles.</p>
</blockquote>
<p><code>stretchy_buffer</code> implements the array as a fat pointer. Fat Pointers are pointers that store a little extra data about the thing their pointing to. To illustrate the basic principle of a fat pointer, imagine we need to allocate a pointer to an object of size 16 <em>O</em> and store a piece of meta-data about it <em>m</em> of size 4. Everything is in bytes. To do this as a fat pointer, we would allocate a memory block <code>sizeof(</code><em>O</em><code>)</code> + <code>sizeof(</code><em>m</em><code>)</code> (16 + 4) for a total size of 20. We&rsquo;re going to put memory alignment issues aside for the moment. Once we have our pointer <em>p</em> of size 20, we&rsquo;ll create pointer <em>p&rsquo;</em> by moving <em>p</em> by 4 bytes.</p>
<pre tabindex="0"><code>Allocated Block
0   4   8   12  16  20 
↓   ↓   ↓   ↓   ↓   ↓
--------------------
↑   ↑ 
p → p&#39;
</code></pre><p>We now have two regions, one before the pointer of size 4, where we can store <em>m</em> and one where we can store the object <em>O</em>. Notably, this pattern preserves direct pointer access to <em>O</em>. The meta data can still be accessed with some pointer arithmetic. This pattern is commonly used for strings, where <em>O</em> is the string&rsquo;s content and <em>m</em> is the string&rsquo;s length.</p>
<pre tabindex="0"><code>0   4   8   12  16  20 
↓   ↓   ↓   ↓   ↓   ↓
--------------------
[m ][       O      ]
    ↑ 
    p&#39;
</code></pre><p><code>stretchy_buffer</code> stores two values as meta-data, the array&rsquo;s current occupancy (count) and total occupancy it can support with the amount of memory it has(cap). This is sufficient to implement automatic resizing. The other thing that makes stretchy_buffer work is that its operations are implemented as a series of macros. As you can see in this excerpt:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#define stb_sb_free(a)         ((a) ? free(stb__sbraw(a)),0 : 0)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#define stb_sb_push(a,v)       (stb__sbmaybegrow(a,1), (a)[stb__sbn(a)++] = (v))
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#define stb_sb_count(a)        ((a) ? stb__sbn(a) : 0)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#define stb_sb_add(a,n)        (stb__sbmaybegrow(a,n), stb__sbn(a)+=(n), &amp;(a)[stb__sbn(a)-(n)])
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#define stb_sb_last(a)         ((a)[stb__sbn(a)-1])
</span></span></span></code></pre></div><p>And the usage code is also ergonomic:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&#34;stretchy_buffer.h&#34;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#f92672">*</span>array <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> a <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">sb_push</span>(array, a);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">sb_push</span>(array, <span style="color:#ae81ff">6</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">sb_push</span>(array, <span style="color:#ae81ff">7</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> b <span style="color:#f92672">=</span> array[<span style="color:#ae81ff">0</span>];
</span></span></code></pre></div><p>Because you declare the pointer as pointing to the type it stores, the system is largely typesafe during normal use. The implementation is also truly tiny. If you just need &lsquo;an&rsquo; array, this will do the job, especially if you&rsquo;re not squemish about the intrusion of macros into your c code.</p>
<h2 id="macro-templates">Macro Templates</h2>
<p>So if you don&rsquo;t want to do that, or you need your array needs to do &lsquo;something&rsquo; that would be annoying to implement as macros, or if you&rsquo;re just not willing to accept that level of macro intrusion, you could emulate c++ templates by using the c preprocessor to get something a little more familiar to <code>std::vector</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">// Template Via Macro
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#define TYPE int
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#define NAME i
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&#34;template-array.h&#34;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Example Usage:
</span></span></span><span style="display:flex;"><span>i_Array array <span style="color:#f92672">=</span> <span style="color:#a6e22e">i_ArrayCreate</span>(<span style="color:#ae81ff">128</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">i_ArrayPush</span>(<span style="color:#f92672">&amp;</span>array, <span style="color:#ae81ff">5</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> item <span style="color:#f92672">=</span> array.items[<span style="color:#ae81ff">0</span>];
</span></span></code></pre></div><p>The usage code is calling into an interface generated by the preprocessor but the usage itself doesn&rsquo;t invoke the preprocessor at all. I also don&rsquo;t like that this will necessitate putting the array type definition way at the top of the file instead of at it&rsquo;s usage site. Since we wish to store many types using arrays, this will cause many files to have a long collection of array definitions at the top, and even the most diligent programmer will forget to remove the unneeded ones. This method will also generate a lot more code, and in a sense you will get the worst of both worlds because &ldquo;template-array.h&rdquo; is going to be full of less-scrutable preprocessor stuff. As just an example, forming the function <code>i_ArrayCreate()</code> will require code that looks like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> <span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">JOIN</span>(NAME,_Array)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> count;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> cap;
</span></span><span style="display:flex;"><span>    TYPE <span style="color:#f92672">*</span>items;
</span></span><span style="display:flex;"><span>} <span style="color:#a6e22e">JOIN</span>(NAME,_Array);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">JOIN</span>(NAME,_Array) <span style="color:#a6e22e">JOIN</span>(NAME, _ArrayCreate)(<span style="color:#66d9ef">int</span> initCap)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">JOIN</span>(NAME, _Array) result <span style="color:#f92672">=</span> 
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        .count <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>,
</span></span><span style="display:flex;"><span>        .cap <span style="color:#f92672">=</span> initCap,
</span></span><span style="display:flex;"><span>        .items <span style="color:#f92672">=</span> <span style="color:#a6e22e">ALLOC</span>(<span style="color:#66d9ef">sizeof</span>(TYPE)<span style="color:#f92672">*</span>initCap),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">ZERO</span>(items, <span style="color:#66d9ef">sizeof</span>(TYPE)<span style="color:#f92672">*</span>initCap);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> result;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>We&rsquo;ve already sacrificed some readability in the array implementation. Of course, the preprocessor won&rsquo;t consistently join tokens together when they are passed into a &lsquo;function-like macro invocation&rsquo; unless you use a work-around so instead of typing <code>NAME ## _Array</code>, you have to type <code>JOIN(NAME, _ARRAY)</code>, and JOIN will have the following definition:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#define JOIN3(a,b) a ## b
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#define JOIN2(a,b) JOIN3(a,b)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#define JOIN(a,b) JOIN2(a,b)
</span></span></span></code></pre></div><p>But to be honest, this is some of the more tame preprocessor manipulation I&rsquo;ve seen, so make of this what you will.
Interestingly, you can also invert this pattern. We define template parameters and then included a header that used them. But you could also include a header that defines a macro that generates the code from its arguments. i.e.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">// Template Via Macro
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&#34;template-array.h&#34;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">INSTANTIATE_ARRAY</span>(i,<span style="color:#66d9ef">int</span>,<span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Example Usage:
</span></span></span><span style="display:flex;"><span>i_Array array <span style="color:#f92672">=</span> <span style="color:#a6e22e">i_ArrayCreate</span>(<span style="color:#ae81ff">128</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">i_ArrayPush</span>(<span style="color:#f92672">&amp;</span>array, <span style="color:#ae81ff">5</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> item <span style="color:#f92672">=</span> array.items[<span style="color:#ae81ff">0</span>];
</span></span></code></pre></div><p>If you&rsquo;re curious, the inside of &ldquo;template-array.h&rdquo; will look like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#define INSTANTIATE_ARRAY(NAME, TYPE, INIT)                         \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">	typedef struct JOIN(NAME, _Array)                           \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">	{                                                           \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">		int count;                                          \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">		int cap;                                            \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">		TYPE *items;                                        \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">	} JOIN(NAME, _Array);                                       \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">	JOIN(NAME, _Array) JOIN(NAME, _ArrayCreate)(int initCap)    \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">	{                                                           \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">		JOIN(NAME, _Array) result =                         \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">		{                                                   \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">			.count = 0,                                 \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">			.cap = initCap,                             \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">			.items = malloc(sizeof(TYPE)*initCap),      \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">		};                                                  \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                                                                    \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">		for (int i = 0; i &lt; result.cap; i++)                \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">		{ result.items[i] = INIT; }                         \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                                                                    \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">		return result;                                      \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">	}
</span></span></span></code></pre></div><p>Fun.</p>
<h2 id="void-pointer-generics">Void Pointer Generics</h2>
<p>And then there&rsquo;s the old choice. My impression is that many older c collections implement their data structures using <code>void*</code> to accept any type. The implementation is trivial if annoying. The usage code is straight-forward.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">// inclusion
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&#34;c-array.h&#34;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// usage
</span></span></span><span style="display:flex;"><span>Array array <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#66d9ef">sizeof</span>(<span style="color:#66d9ef">int</span>), <span style="color:#ae81ff">128</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> a <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span>;
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ArrayPush</span>(<span style="color:#f92672">&amp;</span>array, <span style="color:#f92672">&amp;</span>a);
</span></span><span style="display:flex;"><span><span style="color:#75715e">// there are ways to make this access less terrible
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> b <span style="color:#f92672">=</span> ((<span style="color:#66d9ef">int</span><span style="color:#f92672">*</span>)array.items)[<span style="color:#ae81ff">0</span>];
</span></span><span style="display:flex;"><span><span style="color:#75715e">// or 
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> b <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ArrayGet</span>(<span style="color:#f92672">&amp;</span>b, <span style="color:#f92672">&amp;</span>array, <span style="color:#ae81ff">0</span>);
</span></span></code></pre></div><blockquote>
<p><strong>NOTE:</strong> If you&rsquo;re coming from C++, you may be surprised by the lack of casts to (void*). In c, unlike c++, all pointer types implicitly cast to void*.</p>
</blockquote>
<p>Although the implementation will involve no proprocessor nonsense, we&rsquo;ve not only fully given up type-checking, but introduced a easily stepped on error case that will be miserable to track down. You see because the array interface uses void pointers, the signiture of <code>ArrayPush()</code> will be something like</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#a6e22e">ArrayPush</span>(Array <span style="color:#f92672">*</span>array, <span style="color:#66d9ef">void</span> <span style="color:#f92672">*</span>item);
</span></span></code></pre></div><p>Then, it will use the sizeof data we gave to <code>ArrayCreate()</code> to know how many bytes to copy from pointer <code>item</code> to next slot of <code>array-&gt;items</code>. And that means&hellip;</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>Array array <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#66d9ef">sizeof</span>(<span style="color:#66d9ef">int</span>), <span style="color:#ae81ff">128</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">long</span> <span style="color:#66d9ef">long</span> <span style="color:#66d9ef">int</span> a <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// type mismatch long long int vs int
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// No warning or error, but will create malformed data.
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">ArrayPush</span>(<span style="color:#f92672">&amp;</span>array, <span style="color:#f92672">&amp;</span>a);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> <span style="color:#66d9ef">struct</span> GiantStructThing
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//...
</span></span></span><span style="display:flex;"><span>} GiantStructThing;
</span></span><span style="display:flex;"><span>GiantStructThing giantStruct <span style="color:#f92672">=</span> {<span style="color:#ae81ff">0</span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// It won&#39;t warn you about this either.
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">ArrayPush</span>(<span style="color:#f92672">&amp;</span>array, <span style="color:#f92672">&amp;</span>giantStruct);
</span></span></code></pre></div><p>We no longer detect any type mismatches when adding to the array. Which is, as I would call it, an oof.</p>
<h1 id="a-proposed-solution-partial-generics">A Proposed Solution: Partial Generics</h1>
<p>I have implemented and am using a compromise solution that I believe provides the best of these properties, which I&rsquo;m calling Partial Generics.</p>
<p>My solution comes from the following insights:</p>
<ol>
<li>We need type-checking only for operations that actually read or write elements in the array, from the outside.</li>
<li>Therefore, operations that don&rsquo;t copy items into or out of the array don&rsquo;t need type-checking.</li>
<li>Moving items internally to the array can be done safely using sizeof and/or alignof information.</li>
<li>For many operations, we can return an index rather than the value, and then have the usage code perform a typesafe access.</li>
<li>We could implement a dynamic array that can be accessed through a typed pointer to preserve type-checking, but has other operations invoked through generic void pointers using stored size and layout info.</li>
</ol>
<p>The Partially Generic Array takes the form of a fat pointer where the meta-data item is an <code>ArrayHeader</code> struct that stores information like occupancy, capacity, and grow factor. In my code base it also stores some information related to allocator, and to other features intrusively implemented as part of the array.</p>
<pre tabindex="0"><code>{ArrayInfo} | Item 0 | Item 1 | Item 2 | ...
              ⬑ Pointer to array points here.
</code></pre><p>Let&rsquo;s take a look at usage code.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">// inclusion
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&#34;array.h&#34;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// usage
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// creation/init
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#f92672">*</span>array <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#66d9ef">sizeof</span>(<span style="color:#f92672">*</span>array), <span style="color:#ae81ff">128</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// add item
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> slot <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayReserve</span>((<span style="color:#66d9ef">void</span><span style="color:#f92672">**</span>) <span style="color:#f92672">&amp;</span>array, <span style="color:#ae81ff">1</span>);
</span></span><span style="display:flex;"><span>array[slot] <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// add multiple items
</span></span></span><span style="display:flex;"><span>slot <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayReserve</span>((<span style="color:#66d9ef">void</span><span style="color:#f92672">**</span>) <span style="color:#f92672">&amp;</span>array, <span style="color:#ae81ff">2</span>);
</span></span><span style="display:flex;"><span>array[slot] <span style="color:#f92672">=</span> <span style="color:#ae81ff">7</span>;
</span></span><span style="display:flex;"><span>array[slot<span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>] <span style="color:#f92672">=</span> <span style="color:#ae81ff">6</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// read
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> a <span style="color:#f92672">=</span> array[<span style="color:#ae81ff">0</span>];
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> b <span style="color:#f92672">=</span> array[<span style="color:#ae81ff">1</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// generic function
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">ArraySort</span>(array);
</span></span><span style="display:flex;"><span><span style="color:#75715e">// similarly: ArrayClear(array);
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// remove
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">ArrayRemove</span>(array, <span style="color:#ae81ff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// info
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> count <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCount</span>(array);
</span></span></code></pre></div><p>The create function takes as input the memory attributes of the member type, and an initial capacity. It uses those memory attributes to place the meta data in the fat pointer, and then returns the pointer to the block of memory containing the array&rsquo;s members.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">void</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#66d9ef">size_t</span> itemSize, <span style="color:#66d9ef">size_t</span> itemAlign, <span style="color:#66d9ef">size_t</span> initCap)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">size_t</span> headerSize <span style="color:#f92672">=</span> ((<span style="color:#66d9ef">sizeof</span>(ArrayHeader)<span style="color:#f92672">/</span>itemSize<span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>)<span style="color:#f92672">*</span>itemSize;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">size_t</span> headerDiff <span style="color:#f92672">=</span> headerSize <span style="color:#f92672">-</span> <span style="color:#66d9ef">sizeof</span>(ArrayHeader);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    ArrayHeader <span style="color:#f92672">*</span>header <span style="color:#f92672">=</span> (ArrayHeader<span style="color:#f92672">*</span>) <span style="color:#a6e22e">malloc</span>(itemSize<span style="color:#f92672">*</span>initCap<span style="color:#f92672">+</span>headerSize);
</span></span><span style="display:flex;"><span>    header <span style="color:#f92672">=</span> (ArrayHeader<span style="color:#f92672">*</span>)(((<span style="color:#66d9ef">char</span><span style="color:#f92672">*</span>)header) <span style="color:#f92672">+</span> headerDiff);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">*</span>header <span style="color:#f92672">=</span> (ArrayHeader)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        .count <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>,
</span></span><span style="display:flex;"><span>        .cap <span style="color:#f92672">=</span> initCap,
</span></span><span style="display:flex;"><span>        .itemSize <span style="color:#f92672">=</span> itemSize,
</span></span><span style="display:flex;"><span>        .itemAlign <span style="color:#f92672">=</span> itemAlign,
</span></span><span style="display:flex;"><span>        .growFactor <span style="color:#f92672">=</span> <span style="color:#ae81ff">4</span>,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> header<span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The reserve function is called to find out what slot a new item should go into. It checks the capacity of the array and grows it if necessary, grows the array to be able to contain the new items. It can be called once to reserve space for reserveCount contiguous elements on the end of the array.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">size_t</span> <span style="color:#a6e22e">ArrayReserve</span>(<span style="color:#66d9ef">void</span> <span style="color:#f92672">**</span>array, <span style="color:#66d9ef">size_t</span> reserveCount)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    ArrayHeader <span style="color:#f92672">*</span>header <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayGetHeader</span>(<span style="color:#f92672">*</span>array);
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">assert</span>(reserveCount <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// do we need to resize?
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">size_t</span> oldCount <span style="color:#f92672">=</span> header<span style="color:#f92672">-&gt;</span>count;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">size_t</span> avail <span style="color:#f92672">=</span> header<span style="color:#f92672">-&gt;</span>cap <span style="color:#f92672">-</span> header<span style="color:#f92672">-&gt;</span>cap;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> (avail <span style="color:#f92672">&lt;</span> reserveCount)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> (header<span style="color:#f92672">-&gt;</span>growFactor <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">// error
</span></span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">size_t</span> newArrayCap <span style="color:#f92672">=</span> header<span style="color:#f92672">-&gt;</span>cap;
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> (newArraycap <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>        { newArrayCap <span style="color:#f92672">=</span> header<span style="color:#f92672">-&gt;</span>growFactor; }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// increase cap using growFactor until big enough
</span></span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">while</span> (newArrayCap <span style="color:#f92672">&lt;</span> header<span style="color:#f92672">-&gt;</span>count <span style="color:#f92672">+</span> reserveCount)
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            newArrayCap <span style="color:#f92672">*=</span> header<span style="color:#f92672">-&gt;</span>growFactor;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// reallocate and move header pointer
</span></span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">size_t</span> headerSize <span style="color:#f92672">=</span> ((<span style="color:#66d9ef">sizeof</span>(ArrayHeader)<span style="color:#f92672">/</span>header<span style="color:#f92672">-&gt;</span>itemSize)<span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>)<span style="color:#f92672">*</span>header<span style="color:#f92672">-&gt;</span>itemSize;
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">size_t</span> headerDiff <span style="color:#f92672">=</span> headerSize <span style="color:#f92672">-</span> <span style="color:#66d9ef">sizeof</span>(ArrayHeader);
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">size_t</span> newArraySize <span style="color:#f92672">=</span> headerSize <span style="color:#f92672">+</span> header<span style="color:#f92672">-&gt;</span>itemSize<span style="color:#f92672">*</span>newArrayCap;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">void</span> <span style="color:#f92672">*</span>base <span style="color:#f92672">=</span> (<span style="color:#66d9ef">void</span><span style="color:#f92672">*</span>) (((<span style="color:#66d9ef">char</span><span style="color:#f92672">*</span>)array)<span style="color:#f92672">-</span>headerSize);
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">void</span> <span style="color:#f92672">*</span>np <span style="color:#f92672">=</span> <span style="color:#a6e22e">realloc</span>( header<span style="color:#f92672">-&gt;</span>allocator, base, newArraySize);
</span></span><span style="display:flex;"><span>        header <span style="color:#f92672">=</span> (<span style="color:#66d9ef">void</span><span style="color:#f92672">*</span>) (((<span style="color:#66d9ef">char</span><span style="color:#f92672">*</span>)np) <span style="color:#f92672">+</span> headerDiff);
</span></span><span style="display:flex;"><span>        header<span style="color:#f92672">-&gt;</span>cap <span style="color:#f92672">=</span> newArrayCap;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// return the slot that new elements can be copied to
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">size_t</span> index <span style="color:#f92672">=</span> header<span style="color:#f92672">-&gt;</span>count;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    header<span style="color:#f92672">-&gt;</span>cont <span style="color:#f92672">+=</span> reserveCount;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// re-write array pointer in case of realloc
</span></span></span><span style="display:flex;"><span>    <span style="color:#f92672">*</span>array <span style="color:#f92672">=</span> <span style="color:#a6e22e">HeaderGetArray</span>(header);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> index;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>You may notice that the reserve function takes as input a <code>void**</code> to the address of the array. In fat pointer implementations with actual functions, as opposed to macros that expand in place, one must sometimes pass the array, and sometimes pass the address where the pointer to the array is stored. And because of c&rsquo;s automatic casting to <code>void*</code>, and I deemed this too prone to error. If <code>ArrayReserve()</code> accepted a <code>void*</code> instead of a <code>void**</code>, it would be come trivial to make this disasterous error:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#f92672">*</span>array <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#75715e">/*...*/</span>);
</span></span><span style="display:flex;"><span><span style="color:#75715e">// correct, ArrayReserve needs to assign to the array reference it gets when the array resizes, so we have address of the array pointer.
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> slot <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayReserve</span>(<span style="color:#f92672">&amp;</span>array,<span style="color:#ae81ff">1</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// wrong, no error, fails at runtime, vulnerable to various forms of memory corruption
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//  also the normal way to pass the array to functions.
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> slot <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayReserve</span>(array,<span style="color:#ae81ff">1</span>);
</span></span></code></pre></div><p>To remove the possibility of this error, I made <code>ArrayReserve()</code> take a <code>void**</code>, which counter intuitively, is a type that other pointers <em>do not</em> implicitly cast to in c. This mild inconvience slightly damages ergonomics by forcing the users to cast the array pointer explicitly, but in my experience completely stopped this error from occuring. This is why the usage code from above calls the function with the <code>void**</code> cast. i.e.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> slot <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayReserve</span>((<span style="color:#66d9ef">void</span><span style="color:#f92672">**</span>) <span style="color:#f92672">&amp;</span>array,<span style="color:#ae81ff">1</span>);
</span></span></code></pre></div><p>But this compromise can probably be improved. More on that at the end. Another initial pain-point is the lack of a proper pushback function. This model cannot include a pushback function because the functions operating on the array accept it as a void* and copy the array items around without knowledge of their type information. ArrayPushback would have to take the form</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">void</span> <span style="color:#a6e22e">ArrayPushback</span>(<span style="color:#66d9ef">void</span><span style="color:#f92672">**</span> array, <span style="color:#66d9ef">void</span> <span style="color:#f92672">*</span>item);
</span></span></code></pre></div><p>Which would have the same issues as the void pointer generic implementation.</p>
<p><strong>. . .</strong></p>
<p>But what if we stole one more piece of Sean Barret&rsquo;s <code>stretchy_buffer</code>?</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#define ARRAY_ADD(ar,it) \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    do\
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    {\
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">        size_t index = ArrayReserve((void*)&amp;(ar), 1);\
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">        ar[index] = it;\
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    } while(0)
</span></span></span></code></pre></div><p>Hey look! There&rsquo;s no reason we can&rsquo;t use a macro <em>just</em> to perform typed pushback like array insertion.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#f92672">*</span>array <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#66d9ef">sizeof</span>(<span style="color:#f92672">*</span>array), <span style="color:#ae81ff">128</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array, <span style="color:#ae81ff">5</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array, <span style="color:#ae81ff">6</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array, <span style="color:#ae81ff">7</span>);
</span></span></code></pre></div><p>And now we have every property we were looking for. The implementation I&rsquo;m using is a bit heavier, because I add features and operations to it whenever I find one my game could use, but these are the fundamentals.</p>
<h1 id="limitations">Limitations</h1>
<p>One &lsquo;foot-gun&rsquo; that I was unable to eliminate occurs when you pass around the array. If the array is passed to a function that may add members or otherwise cause it to resize, it must be passed by address, so that the calling context receives the re-allocation. Consider the following <strong>correct</strong> case:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">void</span> <span style="color:#a6e22e">UseArray</span>(<span style="color:#66d9ef">int</span> <span style="color:#f92672">**</span>array)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// notice the lack of an &#39;&amp;&#39;
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> slot <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayReserve</span>((<span style="color:#66d9ef">void</span><span style="color:#f92672">**</span>) array, <span style="color:#ae81ff">1</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">*</span>array[slot] <span style="color:#f92672">=</span> <span style="color:#ae81ff">4</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// ...
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// init cap of 4
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#f92672">*</span>array <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#66d9ef">sizeof</span>(<span style="color:#f92672">*</span>array), <span style="color:#ae81ff">4</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// use up all the capacity
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array,<span style="color:#ae81ff">0</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array,<span style="color:#ae81ff">1</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array,<span style="color:#ae81ff">2</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array,<span style="color:#ae81ff">3</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// function adds to array, forces resize, but reallocated pointer is fine because we passed &amp;array.
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">UseArray</span>(<span style="color:#f92672">&amp;</span>array);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array,<span style="color:#ae81ff">5</span>);
</span></span></code></pre></div><p>By lack of contrast, the <strong>incorrect</strong> case looks very similar, will not be caught by the compiler, and will not be noticed by the user unfamiliar with this pattern.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">void</span> <span style="color:#a6e22e">UseArray</span>(<span style="color:#66d9ef">int</span> <span style="color:#f92672">*</span>array)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> slot <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayReserve</span>((<span style="color:#66d9ef">void</span><span style="color:#f92672">**</span>) <span style="color:#f92672">&amp;</span>array, <span style="color:#ae81ff">1</span>);
</span></span><span style="display:flex;"><span>    array[slot] <span style="color:#f92672">=</span> <span style="color:#ae81ff">4</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// ...
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// init cap of 4
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#f92672">*</span>array <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#66d9ef">sizeof</span>(<span style="color:#f92672">*</span>array), <span style="color:#ae81ff">4</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// use up all the capacity
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array,<span style="color:#ae81ff">0</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array,<span style="color:#ae81ff">1</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array,<span style="color:#ae81ff">2</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array,<span style="color:#ae81ff">3</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// function adds to array, forces resize, but reallocated pointer goes out of scope when function returns.
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">UseArray</span>(array);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// array pointer is stale, uh oh...
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">ARRAY_ADD</span>(array,<span style="color:#ae81ff">5</span>);
</span></span></code></pre></div><p>This error has not occured in my codebase, but again, likely would in a codebase where there are several or many users unfamiliar with the implementation. See more at the end.</p>
<h1 id="conclusion">Conclusion</h1>
<p>To be honest, it&rsquo;s not everything I would hope for, but it&rsquo;s good enough to use c in a modern and type-safe way, and fits my purposes. If you&rsquo;re programming c in 2026 and need an resizing array, this is what I have found to be the best set of compromises.</p>
<h1 id="addendum">Addendum</h1>
<p>I have considered implementing a version where the data pointer is stored in a structure, and therefore a pointer to the structure could be safely passed around. I understand this pattern to be common in languages like Zig and perhaps some others. The issue in this case is that we forced to choose between an array struct carrying a generic <code>void*</code>, or a neverending series of near identical array structures with typed pointers. Have fun passing them to a common function family!</p>
<p>But&hellip; Let&rsquo;s try anyway. A macro of the form</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> <span style="color:#66d9ef">struct</span> ArrayGeneric { <span style="color:#66d9ef">void</span> <span style="color:#f92672">*</span>arr; } ArrayGeneric;
</span></span><span style="display:flex;"><span><span style="color:#75715e">#define DECLARE_ARRAY(type) union { ArrayGeneric gen; type *items; };
</span></span></span></code></pre></div><p>declares a type that can be used in both ways</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) array <span style="color:#f92672">=</span> { .gen <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#75715e">/* ... */</span>) };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// both are type safe
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// ArrayReserve() takes typechecked ArrayGeneric*
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">ArrayReserve</span>(<span style="color:#f92672">&amp;</span>array.gen,<span style="color:#ae81ff">1</span>);
</span></span><span style="display:flex;"><span><span style="color:#75715e">// array.items is of type int*
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> item <span style="color:#f92672">=</span> array.items[<span style="color:#ae81ff">0</span>];
</span></span></code></pre></div><p>Because the two pointers are both the same size and at the same base address of all of their containing types on <em>certain</em> platforms, <code>array.gen.arr</code> and <code>array.items</code> can be used interchangably, on <em>those</em> platforms! (Platforms where all pointers are of equal size and alignment.) Despite being interchangable, they are each usable without typecasting in their various contexts.</p>
<p>But this has sacrificed a great deal in terms of ergonomics, in two ways. First in initialization, nesting the constructor in an initializer is disappointing considering how often arrays themselves are in initializer lists. Second, and much more importantly, the type of this array will not implicitly cast to other identical declarations. i.e.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">// Declaration is actually fine here as type of parameter
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">void</span> <span style="color:#a6e22e">UseArray</span>(<span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) <span style="color:#f92672">*</span>param_array)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/* do something */</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) array_1 <span style="color:#f92672">=</span> { .gen <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#75715e">/* ... */</span>) };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Here&#39;s what you can do:
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) array_2 <span style="color:#f92672">=</span> {.items <span style="color:#f92672">=</span> array_1.items};
</span></span><span style="display:flex;"><span><span style="color:#75715e">// or
</span></span></span><span style="display:flex;"><span>array_2.items <span style="color:#f92672">=</span> array_1.items;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// The compiler will yell at you about this because c is not duck-typed.
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) array_2 <span style="color:#f92672">=</span> array_1;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// The compiler will yell at you about this too
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">UseArray</span>(<span style="color:#f92672">&amp;</span>array_1);
</span></span></code></pre></div><p>If you assign by the <code>.items</code> members, it looks to me like incorrect usage, even though it&rsquo;s not. You can&rsquo;t cast it without using <code>typeof()</code>, because in <code>DECLARE_ARRAY(int) array_1;</code> the <code>DECLARE_ARRAY(int)</code> is declaring an unnamed bespoke type as part of the definition of variable <code>array_1</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) array_2 <span style="color:#f92672">=</span> (<span style="color:#75715e">/* there&#39;s only one/zero thing(s) you can put here*/</span>) array_1;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// this does work in c23 or before that with compiler extensions, but it jetisons type-checking
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) array_2 <span style="color:#f92672">=</span> (<span style="color:#a6e22e">typeof</span>(array_2)) array_1; 
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// this line declares two separate, bespoke array types that do not cast to one another.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//  doesn&#39;t work, and would also jetison type-checking if it did
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) array_2 <span style="color:#f92672">=</span> (<span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>)) array_1; 
</span></span></code></pre></div><blockquote>
<p><strong>NOTE</strong>: In case <code>typeof()</code> seems too convenient a solution, <code>typeof()</code> only became a standard language feature (not an compiler extension anymore) in c23, which was adopted in 2024.</p>
</blockquote>
<p>Typesafe-ish casting requires you to pass the address of the typed pointer member of the union, and then perform an unsafe cast. One pattern I use in C in situations like this is to try and hide the type unsafe operation behind checked one, or enforce some sort of runtime type check. Unfortunately, I think an RTTI implementation would be cumbersome in this application.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">// We lose the explicit array type but the double pointer make malformed passing less likely.
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">void</span> <span style="color:#a6e22e">UseArray</span>(<span style="color:#66d9ef">int</span> <span style="color:#f92672">**</span>param_array)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Lose type-checking entirely on this cast.
</span></span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) <span style="color:#f92672">*</span>array <span style="color:#f92672">=</span> (<span style="color:#a6e22e">typeof</span>(array)) param_array;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/* do something */</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// ...
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) array_1 <span style="color:#f92672">=</span> { .gen <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#75715e">/* ... */</span>) };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">UseArray</span>(<span style="color:#f92672">&amp;</span>array_1.items);
</span></span></code></pre></div><p>Although you could then typedef every array type you use, at the moment I have deemed this an unneccesary compromise given the lack of errors I have produced of this form, but I would certainly consider it in a team setting where most people didn&rsquo;t also write the array library. The above case, resolved with typedefs, would look like this.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> <span style="color:#a6e22e">DECLARE_ARRAY</span>(<span style="color:#66d9ef">int</span>) i_Array;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">void</span> <span style="color:#a6e22e">UseArray</span>(i_Array <span style="color:#f92672">*</span>param_array)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/* do something */</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// no complaints from compiler
</span></span></span><span style="display:flex;"><span>i_Array array_1 <span style="color:#f92672">=</span> { .gen <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#75715e">/* ... */</span>) };
</span></span><span style="display:flex;"><span>i_Array array_2 <span style="color:#f92672">=</span> array_1;
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">UseArray</span>(<span style="color:#f92672">&amp;</span>array_1);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// if you&#39;re initializing an array that belongs to a struct it will can be initialized
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//  with the slightly less bad syntax
</span></span></span><span style="display:flex;"><span>Thing thing <span style="color:#f92672">=</span> (Thing)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  .ids.gen <span style="color:#f92672">=</span> <span style="color:#a6e22e">ArrayCreate</span>(<span style="color:#66d9ef">sizeof</span>(<span style="color:#f92672">*</span>thing.ids.items), <span style="color:#ae81ff">128</span>),  
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>This will re-add some of the top of file declarations from the Macro Templates section, away from the point of initialization for the array. If you&rsquo;re interested in adopting an array of this form, but want some added safety checks, this may be a compromise worth considering.</p>
<h1 id="next-time">Next Time</h1>
<p>Join me for something easier next time, where we&rsquo;ll discuss no-pain enums for c.</p>
]]></content></item></channel></rss>