Lab 7 Ex3

You cannot submit for this problem because the homework's deadline is due.

Ex3. Vectors (20 marks)

The C++ standard library offers a very useful data type: std::vector. A vector is an array with dynamic size. As long as your computer has enough memory, you can store infinitely many elements in a vector without pre-claiming too much memory that you do not actually use.

For this exercise, implement a data type Vector that models a dynamic array.

We have provided you with a file Vector.h that contains a struct definition as well as declarations for six functions:

typedef struct {
    // Pointer to the beginning of dynamically allocated chunk of memory.
    int* data;
    // The actual size of the vector.
    size_t size;
    // The size of the allocated dynamic memory. capacity * sizeof(int) bytes of
    // memory is allocated.
    size_t capacity;
} Vector;

// Print a vector to stdout. The first line should be the size and capacity of
// the vector, and the second line should be all the elements of the vector. For
// the first line, use "size: %zu, capacity: %zu\n" in printf(). For the second
// line, add one space between adjacent elements. It does not matter whether the
// last element is followed by a space or not. The second line should end with
// '\n'. If size is 0, the second line should only contain '\n'.
void vector_print(const Vector* vec);

// Return an empty vector. Both size and capacity should be zero, and data
// should be NULL.
Vector create_vector(void);

// Destory the vector by freeing the dynamically allocated memory and setting
// size and capacity to 0.
void free_vector(Vector* vec);

// Append element to the end of vec. If vec's capacity is zero, first use
// malloc() to allocate a memory chunk of sizeof(int) and set capacity to 1. If
// vec's size equals capacity (i.e., the vector is full) before element is
// appended and capacity is non-zero, use realloc() to re-allocate the memory
// *such that the new capacity is twice of the old capacity* before appending
// element.
void vector_push_back(Vector* vec, int element);

// Return a const pointer to the element at index (i.e. data[index]). Check for
// out-of-bound access, and if index is out of bound, return NULL.
const int* vector_get(const Vector* vec, size_t index);

// Set data[index] to new_value. Check for out-of-bound access. If index is out
// of bound, return -1; otherwise, return 0.
int vector_set(Vector* vec, size_t index, int new_value);

Implement the three functions in a new file named Vector.c. Note that to test your function implementation, you need to write your own driver program. Submit Vector.c only!

Notes:

  • Note that vec is passed as a pointer to const when the function does not modify the vector, and is passed as a normal pointer when the function potentially modifies the vector. This is a good practice and you should follow this when writing your own code.
  • In C, the void in Vector create_vector(void); matters. It states explicitly that the function has absolutely no input argument. This is different from C++ where () has the same meaning. In C, Vector create_vector(); means the function can take arbitrary number of arguments. gcc and clang behave differently when you pass parameters to functions declared with empty parameter lists. clang emits a warning while gcc does not. Most of the time, this will not cause any issue, but it is a good practice to add this void to keep your code compatible and consistent with C++.
  • Always remember to free a dynamically allocated memory block when it is no longer needed! Otherwise you will have memory leaks.
  • We choose to return a const int* instead of int in vector_get(). This is because we want to do out-of-bound checking. If the return type is int, any return value can be regarded as valid and there exists no return value we can use to denote an error. However, every valid pointer to an int will not be a null pointer, so NULL can be used as an error return value if we return const int*s instead.
  • An int does not always take exactly 4 bytes. Its size depends on the computer architecture. This is why we use sizeof(int). C indeed has integral types of fixed size defined in <stdint.h>. Use these types when you want well-defined sizes and ranges.

We will use a driver program to test your implementation. An example driver program ex3_sample_test.c can be downloaded from Canvas, and its output is shown below:

size: 0, capacity: 0

size: 1, capacity: 1
1 
size: 2, capacity: 2
1 1 
size: 3, capacity: 4
1 1 2 
size: 4, capacity: 4
1 1 2 3 
size: 5, capacity: 8
1 1 2 3 5 
1 2 5

As long as your implementation is correct, you will pass the tests on JOJ. You do not need to worry about I/O except when implementing vector_print().

Lab 7 Exercises

Not Claimed
Status
Finished
Problems
4
Open Since
2022-06-30 18:15
DDL
2022-07-01 23:59
Extension
0.0 hour(s)