Exercise 3: Structs & Dynamic Memory

Due:   Wednesday, July 8 by 11:59 pm
Rating:   2 (note)
Learning Objectives:

Warm-Up Questions

This exercise includes a short, graded and required warm-up in questions.txt (in the starter). It is a set of conceptual questions about pointers, structs, memory ownership, and how a multi-file C program is built.

Answer the questions before you start writing code. You will be graded on correctness. However, you can freely discuss the answers with other students. Submit your completed questions.txt along with your code.

Problem Description

In this exercise you will build a small Point3d module in C. You will define a struct type that bundles three integer coordinates, write a handful of functions that create, transform, and inspect points, and split the work across three files with a main that tests everything. The specifics of the type and each function are described below.


The Point3d type

Define a new structured type named Point3d that groups together three int32_t fields for the x, y, and z coordinates. Use typedef to give an alias to your struct. When you are done you should be able to declare a point with syntax like Point3d p = ...;.

Do not use typedef to create a pointer alias such as Point3dPtr. While it is acceptable (and common) to typedef a pointer, it will break our autograder for this exercise. Instead, you should write Point3d* explicitly wherever you need a pointer.


Function: Point3d_Allocate

This function takes three int32_t arguments and hands back a heap-allocated point. It should malloc room for a single Point3d, store the three arguments into the x, y, and z fields, and return a pointer to that allocation. Think carefully about what should happen if the allocation does not succeed.


Function: Point3d_Scale

This function takes a Point3d* and a single int32_t value. It should multiply each of the pointed-to struct's x, y, and z fields by that value, changing the struct in place, and return nothing. For the sake of the autograder, do not return a bool here, even though doing so would be a reasonable design decision.


Function: Point3d_GetOrigin

This function takes no arguments and produces the origin. It should build a Point3d whose x, y, and z are all zero and return a copy of that struct (not a pointer).


Testing with main

Write a main function that runs at least one automated test on each of the functions above. Before you start, read the "Testing" part of the Implementation Notes below very carefully so that you understand what an automated test means in this context.


File structure

Modularize your work nicely across three files:

  • Point3d.h should contain the struct definition and the function declarations related to Point3d.
  • Point3d.c should contain the function definitions.
  • ex3.c should contain the main that tests your functions.

Compilation

While testing, you can compile your program into an executable called ex3 with a single command. Your code lives in three files, but only the two .c source files are named here, since each of them #includes the Point3d.h header:

$ gcc -Wall -g -std=c17 -o ex3 ex3.c Point3d.c

Implementation Notes

Error Handling & Robustness

As part of this exercise, you will have to make design decisions about how to handle errors. Be sure to take some time and reason about what arguments might be problematic for each function. Be sure to handle other types of errors, like the case in which malloc fails. Whatever decisions you make, be sure to document them appropriately. You may, however, ignore any possible integer overflow errors.

Memory Cleanup

Make sure your main frees any memory that was dynamically allocated, even when handling edge cases. We will be using valgrind (valgrind --leak-check=full ./ex3) to check for memory leaks and other memory issues.

Testing

For the purposes of this exercise, it is enough for you to write code that makes use of all of the functions that you wrote and verifies that the struct members contain the correct values at each step. When an error is encountered during testing, you should immediately return an appropriate status code to indicate failure in addition to printing an error message. This signals an error to the parent process (this is what makes it automated) and is easier to detect than having to manually scan over your program output, especially if you have a lot of tests.

Your main counts as testing code for your Point3d module, and testing code is the only place where assert() is allowed, though you are not required to use it.

Style Focus

General

For the sake of our autograder, make sure that your function and type names match the specifications exactly, including capitalization. You should write comments explaining the behaviour and purpose of the struct and functions you define. Be sure that the comments you write document how errors are handled.

Multiple files

Make sure to include header guards, where appropriate, and that you place the function block comments in the appropriate place.

Submission

Submit the following files by creating an ex3-submit tag in your exercise repo before the assignment deadline. They must be located at the exact paths listed below, including capitalization:

  • ex3/ex3.c
  • ex3/Point3d.h
  • ex3/Point3d.c
  • ex3/questions.txt

Requirements for Full Credit

For full credit, your code must:

  • Be split across the three files described above and compile without errors or warnings on CSE Linux machines (lab workstations, attu, or CSE home VM) using the commands in the Compilation section.
  • Have no runtime errors, memory leaks, or memory errors (gcc and valgrind).
  • Have a comment at the top of your .c file with your name(s) and CSE or UW email address(es).
  • Be pretty: the formatting, modularization, variable and function names, commenting, and so on should be consistent with class style guidelines. Additionally, the linter shouldn't have any complaints about your code (cpplint.py --clint).
  • Be robust: your code should deal with hard-to-handle/edge cases and bogus user input (if there are any) gracefully.