CMSC216 HW02: C Stack Memory and Structs
- Due: 11:59pm Sun 14-Sep-2025 on Gradescope
- Approximately 0.83% of total grade
CODE DISTRIBUTION: hw02-code.zip
CHANGELOG: Empty
Table of Contents
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()'.