CS 3x (Spring 2026) Datastructures 00: Optimizing StrArray and Extending to More Types

In this project, we will try to optimize a data structure that we previously used in our webserver.

Setup

Register for the project using the registration tool and clone the repository as explained in the setup instructions.

You MUST work solo on this project! You may not collaborate at all with anyone else! Please use the SSH link found at the picture after clicking the link in the registration email:

img

Introduction

We’ve seen the reason why we would want to encode more information in a char **, using our strarray_t. But is this implementation inefficient?

It’s been introduced in lecture that pointers can reference information that exists on the heap. While you don’t know the exact reasoning for it (take CS24 :D), iterating over pointers with addresses that are not contiguous in memory is quite expensive in terms of runtime upon dereference. To get around this, we will create a new struct which stores strings contiguously in memory and later use this in our webserver.

Arrays of Strings: A Reimplementation

You can then run make task0 to make sure you’re done.

Arrays of … who knows?: A Generalization

Our data structures so far have only supported strings. If we wanted to make an array of any other type, we’d need to copy paste our code and be very careful about updating all the types! We’d like to avoid doing this and only write code once, that can then be used for multiple types. In Java, we saw this in action with ArrayList<T>… but C doesn’t have generics or a “universal type” like Object. Instead, we have the void * type, which acts as a “pointer to an unknown type”, and can be cast to a pointer to any type.

But not all types are equivalent. For example, if we have an int * versus a strarray_t *, their freeing requirements are very different. Additionally, if we wanted to store the data contiguously (like in packed_strarray_t), these types are of different size, but the rest of the implementation would be the same.

Now we can generalize on both of these constraints! We will save the free generalization until later in the course, but for now, we can store our data size on initialization for use when “get”-ing, allowing us to make use of void * store our generic data! The free problem and what type data is being stored are left to the caller (the test cases).

You can then run make task1 to make sure you’re done.

Make sure to push to gitlab.