LMU ☀️ CMSI 3801
LANGUAGES AND AUTOMATA I
HOMEWORK #5 Due: 2025-12-03

Learning Objectives

With this assignment you will demonstrate:

Readings and Videos

Please:

Instructions

Work in teams of 1 to 4 students.

Do all work in the GitHub repository you created in the previous assignment.

Remember: There must be only one official repository per group.

Repository

Add files according to the folder structure below. You will be implementing the assigned functions and classes from scratch. The test files have been written for you; follow the links to obtain them.

.
├── code/
│   ├── c/
│   │   ├── string_stack.h
│   │   ├── string_stack.c
│   │   └── string_stack_test.c
│   ├── cpp/
│   │   ├── stack.h
│   │   └── stack_test.cpp
│   ├── rust/
│   │   └── (see instructions below)

Code

In this assignment, you will be adding files for the three languages to implement a user defined data type for the famous Stack data structure. For C, you will build a stack of strings; for C++ and Rust your stack will be generic. In C and C++, you will build the stack with manually-managed array storage, resized by doubling the capacity when an attempt is made to add an element beyond the current capacity, and shrink when popping to a size below one-fourth of the current capacity. Stacks will have a maximum capacity and a minimum capacity; the minimum capacity is the same as the initial capacity, which will be 16. Do not exceed the capacity bounds when resizing. You are expected to follow best practices for information hiding, hiding not only the fields for your objects, but also your reallocation method(s). In Rust, we’ll keep things simple and require only that you wrap a Rust vector, which handles its own resizing; however, you must set a maximum capacity will be set upon initialization.

Language-specific requirements are as follows.

C
You are given a stack specification in string_stack.h and a complete test suite in string_stack_test.c. Create and write the file string_stack.c to implement the specification and pass the tests. Note the that the specification is based on returning ”response objects” for several of the operations. Information hiding is scaffolded for you in the opaque type declared in string_stack.h.

Your code needs to be free of memory leaks. As these are hard to look for in unit tests, the teaching staff will run valgrind on your program to find them. You should learn valgrind too, if time allows.

C++
You are given a complete test suite in stack_test.cpp. Because the stack abstract data type is implemented as a C++ template, and templates do not have a separate compilation step, there will be no stack.cpp file and you must create the entirety of stack.h from scratch. Information hiding will be accomplished via private data members. Errors are handled through throwing exceptions. Structure your stack.h file like so:
#include <stdexcept>
#include <string>
#include <memory>

#define MAX_CAPACITY 32768
#define INITIAL_CAPACITY 16

template <typename T>
class Stack {
  // Allocate the data array with a smart pointer, so no destructor needed
  unique_ptr<T[]> elements;
  int capacity;
  int top;

  // Prohibit copying and assignment
  // ...

public:
  // constructor ...
  // size ...
  // is_empty ...
  // is_full ...
  // push ...
  // pop ...
private:
  // reallocate ...
};
Rust
For this assignment, your stack type will be a trivial wrapper around the Rust generic Vec type. As the type is so simple, the struct, the impl, and the tests will all be in one file, stack/src/lib.rs. Unlike your C and C++ solutions, you’ll be required to add a peek method. For operations that may fail, use optionals.

To create and test your code, you will use cargo. In your rust folder, run cargo new stack --lib to create a new package, then add your code to stack/src/lib.rs.

Structure your lib.rs file as follows (using these tests):

pub struct Stack<T> {
    // ...

}

impl<T> Stack<T> {
    // ...
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_push_and_pop() {
        let mut stack: Stack<i32> = Stack::new();
        assert!(stack.is_empty());
        stack.push(1);
        stack.push(2);
        assert_eq!(stack.len(), 2);
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(1));
        assert_eq!(stack.pop(), None);
        assert!(stack.is_empty());
    }

    #[test]
    fn test_peek() {
        let mut stack: Stack<i32> = Stack::new();
        assert_eq!(stack.peek(), None);
        stack.push(3);
        assert_eq!(stack.peek(), Some(&3));
        stack.push(5);
        assert_eq!(stack.peek(), Some(&5));
    }

    #[test]
    fn test_is_empty() {
        let mut stack: Stack<String> = Stack::new();
        assert!(stack.is_empty());
        stack.push(String::from("hello"));
        assert!(!stack.is_empty());
        stack.pop();
        assert!(stack.is_empty());
    }

    #[test]
    fn test_stacks_cannot_be_cloned_or_copied() {
        let stack1: Stack<i32> = Stack::new();
        let _stack2: Stack<i32> = stack1;
        // Should get a compile error if next line uncommented
        // let _stack3: Stack<i32> = stack1; // Error: `stack1` has been moved
    }
}

Strive to use the most idiomatic constructs of each language in your solutions.

Generative AI is permitted for this assignment; however, there is no guarantee that it will produce code that meets all of the requirements. Do not try to prompt your way to working solutions. Make sure to thoroughly review and test any code produced by AI tools.

To use the supplied unit tests, make sure you’ve created the test-data folder and its associated files as described in the instructions for Homework 2. Run the tests in their corresponding code folders, with the following commands:

Exercises

In the file exercises/hw5.md, provide solutions to the following problems. You will need to do research, as not all of these topics were covered in class. For exercises that ask you for prose answers, please be comprehensive and demonstrate a broad understanding. But avoid long-winded, silly gen-ai answers. Expect deductions for verbatim copies of AI slop. Be precise and concise.

  1. Explain the meaning of each of the following C declarations.
    1. double *a[n];
    2. double (*b)[n];
    3. double (*c[n])();
    4. double (*d())[n];
  2. In C, when exactly do arrays decay to pointers?
  3. Give a short description, under 10 words each, of the following, as they are understood in the context of the C language: (a) memory leak, (b) dangling pointer, (c) double free, (d) buffer overflow, (e) stack overflow, (f) wild pointer.
  4. Explain why C++ move constructors and move assignment operators only make sense on r-values and not l-values. You can use a rough code fragment in your explanation.
  5. Why does C++ even have moves, anyway?
  6. What is the rule-of-5 in C++?
  7. What are the three ownership rules of Rust?
  8. What are the three borrowing rules of Rust?

Please use professional and well-structured Markdown formatting for your answers. Take pride in your work. Show you care.

Submission

To submit your work, choose one and only one team member to submit to BrightSpace (1) the names of all team members, (2) the URL of your private repository, and (3) an affidavit for each team member stating that they have done the assigned book readings and reviewed the aforementioned course notes pages.

Teamwork

Remember that, when working in teams, all team members should participate in generating solutions and are responsible for understanding all submitted answers. Ideally, each team member should produce individual answers for all exercises, and the team should combine them to produce the ultimate submissions.

Grading

You will be graded both on the correctness of your solutions, adherence to each language’s conventions, the following of the assignment instructions, and the cleanliness of the repository. Feedback will be in the form of deductions for such things as:

This list is not exhaustive, but should help in getting you used to paying attention to your submissions and taking pride in your work. Note that most code editors have plugins that will auto-format your code and even look for suspicious coding practices. You are strongly encouraged to use them.

Your homework submission will be the state of your repository on your main branch, at 18:00 in the America/Los Angeles time zone on the due date.