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()'.