Last Updated: 2025-09-07 Sun 13:10

CMSC216 HW02: C Stack Memory and Structs

CODE DISTRIBUTION: hw02-code.zip

CHANGELOG: Empty

1 Rationale

This HW covers the basics of memory layout and C structs. Problems provide practice at creating memory diagrams and address some of the conventions associated with struct declaration, and usage. Importantly, the distinction between an "actual" struct and a pointer to a struct is covered.

Associated Reading / Preparation

From any good C resource review struct declarations.

Grading Policy

Credit for this HW is earned by taking the associated HW Quiz which is linked under Gradescope. The quiz will ask similar questions as those that are present in the QUESTIONS.txt file and those that complete all answers in QUESTIONS.txt should have no trouble with the quiz.

Homework and Quizzes are open resource/open collaboration. You must submit your own work but you may freely discuss HW topics with other members of the class.

See the full policies in the course syllabus.

2 Codepack

The codepack for the HW contains the following files:

File Description
QUESTIONS.txt Questions to answer
diagram.c C file for Problem 1
struct_demo.c Demo C file for Problem 2
struct_define.c C file to complete for Problem 2
struct_pointer_demo.c Demo file for Problem 2
struct_pointer_funcs.c C file to create for Problem 2

3 Questions

Analyze the files in the provided codepack and answer the questions given in QUESTIONS.txt.

                            ________________

                             HW02 QUESTIONS
                            ________________


Write your answers to the questions below directly in this text file to
prepare for the associated quiz. Credit for the HW is earned by
completing the associated online quiz on Gradescope.


PROBLEM 1: Memory in diagram.c
==============================

  Lecture has introduced the basic memory model that C uses where
  variables are placed in memory at runtime at locations chosen by the
  compiler.  The space required for variables is dictated by their
  type. This problem gives some practice at working with variables in
  memory and pointers.

  For each of the C blocks below, give a memory diagram of the block
  indicating memory locations and contents of cells. These blocks appear
  in the file `diagram.c' which you can modify to print results if you
  want to verify your answers.

  MAKE SURE to accurately express the standard sizes for each of the
  kinds of variables ON A 64-BIT MACHINE in your diagrams by placing
  them at appropriate memory addresses that are tightly packed. A
  reminder: on 64-bit machines, all pointers are 64 bits / 8 bytes.

  The specific order of variables appear in memory will be chosen by the
  compiler. In graded problems, so long as answers are internally
  consistent, they will receive full credit; that means allocating
  enough space for variables in whatever order is chosen and ensuring
  that pointer point at the location of the indicated variables.


A
~

  ,----
  |   // BLOCK A
  |   int a = 5;
  |   int b = 7;
  |   double x = 4.5;
  |   int *ip = &a;
  |   ip = &b;
  |   int c = *ip;
  |   *ip = 19;
  |   // DRAW MEMORY HERE 
  `----

  ,----
  | | ADDR  | SYMBOL | VAL |
  | |-------+--------+-----|
  | | #1048 | a      |     |
  | | #1044 | b      |     |
  | |       |        |     |
  | |       |        |     |
  | |       |        |     |
  `----


B
~

  ,----
  |   // BLOCK B
  |   int arr[4] = {12, 14, 16, 18};
  |   int *arp = arr;
  |   int brr = 11;
  |   arr[1] = 23;
  |   arp[3] = 29;
  |   arp = &arr[2];
  |   *arp = brr;
  |   // DRAW MEMORY HERE 
  `----

  ,----
  | | ADDR  | SYMBOL | VAL |
  | |-------+--------+-----|
  | | #2024 | arr[3] |  18 |
  | | #2020 | arr[2] |  16 |
  | |       |        |     |
  | |       |        |     |
  | |       |        |     |
  | |       |        |     |
  `----


C
~

  ,----
  |   // BLOCK C
  |   char str[8] = "hello";
  |   str[5] = 'w';
  |   char *cp = str + 6;
  |   *cp = '\0';
  |   str[0] = 'y';
  |   // DRAW MEMORY HERE 
  `----

  ,----
  | 
  | | ADDR  | SYMBOL | VAL |
  | |-------+--------+-----|
  | | #3107 | str[7] | ?   |
  | | #3106 | str[6] | ?   |
  | | #3105 | str[5] | \0  |
  | | #3104 | str[4] | o   |
  | | #3103 | str[3] | l   |
  | | #3102 | str[2] | l   |
  | | #3101 | str[1] | e   |
  | | #3100 | str[0] | h   |
  | | #3092 |     cp | ?   |
  | 
  `----


PROBLEM 2: Structs, Dots, and Arrows
====================================

  Lecture will soon discuss structs, a way to aggregate data of
  different types into a single datum. They are akin to objects in other
  programming environments but do not have methods or and public/private
  attributes for fields. There are a half dozen syntactic variants that
  declare structs but we will favor these two.
  ,----
  | typedef struct {                // most common syntax; declares new type mytype_t
  |   int an_int_field;
  |   double a_double_field;
  |   char *a_char_ptr_field;
  | } mytype_t;
  | 
  | typedef struct othertype {      // variant used when a pointer to the type being
  |   int first_field;              // defined is required such as in linked lists
  |   char second_field;
  |   struct othertype *pointer_field;
  | } othertype_t;  
  `----

  The use of `_t' at the end of struct names is an convention to
  indicate that they are a type; it is not a strict rule and some
  historical types do not end with an `_t' but in all course examples
  defined types will follow it.

  With these set up, one can declare data of the type of the struct and
  access fields of the struct using the dot notation. An example appears
  in the `struct_demo.c' file.

  ,----
  | int main(int argc, char *argv[]){
  |   mytype_t mine1;               // first struct
  |   mine1.an_int_field = 5;
  |   mine1.a_double_field = 11.6;
  |   char mychar = 'h';
  |   mine1.a_char_ptr_field = &mychar;
  | 
  |   mytype_t mine2;               // second struct
  |   mine2.an_int_field = 222;
  |   mine2.a_double_field = 333.4;
  |   mine2.a_char_ptr_field = &mychar; // points to same place as first struct does
  | 
  |   // print out the fields of the two structs
  |   printf("mine1: %d %f %p\n",
  |          mine1.an_int_field, mine1.a_double_field, mine1.a_char_ptr_field);
  |   printf("mine2: %d %f %p\n",
  |          mine2.an_int_field, mine2.a_double_field, mine2.a_char_ptr_field);
  | 
  |   return 0;
  | }
  `----


A Basic Struct Definition and Use
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  In the file `struct_define.c' below with a simple struct definition
  and use to print the fields of a struct.


B Memory Layout of Structs
~~~~~~~~~~~~~~~~~~~~~~~~~~

  Draw a memory diagram of the stack frame for `main()' in
  `struct_define.c' at the `return' line to show how the structs are
  likely to lay out in memory. Keep in mind that the compiler will
  respect the order of struct fields specified in memory with the first
  struct field declared at the earliest point in memory.

  Below is a table to help you get started.
  ,----
  | | FRAME         | Address | Symbol              |     Value |
  | |---------------+---------+---------------------+-----------|
  | | main()        |         | grumpycat.is_grumpy |           |
  | | before return |         |                     |           |
  | |               |         |                     |           |
  | |               |         |                     |           |
  | |               | #4040   | grumpycat.?         |           |
  | |               | #4039   |                     |       'N' |
  | |               | #4038   | nyancat.is_active   |       'Y' |
  | |               |         |                     |        14 |
  | |               | #4028   |                     |       0.1 |
  | |               | #4024   | nyancat.views       | 205000000 |
  `----


C Dots vs Arrows
~~~~~~~~~~~~~~~~

  The "dot" operation in C is for "field access" and is appropriate to
  use when a variable is an actual struct. C allows for pointers to data
  and when structs are pointed at, accessing their data requires first a
  dereference then a field access.  This is done via the "arrow"
  operator "->" as in `ptrstrct->fieldname'.

  In summary
  - Use . when an actual (non-pointer) struct is in use
  - Use -> when a pointer to a struct is in use

  A common use of struct pointers is when structs are passed via their
  addresses (as pointers) to a function that operates on the struct. An
  example of this is given in `struct_pointer_demo.c' which has a
  function which halves a field. Study this example which shows how to
  pass a pointer to a struct into the function and uses the Arrow syntax
  to modify the struct.

  #include <stdio.h>

  typedef struct { // most common syntax; declares new type mytype_t int
    an_int_field; double a_double_field; char *a_char_ptr_field; }
    mytype_t;

  void mytype_halve_double(mytype_t *mine){ mine->a_double_field =
    mine->a_double_field / 2.0; }

  int main(int argc, char *argv[]){ mytype_t mine1; // first struct
    mine1.an_int_field = 5; mine1.a_double_field = 11.6; char mychar =
    'h'; mine1.a_char_ptr_field = &mychar;

  mytype_halve_double(&mine1);

  // print out the fields of the two structs printf("mine1: %d %f %p\n",
  mine1.an_int_field, mine1.a_double_field, mine1.a_char_ptr_field);

    return 0; }

  Create a new file called `struct_pointer_funcs.c' and copy the
  contents your previous `struct_define.c' file with `cat_t' into it.
  Add the following two functions to the code which involve pointers to
  structs and the arrow operator and use them in the way specified.

  ,----
  | // reduces the weight of the cat to 90% of what it was
  | void cat_diet(cat_t *cat);
  | 
  | // prints all fields of the cat using a format like the following
  | // views 205000000 weight: 0.100000 age: 14 active: Y grumpy: N
  | void cat_print(cat_t *cat);
  | 
  | // age goes up by one and due to a viral birthday video, views doubles
  | void cat_birthday_viral(cat *cat);
  | 
  | 
  | // in main(), after data is initialzed as before, grumpycat goes on a
  | // diet, nyancat has a viral birthday, and both cats are printed using
  | // the new printing function.
  | // EXPECTED OUTPUT
  | // views 410000000 weight: 0.100000 age: age 15 active: Y grumpy: N
  | // views 8300000 weight: 6.750000 age: age 13 active: N grumpy: Y
  `----


D Pointers to structs in functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  Draw a memory diagram involving the stack frames for both `main()' and
  `cat_birthday_viral()' at the point in `main()' where `nyancat' has
  the `cat_birthday_viral()' function called on it. It's a good idea to
  copy over the memory diagram you previously constructed. Don't forget
  to add a stack frame for `cat_birthday_viral()'.

Author: Chris Kauffman (profk@umd.edu)
Date: 2025-09-07 Sun 13:10