What is the difference between vectors and dynamically allocated arrays?

Is there a difference between a C dynamic array

int* dynamic_array = malloc(sizeof(int) * x));

and a rust vector

let mut vector: Vec<i32> = vec![0; x];

if we do not change the size of the vector?

(Does the vector have extra levels of indirection?)

Quick note: both are not arrays (in fact, C doesn’t have arrays at all).

Vector stores capacity and length additionally.

C code and Rust code do different things. C code, similar to the Rust one, would be calloc(sizeof(int), x). Rust code, similar to the C one, would he Vec::with_capacity(c).

2 Likes

No, there’s no additional indirection. A Vec<T> consists simply of the three parts: pointer to the data (*mut T), size (usize) and capacity (usize). This is also why methods such as Vec::from_raw_parts can exist (see the docs for the signature). The pointer points to a memory region for capacity-many values of type T, if the vector is full with length == capacity, then all of those are initialized.

The more “simple” dynamically-allocated-“array” type in Rust is Box<[T]>, by the way; this types does not have any unused capacity (hence that a capacity field is not needed and it consists only of the pointer and the length), so it’s comparable to an always-full Vec (and in fact, there’s cheap conversion functions between a full Vec<T> and a Box<[T]> in the standard library via the From trait).

5 Likes

It depends on what level you are asking about.

At the low level, a Rust Vector is implemented in the exact same way – it allocates a memory region that's big enough for so many elements, and then operates over the returned pointer-to-buffer. Rust's Vec type is an RAII wrapper, so it manages this allocation automatically: the buffer will be freed and all items' destructors (if any) will be run when the vector goes out of scope, and when you push() to the Vec, it will reallocate and grow the buffer if necessary.

At the high level, you would probably use the Rust Vector for the same purposes as you would use a raw malloc()'ed buffer in C. Rust is a higher-level language, and its idioms differ from C, so it makes little sense to compare such details one-to-one. You could use a raw buffer pointer in Rust, too, but you wouldn't and shouldn't – in C, you're stuck with it as there's no better option.

C does have arrays.

5 Likes

Only C++ does (std::array). C’s “arrays” are automatically coerced to pointers.

No, that is false.

First, there is a proper array type, spelled T[N] where N is an integer constant. It is possible to declare, for example, a pointer-to-array type, which is distinct from a pointer-to-pointer type.

Second, the array-to-pointer decay you are talking about is 1. not unconditional, and 2. does not mean that arrays would be the same as pointers, or that they wouldn't exist.

Array to pointer decay works in assignment and function argument position, for example. But in other contexts, e.g. when the argument of the sizeof operator, an array is absolutely, undoubtedly, an array. Demonstration.

10 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.