Starting from:
$40

$34

CMSC216 Project 2: Bit Ops, Debugging, Data Structures

This project addresses more advanced C programming topics each in its own problem.

    1. Bit-level operations are common in C and systems programming. This assignment features a problem in which shifting and bitwise AND/OR-ing are required to complete the requirements.

    2. Debugging is also a critical skill enabled by the debugger. The second problem in the assignment makes use of the GNU Debugger, gdb, to work through a puzzle program requiring specific inputs to pass its "phases".
    3. Data structures pervade computing and getting some practice with them in C will improve one's skill at pointers and memory usage while also giving a great appreciation for garbage collected languages. A basic "map" application which maps keys to values is implemented that is backed by a hash table.

Difficulty Note

Past students have found this content to be more challenging than Project 1.

If you were pressed for time to finish Project 1, start this project as early as possible. Most students have found the first two problems (bit manipulations and debugging) only mildly challenging but run out of time on the larger third problem.

You have been warned.

2 Download Code and Setup

Download the code pack linked at the top of the page. Unzip this which will create a project folder. Create new files in this folder.

Ultimately you will re-zip this folder to submit it.

https://www.cs.umd.edu/~profk/216/p2.html    2/51
3/5/24, 8:25 PM

CMSC216 Project 2: Bit Ops, Debugging, Data Structures





File
State
Notes





thermo.h
Provided
Problem 1 header file

thermo_main.c
Provided
Problem 1 main() function for thermometer simulation

thermo_update.c
CREATE
Create this file and write required function in it to complete Problem 1

thermo_examples.sh
Sample
Prints a variety of sample runs of thermo_main

test_thermo_update.c
Testing
Problem 1 functions tests for thermo_upate.c

test_thermo_update.org
Testing
Problem 1 testing data file





puzzlebox.c
Provided
Problem 2 Debugging problem

input.txt
EDIT
Problem 2 Input for puzzlebox, fill this in





hashmap_funcs.c
CREATE
Problem 3 functions to write

hashmap_main.c
CREATE
Problem 3 main function to write

hashmap.h
Provided
Problem 3 header file

data/hash-demo.script
Data
Problem 3 sample input script to main program

data/stranger.hm
Data
Problem 3 sample hash map saved to file

data/other.script
Data
Problem 3 sample input script to main program

data/other.hm
Data
Problem 3 sample hash map saved to file

data/big.script
Data
Problem 3 sample input script to main program

data/big.hm
Data
Problem 3 sample hash map saved to file

test_hashmap.org
Testing
Problem 3 tests





Makefile
Provided
Build file to compile all programs

testy
Testing
Test running script





Makefile




As in the first assignment, a Makefile is provided as part of this project. The essential targets pertinent to each problem are described in those sections. The Makefile is equipped with a brief help listing:

    • make help Typical usage is:

https://www.cs.umd.edu/~profk/216/p2.html    3/51
3/5/24, 8:25 PM
CMSC216 Project 2: Bit Ops, Debugging, Data Structures


> make
# build all programs






> make clean
# remove all compiled items


> make zip
# create a zip file for submission


> make prob1
# built targets
associated with problem 1


> make test-prob1 testnum=5
# run problem 1
test #5 only


> make test-prob2
# run test for problem 2


> make test
# run all tests








Automated Tests

As in previous assignments, automated tests are provided and associated with problems. Each problem describes how to run tests associated with it. Generally this is done as before:


    • make test-prob1

gcc -Wall -Wno-comment -Werror -g -c batt_main.c gcc -Wall -Wno-comment -Werror -g -c batt_update.c ...

./testy test_bat_update.org

============================================================

    • test_prob1.org : Problem 1 test_batt_update and batt_main tests

    • Running 35 / 35 tests

1)
set_batt_from_ports() 0
V

: ok
2)
set_batt_from_ports() 0
P

: ok
3)
set_batt_from_ports()
7400
V
: ok
4)
set_batt_from_ports()
7400
P
: ok

    5) set_batt_from_ports() mixed STATUS V : ok

...

>> make test-prob2    # run "tests" associated with problem 2

...

>> ./puzzlebox input.txt    # same as above: run puzzlebox to test answers


3 Problem 1: Thermometer Simulation

3.1 Overview

You are tasked with writing code which will be run by a microcontroller in a digital thermometer. The hardware has the following relevant features.

A temperature sensor whose value can be accessed via a memory mapped port. In C this is presented as a global variable. Another port indicates whether the temperature should be displayed in Celsius or Fahrenheit.

A digital with a port control port; setting certain global variable will change the temperature display with User code that you will need to write to update the display based on the temperature sensor.

A simulator program with Makefile to test your code


All of the code for this problem will be written in the file thermo_update.c which you will create. Each feature of the simulated hardware and how it relates to the functions that you will write in thermo_update.c are discussed in subsequent sections.

https://www.cs.umd.edu/~profk/216/p2.html    4/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures

Temperature Sensor

A temperature sensor is attached to the thermometer and can be accessed via a C global variable. This is declared in the thermo.h header file as follows.


extern short THERMO_SENSOR_PORT;

    • Set by the sensor to indicate temperature. Value is a positive int

    • in units of 0.1 / 32 deg C above -45.0 deg C with a max of +45.0

    • deg C. Above the max, the sensor becomes unreliable and below 0

    • indicates the senor is failing.


You do not need to define this variable as it is already there. You do not need to set this variable as it is automatically changed by the hardware. Instead, you will need to access its value to determine various aspects of the temperature. Note the type which is short: positive and negatives values are present in it and the variable will have 16 bits. The temperature sensor has a limited range and uses units of 1/32 of a tenth degree above -45.0 deg C. This leads to the following equivalences.


Sensor  Celsius    Notes


    • -45.0  Minimum valid sensor value / measurable temp

    15 -45.0  Remainder rounded down

    16 -44.9  Remainder rounded up

32
-44.9
Exactly one tenth degree above -45.0 deg C
64
-44.8
Exactly two tenths degree above -45.0 deg C
320
-44.0
Exactly ten tenths = one degree above -45.0 deg C
3200
-35.0
Ten degrees above -45.0 C
14080
-1.0
44.0 degrees above -45.0
14240
-0.5
44.5 degrees above -45.0
14400
0.0
45.0 degrees above -45.0
14432
0.1
45.1 degrees above -45.0
17600
10.0
degrees above -45.0
28800
45.0
90.0 degrees above -450.0, MAXIMUM measurable temp
28801
ERR
Error: sensor out of range
29742
ERR
Error: sensor out of range
-5
ERR
Error: sensor malfunction
-1245
ERR
Error: sensor malfunction





Notice 32 units of value in the sensor are 0.1 degree Celsius starting from -45.0 deg C. The maximum value allowable is 45.0 deg Celsius which is a sensor value of 28800.

https://www.cs.umd.edu/~profk/216/p2.html    5/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures

Notice also that the temperature should be rounded appropriately:

The temperature sensor is 1/32 of a tenth degree


A sensor value of 7 rounds down to -45.0 deg C


A sensor value of 15 rounds down to -45.0 deg C


A sensor value of 16 rounds up to -44.9 deg C


A sensor value of 30 rounds up to -44.9 deg C


Temperature Display Mode

Another global variable exposes whether the user has pressed a button which toggles between displaying temperature in the two most common scales: Celsius or Fahrenheit. It also exposes whether there are internal hardware problems in which case the display should show an error.


extern unsigned char THERMO_STATUS_PORT;

    • Bit 5 indicates whether display should be in Celsius (0) or

    • Fahrenheit (1). This bit is toggled using a button on the

    • thermometer but is set using command line args in the simulator.

    • 

    • Bit 2 is 0 for normal operation or 1 for an ERROR state. When in

    • ERROR state, ERR should be shown on the display.

//

    • Remaining bits may be 0 or 1 and should be ignored as they are not

    • relevant to the display or temperature sensor.


Both bits 5 and 2 will need to be checked to adjust the display according to the documentation provided. The remaining bits are ignored.

Display Port

The thermometer has a digital display which shows the temperature. This display is controlled by a special memory area exposed as another global variable in C.


extern int THERMO_DISPLAY_PORT;

    • Controls thermometer display. Readable and writable. Routines

    • wishing to change the display should alter the bits of this

    • variable.


While listed as in int, each bit of the is actually tied to part of the thermometer display screen. When bits are set to 1, part of the display is lit up while 0 means it is not lit.

3.2 Diagrams of Display

The following diagram shows bit patterns for various symbols and how they correspond to parts of a single digit of the display. Digits are displayed by darkening certain bars in the display which correspond to certain bits in the THERMO_DISPLAY_PORT being set. 






https://www.cs.umd.edu/~profk/216/p2.html    6/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures




























































Figure 1: Correspondence of bit in THERMO_DISPLAY_PORT to bars in a single digit. The 0th bit controls the top horizontal bar, the 1th bit controls the upper left bar, and so on working generally left to right nad top down. When a bit is 1 (set), the bar will be darkened while when the bit is 0 (clear) the bar will not be displayed (shown as empty). The combinations of bits shown are the only ones that arise when showing digits for temperatures.



Notice the following.

Bits that are set (equal to 1) will turn on (darken) one bar of the display digit


https://www.cs.umd.edu/~profk/216/p2.html    7/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures

Bits that are clear (equal to 0) will turn off one bar of the digit


7 bits are required to control the display of one digit


The bits are arranged with the low order bit (bit 0) for the middle bar and remaining bits control bars starting from the top going around clockwise

Bit 0 top middle


Bit 1 top left


Bit 2 middle middle


Bit 3 top right


Bit 4 lower left


Bit 5 lower middle


Bit 6 lower right


The programmer can set bits to any pattern which will be displayed but only patterns shown correspond to symbols of interest.


Temperature is displayed with several adjacent digits along with a Celsius/Fahrenheit indicator. The diagram below shows several full temperatures along with the bits representing the digits. The bits correspond to how the global variable THERMO_DISPLAY_PORT should be set in order to make the temperature appear as it does.


















































https://www.cs.umd.edu/~profk/216/p2.html    8/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures











































































https://www.cs.umd.edu/~profk/216/p2.html    9/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures











































































https://www.cs.umd.edu/~profk/216/p2.html    10/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures











Figure 2: Full examples of how the 30 bits of the thermometer display state control which parts of the temperature are shown. Each digit follows the same pattern of bit to bar correspondence as the right-most bits. The lowest order (rightmost) bit controls the top bar of each digit and remaining bits control bars proceeding left-to-right and top down for digit. The highest order bits (28 and 29) control whether the Celsius or Fahrenheit indicators are shown. Note that both could be shown at the same time or neither shown but this should not be done for actual temperatures.


Notice the following.

You may presume that the THERMO_DISPLAY_PORT is a 32-bit integer.


30 bits are used to control the full temperature display.


Bits 0-6 control the tenths place


Bits 7-13 control the ones place


Bits 14-20 control the tens place


Bits 21-27 control the hundreds place


Bit 28 controls whether degrees Celsius is shown


Bit 29 controls whether degrees Fahrenheit is shown


Bits 30 and 31 are not used and should always be 0.


3.3 thermo_update.c: Updating the Display with User Code

Periodically the microcontroller will run code to adjust the thermometer display to show the current temperature. This function is



int thermo_update();


and it will be your job to write this function

Rather than write everything that needs to be done within thermo_update(), several helper functions will be used to divide this task into several more manageable and testable chunks. These are


int set_temp_from_ports(temp_t *temp);

int set_display_from_temp(temp_t temp, int *display);


and are described in subsequent sections.

All these function should be written in thermo_update.c.


3.4 set_temp_from_ports()


int set_temp_from_ports(temp_t *temp);

// Uses the two global variables (ports) THERMO_SENSOR_PORT and

https://www.cs.umd.edu/~profk/216/p2.html    11/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


    • THERMO_STATUS_PORT to set the fields of `temp`. If

    • THERMO_SENSOR_PORT is negative or above its maximum trusted value

    • (associated with +45.0 deg C), this function sets the

    • tenths_degrees to 0 and the temp_mode to 3 for `temp` before

    • returning 1.  Otherwise, converts the sensor value to deg C using

    • shift operations.  Further converts to deg F if indicated from

    • THERMO_STATUS_PORT. Sets the fields of `temp` to appropriate

    • values. `temp_mode` is 1 for Celsius, and 2 for Fahrenheit. Returns

    • 0 on success. This function DOES NOT modify any global variables

    • but may access them.

//

    • CONSTRAINTS: Uses only integer operations. No floating point

    • operations are used as the target machine does not have a FPU. Does

    • not use any math functions such as abs().


This function works with the struct temp_t defined in thermo.h which has the following layout.



    • Breaks temperature down into constituent parts typedef struct{

short tenths_degrees;    // actual temp in tenths of degrees

char temp_mode;    // 1 for celsius, 2 for fahrenheit, 3 for error

} temp_t;


The function set_temp_from_ports() will read the global variables mentioned above and fill in values for the struct fields of the parameter temp. To convert the temperature sensor value to a displayable temperature, one must perform some division and modulo operations.

    1. "Divide" the sensor value by 32 to get the number of tenths degrees Celsius above -45.0 deg C. Note the documentation indicates that this can be done using a shift operation as we are dividing by a power of two.

    2. Round up if the remainder is high enough. Note that when using shifting bits to emulate division by a power of 2 bits which are shifted off would be the remainder and these can be isolated with appropriate bitwise logical operations to check them.
    3. Account for the offset from -45.0 deg C by subtracting.

    4. Check THERMO_STATUS_PORT to see if conversion to Fahrenheit is needed.

    5. If conversion is needed, use the formula



farenheit = (celsius * 9) / 5 + 32;


but note that we are working in tenths degrees so adjustments may be needed. No rounding is done when converting from Celsius to Fahrenheit. Use of this conversion and lack of rounding means that, despite the high-resolution temperature, degrees in Fahrenheit only appear in increments of about 0.2 deg F giving it less resolution than the Celsius. This is the price of a simpler implementation. Continue to abide by the constraint: do not use floating point operations. Simple microprocessors cannot perform floating point operations as they lack a Floating Point Unit (FPU).


3.5 set_display_from_temp()





https://www.cs.umd.edu/~profk/216/p2.html    12/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


int set_display_from_temp(temp_t temp, int *display);

    • Alters the bits of integer pointed to by display to reflect the

    • temperature in struct arg temp.  If temp has a temperature value

    • that is below minimum or above maximum temperature allowable or if

    • the temp_mode is not Celsius or Fahrenheit, sets the display to

    • read "ERR" and returns 1. Otherwise, calculates each digit of the

    • temperature and changes bits at display to show the temperature

    • according to the pattern for each digit.  This function DOES NOT

    • modify any global variables except if `display` points at one.

//

    • CONSTRAINTS: Uses only integer operations. No floating point

    • operations are used as the target machine does not have a FPU. Does

    • not use any math functions such as abs().


This function sets the bits in the integer pointed to by display which. In some cases display may point at THERMO_DISPLAY_PORT which will adjust the display itself, but it is useful in testing to change other integers, thus the pointer argument.

To properly set the display bits, set_display_from_temp() will need to do bit shifting along with bitwise operations to construct the correct bit pattern for the thermometer display.

A good trick to use is to create a series of bit patterns that correspond to the various digits. For example, according to the diagrams above, the bit pattern for 9 is 0b1011111. If a 9 should appear on the display somewhere, this bit pattern should be shifted and combined with the existing bits in display so that a 9 will show. Creating similar constant mask patterns for each digit, the minus sign, and the position of the Celsius/Fahrenheit indicator is a good way to make this problem manageable.

A detailed explanation of one approach to the problem follows.

The display parameter may point to an integer with arbitrary bits in it. Work around this either by (A) creating a local int initialized to 0, arranging the display, and then deref-setting display to that integer OR (B) deref-setting display to 0 before altering it.

Create an array of bit masks for each of the digits 0-9. The 0th element of the array contains a bit mask like 0b1111011 which represents the bits that should be set for a 0 digit, the 1th element of this array has a mask like 0b1001000 which are the bits to be set for a 1. There should be ten entries in this array in indices 0-9. The array can be a global variable or an array local to some function.

Use modulo to determine the integer value for the tens, ones, and tenths digits for the temperature. Call these variables something like temp_hundreds, temp_tens and so on. Each variable should be in the range 0-9.

Start with an integer variable of 0 (all 0 bits).


Use temp_tens to index into your array of masks to determine the bits that should be set for it. Combine the state variable with temp_ones mask.

Combining bits here is a logical operation of setting all bits that are one in the mask to 1 in the display variable.


Use temp_hundreds to index into your array of masks for the right mask for that digit. The bits corresponding to the hundreds place of the temperature is shifted to the left by 21 bits so shift the mask to the left and combine it with the state variable. Repeat this process for the tens digit (shifted by 14) ones, and tenths digits.

Early in the function, check that the ranges for the tenths_degrees and temp_mode fields are in range. If they are note, populate display with the ERR message and return 1.


There are several special cases to consider: leading 0's should be blanks so nothing should be drawn. Also, the negative sign should be positioned immediately to the left of the first non-blank digit. A couple examples of how this looks are below with the


https://www.cs.umd.edu/~profk/216/p2.html    13/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures

underscore representing a blank space.



RIGHT

_22.4 deg C _-1.5 deg C _-2.7 deg C ERR._ _____


WRONG

022.4 deg C

-01.5 deg C

-_2.7 deg C

ERR.0 deg C

3.6 thermo_update()



int thermo_update();

    • Called to update the thermometer display.  Makes use of

    • set_temp_from_ports() and set_display_from_temp() to access

    • temperature sensor then set the display. Always sets the display

    • even if the other functions returns an error. Returns 0 if both

    • functions complete successfully and return 0. Returns 1 if either

    • function or both return a non-zero values.

//

    • CONSTRAINT: Does not allocate any heap memory as malloc() is NOT

    • available on the target microcontroller.  Uses stack and global

    • memory only.


NOTE: This documentation was updated to remove some inconsistencies after the initial release of the project.

This function makes use of the previous two functions and the global variables that correspond to the hardware to alter the display. It should be relatively short by making use of the previous functions.

3.7 Thermometer Simulator

While we do not have actual hardware with the features mentioned, a simulator for the system is in the provided file thermo_main.c. You do not need to modify or understand code in either file to complete the assignment though it will certainly expand you C skills to spend some time examining them.

The main() function in thermo_main.c accepts two command line arguments which are the value for the temperature sensor and whether the thermometer is in Celsius or Fahrenheit mode. It will call your functions for this problem and show results for it. You are encouraged to use this function to test your code incrementally

Examine whether set_temp_from_ports() is correct based on the first part of output in thermo_main.c


Once set_temp_from_ports() is complete, examine whether the output of set_display_from_temp() is correct based on the latter part of the output.

Once both these functions are correct, examine whether thermo_update() is correct based on the final part of the output of the main() function.


Note that there are a variety of functions in the thermo_main.c which are used to simulate how the thermometer will display. This is also where the global variables like THERMO_DISPLAY_PORT are defined. However, you do not need to modify or even understand the code; it is only used to show how the display would look when the THERMO_DISPLAY_PORT bits are set.

3.8 Sample Runs of thermo_main


https://www.cs.umd.edu/~profk/216/p2.html    14/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures

Below are samples generated by compiling and running the main() function in the thermo_main.c file. The code is compiled by using the provided Makefile to create the thermo_main program. It compiles the the functions you write in the file thermo_update.c and combines them with functions in thermo_main.c.


########## CELSIUS FOR 0 ##########

    • ./thermo_main 0 C

THERMO_SENSOR_PORT set to: 0

THERMO_STAUS_PORT set to: 1000 1000

index:    4    0

result = set_temp_from_ports(&temp);

result: 0

temp = {

.tenths_degrees = -450

.temp_mode    = 1

}

Simulated temp is: -45.0 deg C

result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
01
0000100
1001110
1100111
1111011
index:
30
28

21
14
7
0
result
= thermo_update();


result: 0






THERMO_DISPLAY_PORT is


bits:
00
01
0000100
1001110
1100111
1111011
index:
30
28

21
14
7
0
Thermometer Display:





~~
~~




|
|
|
|
| o



~~
~~
~~


C



|

| |
|





~~ o ~~







########## FAHRENHEIT FOR 0 ##########

    • ./thermo_main 0 F

THERMO_SENSOR_PORT set to: 0


THERMO_STAUS_PORT set to: 1010
1000
index:
4
0

result
= set_temp_from_ports(&temp);
result: 0


temp =
{


.tenths_degrees
=
-490
.temp_mode
=
2

}

Simulated temp is: -49.0 deg F

https://www.cs.umd.edu/~profk/216/p2.html    15/51
3/5/24, 8:25 PM





CMSC216 Project 2: Bit Ops, Debugging, Data Structures
result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
10
0000100
1001110
1101111
1111011
index:
30
28

21
14
7
0
result
= thermo_update();


result: 0






THERMO_DISPLAY_PORT is


bits:
00
10
0000100
1001110
1101111
1111011
index:
30
28

21
14
7
0
Thermometer Display:





~~
~~




|
|
|
| |
|



~~
~~
~~


o



|

| |
|
F




~~ o ~~







########## CELSIUS FOR 10 ##########

    • ./thermo_main 10 C

THERMO_SENSOR_PORT set to: 10

THERMO_STAUS_PORT set to: 1000 1000

index:    4    0

result = set_temp_from_ports(&temp);

result: 0

temp = {

.tenths_degrees = -450

.temp_mode    = 1

}

Simulated temp is: -45.0 deg C

result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
01
0000100
1001110
1100111
1111011
index:
30
28

21
14
7
0
result
= thermo_update();


result: 0






THERMO_DISPLAY_PORT is


bits:
00
01
0000100
1001110
1100111
1111011
index:
30
28

21
14
7
0
Thermometer Display:





~~

~~



|
|
|
|
| o



~~
~~
~~


C



|

| |
|





https://www.cs.umd.edu/~profk/216/p2.html    16/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


~~ o ~~



########## FAHRENHEIT FOR 10 ##########

    • ./thermo_main 10 F

THERMO_SENSOR_PORT set to: 10

THERMO_STAUS_PORT set to: 1010 1000

index:    4    0

result = set_temp_from_ports(&temp);

result: 0

temp = {

.tenths_degrees = -490

.temp_mode    = 2

}

Simulated temp is: -49.0 deg F

result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
10
0000100
1001110
1101111
1111011
index:
30
28

21
14
7
0
result
= thermo_update();


result: 0






THERMO_DISPLAY_PORT is


bits:
00
10
0000100
1001110
1101111
1111011
index:
30
28

21
14
7
0
Thermometer Display:





~~
~~




|
|
|
| |
|



~~
~~
~~


o



|

| |
|
F




~~ o ~~







########## CELSIUS FOR 20 ##########

    • ./thermo_main 20 C

THERMO_SENSOR_PORT set to: 20


THERMO_STAUS_PORT set to: 1000
1000
index:
4
0

result
= set_temp_from_ports(&temp);
result: 0


temp =
{


.tenths_degrees
=
-449
.temp_mode
=
1

}

Simulated temp is: -44.9 deg C


result = set_display_from_temp(temp, &display); result: 0

https://www.cs.umd.edu/~profk/216/p2.html    17/51
3/5/24, 8:25 PM




CMSC216 Project 2: Bit Ops, Debugging, Data Structures
display is





bits:
00
01
0000100
1001110
1001110
1101111
index:
30
28
21
14
7
0
result
= thermo_update();


result: 0





THERMO_DISPLAY_PORT is


bits:
00
01
0000100
1001110
1001110
1101111
index:
30
28
21
14
7
0


Thermometer Display:

~~

    • | |  | |  | o

~~    ~~    ~~    ~~    C

|    |    |

o ~~



########## FAHRENHEIT FOR 20 ##########

    • ./thermo_main 20 F

THERMO_SENSOR_PORT set to: 20



THERMO_STAUS_PORT set to: 1010 1000

index:




4
0

result
= set_temp_from_ports(&temp);

result: 0






temp = {






.tenths_degrees = -488



.temp_mode
= 2




}







Simulated
temp is: -48.8 deg F


result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
10
0000100
1001110
1111111
1111111
index:
30
28
21
14

7
0
result
= thermo_update();



result: 0






THERMO_DISPLAY_PORT is



bits:
00
10
0000100
1001110
1111111
1111111
index:
30
28
21
14

7
0

Thermometer Display:


~~    ~~

|    ||    ||    |

~~    ~~    ~~    ~~    o

    • ||||F

        ◦ o ~~



https://www.cs.umd.edu/~profk/216/p2.html    18/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures



########## CELSIUS FOR 34 ##########

    • ./thermo_main 34 C

THERMO_SENSOR_PORT set to: 34



THERMO_STAUS_PORT set to: 1000 1000

index:




4
0

result
= set_temp_from_ports(&temp);

result: 0






temp = {






.tenths_degrees = -449



.temp_mode
= 1




}







Simulated
temp is: -44.9 deg C


result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
01
0000100
1001110
1001110
1101111
index:
30
28
21
14

7
0
result
= thermo_update();



result: 0






THERMO_DISPLAY_PORT is



bits:
00
01
0000100
1001110
1001110
1101111
index:
30
28
21
14

7
0

Thermometer Display:

~~

    • | |  | |  | o

~~    ~~    ~~    ~~    C

|    |    |

o ~~



########## FAHRENHEIT FOR 34 ##########

    • ./thermo_main 34 F

THERMO_SENSOR_PORT set to: 34

THERMO_STAUS_PORT set to: 1010 1000

index:
4
0

result = set_temp_from_ports(&temp);

result: 0


temp = {


.tenths_degrees
=
-488
.temp_mode
=
2
}



Simulated temp is: -48.8 deg F

result = set_display_from_temp(temp, &display);

result: 0


display is

bits:    00 10 0000100 1001110 1111111 1111111

https://www.cs.umd.edu/~profk/216/p2.html    19/51
3/5/24, 8:25 PM




CMSC216 Project 2: Bit Ops, Debugging, Data Structures
index:
30
28
21
14
7
0
result
= thermo_update();


result: 0





THERMO_DISPLAY_PORT is


bits:
00
10
0000100
1001110
1111111
1111111
index:
30
28
21
14
7
0


Thermometer Display:

~~    ~~

|    ||    ||    |

~~    ~~    ~~    ~~    o

    • ||||F

        ◦ o ~~



########## CELSIUS FOR 160 ##########

    • ./thermo_main 160 C

THERMO_SENSOR_PORT set to: 160

THERMO_STAUS_PORT set to: 1000 1000

index:    4    0

result = set_temp_from_ports(&temp);

result: 0

temp = {

.tenths_degrees = -445

.temp_mode    = 1

}

Simulated temp is: -44.5 deg C

result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
01
0000100
1001110
1001110
1100111
index:
30
28

21
14
7
0
result
= thermo_update();


result: 0






THERMO_DISPLAY_PORT is


bits:
00
01
0000100
1001110
1001110
1100111
index:
30
28

21
14
7
0
Thermometer Display:






~~




|
|
|
| |

o


~~
~~
~~
~~

C



|

|
|






o ~~







########## FAHRENHEIT FOR 160 ##########

https://www.cs.umd.edu/~profk/216/p2.html    20/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


    • ./thermo_main 160 F

THERMO_SENSOR_PORT set to: 160

THERMO_STAUS_PORT set to: 1010 1000

index:    4    0

result = set_temp_from_ports(&temp);

result: 0

temp = {

.tenths_degrees = -481

.temp_mode    = 2

}

Simulated temp is: -48.1 deg F

result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
10
0000100
1001110
1111111
1001000
index:
30
28

21
14
7
0
result
= thermo_update();


result: 0






THERMO_DISPLAY_PORT is


bits:
00
10
0000100
1001110
1111111
1001000
index:
30
28

21
14
7
0
Thermometer Display:





~~





|
|
|
|
|



~~
~~
~~


o



| |
|
|
F




~~ o







########## CELSIUS FOR 1607 ##########

    • ./thermo_main 1607 C

THERMO_SENSOR_PORT set to: 1607

THERMO_STAUS_PORT set to: 1000 1000

index:    4    0

result = set_temp_from_ports(&temp);

result: 0

temp = {

.tenths_degrees = -400

.temp_mode    = 1

}

Simulated temp is: -40.0 deg C


result
= set_display_from_temp(temp,
&display);
result:
0





display
is





bits:
00
01
0000100
1001110
1111011
1111011
index:
30
28
21
14
7
0


https://www.cs.umd.edu/~profk/216/p2.html    21/51
3/5/24, 8:25 PM




CMSC216 Project 2: Bit Ops, Debugging, Data Structures
result
= thermo_update();


result: 0





THERMO_DISPLAY_PORT is


bits:
00
01
0000100
1001110
1111011
1111011
index:
30
28
21
14
7
0


Thermometer Display:

~~    ~~

    • | |  | |  | o

~~    ~~    C

||    ||    |

~~ o ~~



########## FAHRENHEIT FOR 1607 ##########

    • ./thermo_main 1607 F

THERMO_SENSOR_PORT set to: 1607


THERMO_STAUS_PORT set to: 1010 1000

index:




4
0

result
= set_temp_from_ports(&temp);

result: 0






temp = {






.tenths_degrees = -400



.temp_mode
= 2




}







Simulated
temp is: -40.0 deg F


result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
10
0000100
1001110
1111011
1111011
index:
30
28
21
14

7
0
result
= thermo_update();



result: 0






THERMO_DISPLAY_PORT is



bits:
00
10
0000100
1001110
1111011
1111011
index:
30
28
21
14

7
0

Thermometer Display:

~~    ~~

|    ||    ||    |

~~    ~~    o

    • ||||F

        ◦ o ~~




########## CELSIUS FOR 12689 ##########


    • ./thermo_main 12689 C

THERMO_SENSOR_PORT set to: 12689

https://www.cs.umd.edu/~profk/216/p2.html    22/51
3/5/24, 8:25 PM





CMSC216 Project 2: Bit Ops, Debugging, Data Structures
THERMO_STAUS_PORT set to: 1000 1000

index:




4
0

result
= set_temp_from_ports(&temp);

result: 0






temp = {






.tenths_degrees = -53



.temp_mode
= 1




}







Simulated
temp is: -5.3 deg C



result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
01
0000000
0000100
1100111
1101101
index:
30
28
21
14

7
0
result
= thermo_update();



result: 0






THERMO_DISPLAY_PORT is



bits:
00
01
0000000
0000100
1100111
1101101
index:
30
28
21
14

7
0


Thermometer Display:

~~    ~~

    • | o

~~    ~~    ~~    C

|    |

~~ o ~~



########## FAHRENHEIT FOR 12689 ##########

    • ./thermo_main 12689 F

THERMO_SENSOR_PORT set to: 12689

THERMO_STAUS_PORT set to: 1010 1000

index:    4    0

result = set_temp_from_ports(&temp);

result: 0

temp = {

.tenths_degrees = 225

.temp_mode    = 2

}

Simulated temp is: 22.5 deg F

result
= set_display_from_temp(temp,
&display);
result: 0





display is





bits:
00
10
0000000
0111101
0111101
1100111
index:
30
28
21
14
7
0
result
= thermo_update();



result: 0

https://www.cs.umd.edu/~profk/216/p2.html    23/51
3/5/24, 8:25 PM




CMSC216 Project 2: Bit Ops, Debugging, Data Structures
THERMO_DISPLAY_PORT is


bits:
00
10
0000000
0111101
0111101
1100111
index:
30
28
21
14
7
0
Thermometer Display:




~~
~~
~~




|

| |




~~
~~
~~
o


|

|
|
F



~~
~~ o ~~






########## CELSIUS FOR 15744 ##########

    • ./thermo_main 15744 C

THERMO_SENSOR_PORT set to: 15744

THERMO_STAUS_PORT set to: 1000 1000

index:    4    0

result = set_temp_from_ports(&temp);

result: 0

temp = {

.tenths_degrees = 42

.temp_mode    = 1

}

Simulated temp is: 4.2 deg C

result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
01
0000000
0000000
1001110
0111101
index:
30
28

21
14
7
0
result
= thermo_update();


result: 0






THERMO_DISPLAY_PORT is


bits:
00
01
0000000
0000000
1001110
0111101
index:
30
28

21
14
7
0
Thermometer Display:






~~






|
|
| o





~~
~~

C





| |







o ~~







########## FAHRENHEIT FOR 15744 ##########

    • ./thermo_main 15744 F

THERMO_SENSOR_PORT set to: 15744


THERMO_STAUS_PORT set to: 1010
1000
index:
4
0

https://www.cs.umd.edu/~profk/216/p2.html    24/51
3/5/24, 8:25 PM




CMSC216 Project 2: Bit Ops, Debugging, Data Structures
result
= set_temp_from_ports(&temp);

result: 0





temp = {





.tenths_degrees = 395


.temp_mode
= 2



}






Simulated
temp is: 39.5 deg F


result
= set_display_from_temp(temp, &display);
result: 0





display is





bits:
00
10
0000000
1101101
1101111
1100111
index:
30
28
21
14
7
0
result
= thermo_update();


result: 0





THERMO_DISPLAY_PORT is


bits:
00
10
0000000
1101101
1101111
1100111
index:
30
28
21
14
7
0


Thermometer Display:

~~    ~~    ~~

||    ||

~~    ~~    ~~    o

        ◦ ||  F

    • ~~ o ~~



########## CELSIUS FOR 20448 ##########

    • ./thermo_main 20448 C

THERMO_SENSOR_PORT set to: 20448

THERMO_STAUS_PORT set to: 1000 1000

index:    4    0

result = set_temp_from_ports(&temp);

result: 0

temp = {

.tenths_degrees = 189

.temp_mode    = 1

}

Simulated temp is: 18.9 deg C

result
= set_display_from_temp(temp,
&display);
result:
0





display
is





bits:
00
01
0000000
1001000
1111111
1101111
index:
30
28
21
14
7
0


result = thermo_update();

result: 0


THERMO_DISPLAY_PORT is

bits:    00 01 0000000 1001000 1111111 1101111

https://www.cs.umd.edu/~profk/216/p2.html    25/51
3/5/24, 8:25 PM




CMSC216 Project 2: Bit Ops, Debugging, Data Structures
index:
30
28
21
14
7
0


Thermometer Display:

~~    ~~

| |    | |    | o

~~    ~~    C

||    |    |

~~ o ~~



########## FAHRENHEIT FOR 20448 ##########

    • ./thermo_main 20448 F

THERMO_SENSOR_PORT set to: 20448


THERMO_STAUS_PORT set to: 1010 1000

index:




4
0

result
= set_temp_from_ports(&temp);

result: 0






temp = {






.tenths_degrees = 660



.temp_mode
= 2




}







Simulated
temp is: 66.0 deg F



result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
10
0000000
1110111
1110111
1111011
index:
30
28
21
14

7
0
result
= thermo_update();



result: 0






THERMO_DISPLAY_PORT is



bits:
00
10
0000000
1110111
1110111
1111011
index:
30
28
21
14

7
0

Thermometer Display:

~~    ~~    ~~

|    |    |    |

~~    ~~    o

    • |||||F

        ◦ ~~ o ~~



########## CELSIUS FOR 28544 ##########


    • ./thermo_main 28544 C

THERMO_SENSOR_PORT set to: 28544

THERMO_STAUS_PORT set to: 1000 1000

index:    4    0


result = set_temp_from_ports(&temp);

result: 0

https://www.cs.umd.edu/~profk/216/p2.html    26/51
3/5/24, 8:25 PM





CMSC216 Project 2: Bit Ops, Debugging, Data Structures
temp = {






.tenths_degrees = 442


.temp_mode

= 1



}







Simulated
temp is: 44.2 deg C


result = set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
01
0000000
1001110
1001110
0111101
index:
30
28

21
14
7
0
result = thermo_update();


result: 0






THERMO_DISPLAY_PORT is


bits:
00
01
0000000
1001110
1001110
0111101
index:
30
28

21
14
7
0
Thermometer Display:






~~




|
|
|
|
| o




~~
~~
~~

C



|

| |







o ~~







########## FAHRENHEIT FOR 28544 ##########

    • ./thermo_main 28544 F

THERMO_SENSOR_PORT set to: 28544


THERMO_STAUS_PORT set to: 1010 1000

index:




4
0

result
= set_temp_from_ports(&temp);

result: 0






temp = {






.tenths_degrees = 1115



.temp_mode
= 2




}







Simulated
temp is: 111.5 deg F


result
= set_display_from_temp(temp, &display);
result: 0






display is






bits:
00
10
1001000
1001000
1001000
1100111
index:
30
28
21
14

7
0
result
= thermo_update();



result: 0






THERMO_DISPLAY_PORT is



bits:
00
10
1001000
1001000
1001000
1100111
index:
30
28
21
14

7
0


https://www.cs.umd.edu/~profk/216/p2.html    27/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


Thermometer Display:

~~

|    |    | |

    • o

|    |    |    |    F

o ~~





3.9 Grading Criteria for thermo_update.c  grading 30


Weight    Criteria


AUOTMATED TESTS

    20 make test-prob1 runs 40 tests for correctness, 0.5 points per test

test_thermo_update.c provides tests for functions in thermo_update.c

There are also tests of thermo_main which uses functions from thermo_update.c


MANUAL INSPECTION

    • set_temp_from_ports()

Use of a bitwise operations (shifts, and, etc.) to convert the sensor value to temperature Section to round temperature correctly which uses bitwise operations to calculate remainders. Clear effort to do error checking of out of bounds values.

Clear flow to how each field of temp is calculated.

Correctly setting fields of temp via pointer dereference or arrow operator. No use of floating point operations as per the listed constraint

Concise function that is not longer than 40 lines of code, complex nested conditionals




    • set_display_from_temp()

Clear effort to do error checking for out of bounds values in temp parameter Presence of an error case that sets up the ERR message on the screen.

Clear code that calculates digits to be displayed

Use of bit masks corresponding to digits to be displayed Use of bitwise operators to shift bits appropriately Use of bitwise operators to combine shifted digit bits

Clear dereference/set of the integer pointed to by the display parameter



https://www.cs.umd.edu/~profk/216/p2.html    28/51
3/5/24, 8:25 PM
CMSC216 Project 2: Bit Ops, Debugging, Data Structures




Weight
Criteria


Concise function that is not longer than 80 lines of code, complex nested conditionals



    • thermo_update()

Use of the global variables like THERMO_DISPLAY_PORT

Does not re-define / re-declare these variables, only checks / alters their values Use of previous two functions

Correctly captures return values of previous functions and passes errors up


4 Problem 2: Debugging the Puzzlebox

4.1 Overview

The file puzzlebox.c contains source code that reads inputs from a file named on the command line. If the inputs are correct, points are awarded. If inputs are incorrect, error messages are printed.

The puzzlebox is arranged into a series of phases each of which has some points associated with it.

Not all phases must be completed to get full credit but the phases must done in order.


Each phase reads inputs from the file provided on the command line and performs calculations on them to see if they are "correct" according to various criteria

The very first input is your internet ID like kauf0095 (first part of your UMN email address). This input is used to add randomness to the puzzle so that your answers will be different from most other students. You must you use your own internet ID.


The purpose of this problem is get familiar with using a debugger. This is a powerful tool that pauses programs, allows internal values to be printed and code to be stepped through line by line. It is nearly essential to use as the code in puzzlebox is intentionally convoluted in places. Being able to pause execution and print values at various points make it much easier to solve the puzzles.

4.2 input.txt Input File

Name your input file input.txt and put your internet ID in it along with some numbers like 1 2 3. Then compile and run the puzzlebox program on it.


>>
make puzzlebox
#
compile puzzlebox
gcc -Wall -g
-c puzzlebox.c


gcc -Wall -g
-o puzzlebox puzzlebox.o


>>
cat input.txt
#
show contents of input.txt
kauf0095 1 2
3



    • puzzlebox input.txt

========================================

PROBLEM 2: Puzzlebox

https://www.cs.umd.edu/~profk/216/p2.html    29/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


UserID 'KAUF0095' accepted: hash value = 1936486779

PHASE 1: A puzzle you say? Challenge accepted!

Ah ah ah, you didn't say the magic word...

Failure: Double debugger burger, order up!

RESULTS: 0 / 30 points


This is automated with the Makefile target make test-prob2:



>> make test-prob2    # compile/run puzzlebox with input.txt

gcc -Wall -g -c puzzlebox.c

gcc -Wall -g -o puzzlebox puzzlebox.o

puzzlebox input.txt

========================================

PROBLEM 2: Puzzlebox

UserID 'KAUF0095' accepted: hash value = 1936486779

PHASE 1: A puzzle you say? Challenge accepted!

Ah ah ah, you didn't say the magic word...

Failure: Double debugger burger, order up!

RESULTS: 0 / 30 points


These initial forays are not positive (0 / 30 points) but the real meat of the problem is in examining the source code and determining inputs for input.txt.

4.3 gdb The GNU Debugger

You will definitely need to use a debugger to solve the puzzlebox and gdb is the quintessential debugger associated with our compiler gcc. It is installed by default on all lab machines and is an easy install on must Linux machines.

For a quick overview of GDB, here are some resources

CSCI 2021 Quick Guide to gdb: The GNU Debugger: Page describing how to start the debugger, a sample session using puzzlebox, an overview of the most common commands.

CppCon 2015: Greg Law " Give me 15 minutes & I'll change your view of GDB": Video giving basic overview of hope to run gdb on simple programs with an emphasis on differences between "normal" mode and TUI mode

GNU GDB Debugger Command Cheat Sheet: Extensive list of commands


Debugging with GDB: Official manual for gdb


4.4 Typical Cycle

A typical cycle of working on puzzlebox will be the following.


Start the debugger with puzzlebox



gdb -tui ./puzzlebox


https://www.cs.umd.edu/~profk/216/p2.html    30/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures

Set the arguments array to input.txt



set args input.txt


Set a breakpoint at a phase like phase3



break phase3


Run the program



run


Do some stepping / nexting



step

next


Print some variables



print normal_val

print/x val_in_hex

print/t val_in_binary


Make some changes to input.txt in a different window


Re-run the program to see if things have changed favorably



kill

run


4.5 Kinds of Puzzles

The puzzles presented in the different phases make use of a variety of C program techniques which we have or will discuss including.

Bit-wise operations and their use in place of arithmetic


String and character array manipulations


Interpreting bits as one of several kinds of things (integer, float, character) through pointers and unions


More extensive C control structures like goto and labels


4.6 Tests for puzzlebox.c  grading 30


puzzlebox.c itself reports how many points one can earn at the end of its execution.

Currently there are 40 points available but 30 points is considered full credit.



https://www.cs.umd.edu/~profk/216/p2.html    31/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures

If any additional points are earned, they will be counted as Makeup Credit for Projects to make up for credit lost on past or future projects. Your total score on All Projects cannot exceed 100% so any points beyond will simply be dropped.

Run the following command to 'test' puzzlebox:



make test-prob2


5 Problem 3: Hash Map in C

5.1 Overview

This problem implements a rudimentary hash table application in C along with a program that uses it. The architecture is similar to a lab problem involving linked lists so reviewing that code can provide some insight.

Basic Hash Tables are covered in most introductory data structure classes such as CMSC 132. Should you need to review them, the following resources may prove useful.

Wikipedia Article on Hash Tables: Provides general overview of the data structure. Specifically focus on Separate Chaining with Linked Lists which is the style of hash table implemented in the assignment.

Youtube "Data Structures: Hash Tables" by HackerRank: Short video summarizing major concepts of hash tables in any programming language. Explains briefly hash code functions and the Separate Chaining architecture we will use.

Youtube "How HashMap works in Java" by Ranjith Ramachandran: Short video which includes a detailed walk-through of adding elements to a separately chained hash table. Somewhat Java-centric including use of a different mapping of hash codes to array indices than we will use.


5.2 hashmap_main Demonstration

The intent of this problem is to develop a small application which behaves as the following demo indicates.



>> make hash_main    # build the hash_main application

gcc -Wall
-g -lm -c
hash_main.c
gcc
-Wall
-g
-lm
-c
hash_funcs.c
gcc
-Wall
-g
-lm
-o
hash_main hash_main.o hash_funcs.o

>> ./hash_main    # run the application

Hashmap Main

Commands:

hashcode <key>    : prints out the numeric hash code for the given key (does not chang

put <key> <val>    : inserts the given key/val into the hash map, overwrites existing v

get <key>    : prints the value associated with the given key or NOT FOUND

print    : shows contents of the hashmap ordered by how they appear in the ta

structure    : prints detailed structure of the hash map

clear    : reinitializes hash map to be empty with default size

save <file>    : writes the contents of the hash map the given file

load <file>    : clears the current hash map and loads the one in the given file

next_prime <int> : if <int> is prime, prints it, otherwise finds the next prime and p

expand    : expands memory size of hashmap to reduce its load factor

quit    : exit the program

https://www.cs.umd.edu/~profk/216/p2.html    32/51
3/5/24, 8:25 PM

CMSC216 Project 2: Bit Ops, Debugging, Data Structures








HM>
put Lucas brash
# put key/vals into the hash map


HM>
put Mike
DM




HM>
put Dustin corny




HM>
put Will
lost




HM>
print

# print the contents of the hash map



Mike
: DM
# shows up out of order from insertions



Dustin
: corny
# due to the randomness of hash codes



Will
: lost





Lucas : brash




HM>
get Dustin
# lookup based on key


FOUND: corny

# success: value is returned


HM>
get El





NOT
FOUND

# failure: not in hash map


HM>
get Lucas





FOUND: brash

# success


HM>
get Jim





NOT
FOUND

# failure


HM>
put El weird
# add more key/values to the hash map


HM>
put Steve hairy




HM>
put Nancy torn




HM>
put Barb
ran-away?




HM>
print






Mike : DM





Nancy : torn





Barb
: ran-away?





Dustin
: corny





El
: weird





Will
: lost





Lucas
: brash





Steve
: hairy




HM>
hashcode
Lucas
# show hash codes for various keys,


1633908044

# calculated from the string


HM>
hashcode
Barb
# PRINT USING "%ld" for 64-bit longs


1651663170

# much larger than the table size


HM>
structure

# show the structure of the hash table


item_count: 8

# how many key/val pairs in the map


table_size: 5

# size of the table array


load_factor:
1.6000
# item_count / table_size



0
: {(1701538125) Mike : DM} {(521359221070) Nancy : torn} {(1651663170) Barb :
ran-a


1
: {(121399204345156) Dustin : corny}



2
: {(27717) El : weird}










3
: {(1819044183) Will : lost}




4
: {(495555147084) Lucas : brash} {(435778057299) Steve : hairy}










https://www.cs.umd.edu/~profk/216/p2.html    33/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures



    • above shows hash codes for key, value, linked lists in each bucket

    • 0 and 5 are in bucket 0, 1 and 6 are in bucket 1, etc

HM>
expand
# expand the hash map's table array
HM>
structure
# show the structure
item_count: 8
# same # of key/vals
table_size: 11
# larger array, always a prime number
load_factor: 0.7273
# reduced load factor
0
: {(1819044183) Will : lost}

1
: {(1701538125) Mike : DM} {(121399204345156) Dustin : corny}
2
: {(435778057299) Steve : hairy}

3
: {(1651663170) Barb : ran-away?}


    • :

5 :

6 : {(521359221070) Nancy : torn}

7 :

8 : {(27717) El : weird} {(495555147084) Lucas : brash}

9 :

        10 :

    • all elements rehashed to new locations based on new table size 11

HM>
save stranger.hm
# save hash map to a file
HM>
clear
# clear current hashmap
HM>
print
# print: nothing there
HM>
structure
# structure: empty after 'clear'
item_count: 0

table_size: 5

load_factor: 0.0000

0
:

1
:

2
:

3
:

4
:

HM>
put Jim cop
# put new values in the hashmap
HM>
put Joyce worried

HM>
print
# print new hash map

Joyce : worried


Jim : cop

HM>
structure
# show structure
item_count: 2
# 2 items only
table_size: 5

load_factor: 0.4000

0
:

1
: {(435460599626) Joyce : worried}

2
:



https://www.cs.umd.edu/~profk/216/p2.html    34/51
3/5/24, 8:25 PM
CMSC216 Project 2: Bit Ops, Debugging, Data Structures
3
: {(7170378) Jim : cop}

4
:


HM>
get Dustin

# old elements were cleared out
NOT
FOUND


HM>
get Joyce

# new elements present
FOUND: worried


HM>
load stranger.hm
# load from file; clears current hash table
HM>
print

# old elements are restored

Will :
lost


Mike :
DM


Dustin :
corny


Steve :
hairy


Barb :
ran-away?


Nancy :
torn


El :
weird


Lucas :
brash

HM>
structure

# identical structure from the 'load'
item_count: 8


table_size: 11


load_factor: 0.7273

0
: {(1819044183) Will : lost}

1
: {(1701538125) Mike : DM} {(121399204345156) Dustin : corny}
2
: {(435778057299) Steve : hairy}

3
: {(1651663170) Barb : ran-away?}


    • :

5 :

6 : {(521359221070) Nancy : torn}

7 :

8 : {(27717) El : weird} {(495555147084) Lucas : brash}

9 :

10
:



HM>
get Dustin
# now found

FOUND: corny



HM>
get Joyce
# cleared after the 'load'

NOT
FOUND



HM>
put Will found
# overwrite values associated with existing key

Overwriting previous key/val



HM>
put Nancy decided



Overwriting previous key/val



HM>
put Mike girl-crazy



Overwriting previous key/val



HM>
print









Will : found
# new value








https://www.cs.umd.edu/~profk/216/p2.html    35/51
3/5/24, 8:25 PM
CMSC216 Project 2: Bit Ops, Debugging, Data Structures

Mike :
girl-crazy
# new value

Dustin :
corny


Steve :
hairy


Barb :
ran-away?


Nancy :
decided
# new value

El :
weird


Lucas :
brash

HM>
next_prime
10
# calculates next larger prime
11



HM>
next_prime
25

29



HM>
next_prime
31
# already prime
31



HM>
structure

# show structure
item_count: 8


table_size: 11


load_factor: 0.7273

0
: {(1819044183) Will : found}

1
: {(1701538125) Mike : girl-crazy} {(121399204345156) Dustin : corny}
2
: {(435778057299) Steve : hairy}

3
: {(1651663170) Barb : ran-away?}


    • :

5 :

6 : {(521359221070) Nancy : decided}

7 :

8 : {(27717) El : weird} {(495555147084) Lucas : brash}

9 :

10 :

HM> expand    # expand again to next_prime(table_size*2+1)

HM> structure

item_count:
8
# same as
before

table_size:
23
#
larger,
always
a prime number
load_factor: 0.3478
#
reduced
load factor

    • :

1 :

2 : {(27717) El : weird}

3 :

4 : {(1651663170) Barb : ran-away?} {(495555147084) Lucas : brash}

5 :

6 :

7 :

8 : {(121399204345156) Dustin : corny}

9 :


10 : {(521359221070) Nancy : decided}

11 : {(1701538125) Mike : girl-crazy} {(435778057299) Steve : hairy}

https://www.cs.umd.edu/~profk/216/p2.html    36/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


12 : {(1819044183) Will : found}

    13 :

    14 :

    15 :

    16 :

    17 :

    18 :

    19 :

    20 :

    21 :

    22 :

HM> quit    # quit the program


5.3 hashmap_funcs.c: Hash Table Functions

We will favor separately chained hash maps which have the following features.

A hash map stores key/value pairs allowing fast lookup based on keys. It is a data structure that is often used to implement 'dictionaries'.

The hash map has a 'table' which is a fixed size array. Each array element is a pointer to a linked list node or NULL.


Items in the hash table are stored in linked list nodes including the lookup key and value associated with the key. Items that hash to the same table location are stored in the list at that location

A hashcode() function is provided which generates an integer from a string and is the first step to determining where key/value is located.


Examine the header file hashmap.h to see the two C structs which will be used to represent hash tables.



    • Type for linked list nodes in hash map typedef struct hashnode {

char
key[128];
// string
key
for items in the map
char
val[128];
//
string
value for items in the map
struct hashnode *next;
//
pointer to
next node, NULL if last node

} hashnode_t;

    • Type of hash table typedef struct {

int
item_count;
// how
many
key/val pairs in the table
int
table_size;
//
how
big is the table
array

hashnode_t **table;
//
array of
pointers to
nodes
which contain key/val pai

} hashmap_t;


Standard operations are supported by the hash map.


Adding key/val pairs


Searching for the value associated with a key


Altering the value associated with a key


Clearing the entire hash map


Printing the key/value pairs in the hash map


https://www.cs.umd.edu/~profk/216/p2.html    37/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures

Expanding the memory used by the hash map to improve lookup performance.


These are broken down into the following C functions which you will need to implement in hashmap_funcs.c except for the first hashcode() function which is provided.


    • hashmap_funcs.c: utility functions for operating on hash maps. Most

    • functions are used in hash_main.c which provides an application to

    • work with the functions.

long hashcode(char key[]);

    • PROVIDED: Compute a simple hash code for the given character

    • string. The code is "computed" by casting the first 8 characters of

    • the string to a long and returning it. The empty string has hash

    • code 0. If the string is a single character, this will be the ASCII

    • code for the character (e.g. "A" hashes to 65).  Longer strings

    • will have numbers which are the integer interpretation of up to

    • their first 8 bytes.  ADVANTAGE: constant time to compute the hash

    • code. DISADVANTAGE: poor distribution for long strings; all strings

    • with same first 8 chars hash to the same location.

void hashmap_init(hashmap_t *hm, int table_size);

    • Initialize the hash map 'hm' to have given size and item_count

    • 0. Ensures that the 'table' field is initialized to an array of

    • size 'table_size' and filled with NULLs.

int hashmap_put(hashmap_t *hm, char key[], char val[]);

    • Adds given key/val to the hash map. 'hashcode(key) modulo

    • table_size' is used to calculate the position to insert the

    • key/val.  Searches the entire list at the insertion location for

    • the given key. If key is not present, a new node is added. If key

    • is already present, the current value is altered in place to the

    • given value "val" (no duplicate keys are every introduced).  If new

    • nodes are added, increments field "item_count".  Makes use of

    • standard string.h functions like strcmp() to compare strings and

    • strcpy() to copy strings. Lists in the hash map are arbitrarily

    • ordered (not sorted); new items are always appended to the end of

    • the list.  Returns 1 if a new node is added (new key) and 0 if an

    • existing key has its value modified.

char *hashmap_get(hashmap_t *hm, char key[]);

    • Looks up value associated with given key in the hashmap. Uses

    • hashcode() and field "table_size" to determine which index in table

    • to search.  Iterates through the list at that index using strcmp()

    • to check for matching key. If found, returns a pointer to the

    • associated value.  Otherwise returns NULL to indicate no associated

    • key is present.

void hashmap_free_table(hashmap_t *hm);

// De-allocates the hashmap's "table" field. Iterates through the

https://www.cs.umd.edu/~profk/216/p2.html    38/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


    • "table" array and its lists de-allocating all nodes present

    • there. Subsequently de-allocates the "table" field and sets all

    • fields to 0 / NULL. Does NOT attempt to free 'hm' as it may be

    • stack allocated.

void hashmap_show_structure(hashmap_t *hm);

    • Displays detailed structure of the hash map. Shows stats for the

    • hash map as below including the load factor (item count divided

    • by table_size) to 4 digits of accuracy.  Then shows each table

    • array index ("bucket") on its own line with the linked list of

    • key/value pairs on the same line. The hash code for keys is appears

    • prior to each key.  EXAMPLE:

//

    • item_count: 6

    • table_size: 5

    • load_factor: 1.2000

    • 0:{(65)A:1}

    • 1 :

    • 2 : {(122) z : 3} {(26212) df : 6}

    • 3 : {(98) b : 2} {(25443) cc : 5}

    • 4:{(74)J:4}

//

    • NOTES:

    • - Uses format specifier "%3d : " to print the table indices

    • - Shows the following information for each key/val pair

    • {(25443) cc : 5}

//
|
|
|
//
|
|
+-> value
//
|
+-> key

    • +-> hashcode("cc"), print using format "%ld" for 64-bit longs

void hashmap_write_items(hashmap_t *hm, FILE *out);

    • Outputs all elements of the hash table according to the order they

    • appear in "table". The format is

//

    • Peach : 3.75

    • Banana : 0.89

    • Clementine : 2.95

    • DragonFruit : 10.65

    • Apple : 2.25

    • 

    • with each key/val on a separate line. The format specifier

    • "%12s : %s\n"


//

    • is used to achieve the correct spacing. Output is done to the file

    • stream 'out' which is standard out for printing to the screen or an

    • open file stream for writing to a file as in hashmap_save().


void hashmap_save(hashmap_t *hm, char *filename);

https://www.cs.umd.edu/~profk/216/p2.html    39/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


    • Writes the given hash map to the given 'filename' so that it can be

    • loaded later.  Opens the file and writes its 'table_size' and

    • 'item_count' to the file. Then uses the hashmap_write_items()

    • function to output all items in the hash map into the file.

    • EXAMPLE FILE:

//

    • 5 6

    • A : 2

    • Z : 2

    • B : 3

    • R : 6

    • TI:89

    • T : 7

    • 

    • First two numbers are the 'table_size' and 'item_count' field and

    • remaining text are key/val pairs.

int hashmap_load(hashmap_t *hm, char *filename);

    • Loads a hash map file created with hashmap_save(). If the file

    • cannot be opened, prints the message

//

    • ERROR: could not open file 'somefile.hm'

    • 

    • and returns 0 without changing anything. Otherwise clears out the

    • current hash map 'hm', initializes a new one based on the size

    • present in the file, and adds all elements to the hash map. Returns

    • 1 on successful loading. This function does no error checking of

    • the contents of the file so if they are corrupted, it may cause an

    • application to crash or loop infinitely.

int next_prime(int num);

    • If 'num' is a prime number, returns 'num'. Otherwise, returns the

    • first prime that is larger than 'num'. Uses a simple algorithm to

    • calculate primeness: check if any number between 2 and (num/2)

    • divide num. If none do, it is prime. If not, tries next odd number

    • above num. Loops this approach until a prime number is located and

    • returns this. Used to ensure that hash table_size stays prime which

    • theoretically distributes elements better among the array indices

    • of the table.

void hashmap_expand(hashmap_t *hm);

    • Allocates a new, larger area of memory for the "table" field and

    • re-adds all items currently in the hash table to it. The size of

    • the new table is next_prime(2*table_size+1) which keeps the size

    • prime.  After allocating the new table, all entries are initialized

    • to NULL then the old table is iterated through and all items are

    • added to the new table according to their hash code. The memory for

    • the old table is de-allocated and the new table assigned to the

    • hashmap fields "table" and "table_size".  This function increases


https://www.cs.umd.edu/~profk/216/p2.html    40/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


    • "table_size" while keeping "item_count" the same thereby reducing

    • the load of the hash table. Ensures that all memory associated with

    • the old table is free()'d (linked nodes and array). Cleverly makes

    • use of existing functions like hashmap_init(), hashmap_put(),

    • and hashmap_free_table() to avoid re-writing algorithms

    • implemented in those functions.




5.4 Provided hash_code() Function

The code for hash_code() is provided below. All hash tables require a means of converting keys into a non-unique number. For consistency, we will use the below code which employs several interesting C tricks that will be discussed of the progression of the class. Some of the advantages/disadvantages of the hash function are mentioned in the comments.


    • PROVIDED: Compute a simple hash code for the given character

    • string. The code is "computed" by casting the first 8 characters of

    • the string to a long and returning it. The empty string has hash

    • code 0. If the string is a single character, this will be the ASCII

    • code for the character (e.g. "A" hashes to 65).  Longer strings

    • will have numbers which are the integer interpretation of up to

    • their first 8 bytes.  ADVANTAGE: constant time to compute the hash

    • code. DISADVANTAGE: poor distribution for long strings; all strings

    • with same first 8 chars hash to the same location.

long hashcode(char key[]){

union {

char str[8];

long num;

} strnum; strnum.num = 0;

for(int i=0; i<8; i++){

if(key[i] == '\0'){

break;

}

strnum.str[i] = key[i];

}

return strnum.num;

}


5.5 hashmap_main.c: main function / application

In hashmap_main.c implement an interactive program which allows users to type commands to manipulate the hash map.


The provided Makefile should compile the hashmap_main program as follows.

> make hashmap_main
# Compile with Makefile
gcc
-Wall
-g
-lm
-c hashmap_main.c
gcc
-Wall
-g
-lm
-c
hashmap_funcs.c







https://www.cs.umd.edu/~profk/216/p2.html    41/51
3/5/24, 8:25 PM
CMSC216 Project 2: Bit Ops, Debugging, Data Structures



gcc -Wall -g -lm -o hashmap_main hashmap_main.o hashmap_funcs.o

> ./hashmap_main
# Run hashmap_main application

Hashmap Main


Commands:


hashcode <key>
: prints out the numeric hash code for the given key (does not chang

put <key> <val>
: inserts the given key/val into the hash map

get <key>
: prints the value associated with the given key or NOT FOUND

print
: shows contents of the hashmap ordered by how they appear in the ta

structure
: prints detailed structure of the hash map

clear
: reinitializes hash map to be empty with default size

save <file>
: writes the contents of the hash map the given file

load <file>
: clears the current hash map and loads the one in the given file

next_prime <int> : if <int> is prime, prints it, otherwise finds the next prime and p

expand
: expands memory size of hashmap to reduce its load factor

quit
: exit the program

HM>





The following sections provide some implementation details.

Read commands, Execute

The basic flow of hashmap_main.c follows the same pattern that code for a lab exercise demonstrates. A good way to get started on the main application is to copy over the lab solution and begin modifying it.

Create a hashmap_t variable, likely on the stack as a local variable in main()


Start a loop that terminates when the user exits or there is no more input


Each time the user enters a string, read it and check for one of the built-in commands


On identifying the command, potentially read another string if needed (commands like put and get)


Call an appropriate hashmap_XXX() function to handle the command


Supported Commands

To indicate to users of the program the supported commands, use the following code to print out the initial option list.


printf("Hashmap Main\n");


printf("Commands:\n");


printf("
hashcode <key>
: prints out the numeric hash code for the given key (does

printf("
put <key> <val>
: inserts the given key/val into the hash map, overwrites

printf("
get <key>
: prints the value associated with the given key or NOT FO

printf("
print
: shows contents of the hashmap ordered by how they appear

printf("
structure
: prints detailed structure of the hash map\n");

printf("
clear
: reinitializes hash map to be empty with default size\n")

printf("
save <file>
: writes the contents of the hash map the given file\n");

printf("
load <file>
: clears the current hash map and loads the one in the giv

printf("
next_prime <int>
: if <int> is prime, prints it, otherwise finds the next p

printf("
expand
: expands memory size of hashmap to reduce its load factor

printf("
quit
: exit the program\n");






https://www.cs.umd.edu/~profk/216/p2.html    42/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures

Clearing Hashmaps

When issuing the clear command, the contents of the current hash map should be eliminated and the hash map reinitialized to the default size. This is most easily done via.

    1. Using the hashmap_free_table() function

    2. Using hashmap_init() with the HASHMAP_DEFAULT_TABLE_SIZE constant defined in hashmap.h.

Paths to Files for Saving and Loading

Saving and loading data involves writing to files. The names associated with the files must be specified as a path so that if files are to be saved or loaded from subdirectories, include this as part of the path. For example, the stranger.hm file is provided in the data/ directory and once loading functionality is code, it can be loaded as follows.


p1-code> ./hashmap_main

..



HM>
load data/stranger.hm
# load the provided hash map from a subdirect
HM>
print

# show contents of hash map

Will
: lost


Mike
: DM


Dustin
: corny


Steve
: hairy


Barb
: ran-away?


Nancy
: torn


El
: weird


Lucas
: brash

HM>
structure

# show internal structure of the hash map
item_count: 8


table_size: 11

load_factor:
0.7273

0
: {(1819044183) Will : lost}

1
: {(1701538125) Mike : DM} {(121399204345156) Dustin : corny}
2
: {(435778057299) Steve : hairy}

3
: {(1651663170) Barb : ran-away?}


    • :

5 :

6 : {(521359221070) Nancy : torn}

7 :

8 : {(27717) El : weird} {(495555147084) Lucas : brash}

9 :

10
:


HM>
put Demigorgon scary
# add more data





HM>
save cur.hm
# save in the current directory

HM>
clear
# clear hash map

HM>
print
# show contents are empty





HM>
load cur.hm
# reload from file in current directory

HM>
print
# show contents are restored from save


https://www.cs.umd.edu/~profk/216/p2.html    43/51
3/5/24, 8:25 PM

CMSC216 Project 2: Bit Ops, Debugging, Data Structures





Will :
lost


Mike :
DM


Dustin :
corny


Steve :
hairy


Barb :
ran-away?


Nancy :
torn


Demigorgon :
scary


El :
weird


Lucas :
brash


HM> put Jim cop

# add more data

HM> save data/new.hm
# save in a copy in 'data' subdirectory

HM> quit







Failing to Load Files

If a file cannot be opened with the load 'file.hm' command, the underlying hashmap_load() should print an error of the form



ERROR: could not open file 'somefile.hm'


and the hashmap_main.c main loop should NOT change the hash map and print the message



load failed


in response to the error. Below is a demonstration of this from the automated tests.



...

HM> print    # hash map has contents

A : 1

C : 3

D : 4

E : 2

HM> load test-data/not-there.tmp    # attempt to load a non-existent file

ERROR: could not open file 'test-data/not-there.tmp' load failed

HM> print    # hash map is unchanged

A : 1

C : 3

D : 4

E : 2



Command Echoing: -echo option to hashmap_main




https://www.cs.umd.edu/~profk/216/p2.html    44/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures

Some users may wish to "script" this the main program: allow it to process input commands from a file rather than from the user typing.

This notion is discussed in a lab and should be reviewed if it is unfamiliar.

An example of an input script is in data/hash-demo.script which looks like a lot of user commands:



put Lucas brash

put Mike DM

put Dustin corny

put Will lost

print

get Dustin

get El

get Lucas

get Jim

put El weird

put Steve hairy

put Nancy torn

put Barb ran-away?

print

hashcode Lucas

hashcode Barb

structure

expand

structure

save stranger.hm

clear

print

structure

put Jim cop

put Joyce worried

print

structure

get Dustin

get Joyce

load stranger.hm

print

structure

get Dustin

get Joyce

put Will found

put Nancy decided

put Mike girl-crazy

print

structure

next_prime 10

next_prime 25

expand

structure


https://www.cs.umd.edu/~profk/216/p2.html    45/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


save data/other.hm

quit


The file can be fed directly to the program without needing type it using Unix pipes as per the following:



    • cat data/hash-demo.script | ./hashmap_main -echo


Notice the use of a command line argument for hashmap_main: the -echo option. This is a REQUIRED feature which prints commands typed by users to the screen. To implement this, do the following.

Model the structure of command echoing after what is shown in related Lab work.

Use a variable in main() to indicate whether command echoing is on or off; set it to off by default


Check when main() starts whether command line argument 1 is set to -echo in which case turn echoing on. A condition like the following is useful.


if(argc > 1 && strcmp("-echo",argv[1])==0) {


Each command should check for echoing and print the command being run along with any arguments to it. This technique is demonstrated in related lab work.

It will take some work to get the exact placement of echoes correct but will ultimately lead to nice results that involve LITTLE typing like the example below.


    • cat data/hash-demo.script | ./hashmap_main -echo Hashmap Main

Commands:

hashcode <key>
: prints out the numeric
hash
code
for the given key (does not chang
put <key> <val>
: inserts the given key/val
into the hash
map, overwrites existing v
get <key>
: prints the value associated
with
the given key or NOT FOUND
print
: shows contents of the hashmap ordered
by how they appear in the ta
structure
: prints detailed structure
of the
hash
map
clear
: reinitializes hash map
to
be empty with
default size
save <file>
: writes the contents of
the hash map the
given file
load <file>
: clears the current hash map
and loads
the one in the given file

next_prime <int> : if <int> is prime, prints it, otherwise finds the next prime and p

expand    : expands memory size of hashmap to reduce its load factor

quit    : exit the program

HM> put Lucas brash

HM> put Mike DM

HM> put Dustin corny

HM> put Will lost

HM> print

Mike : DM

Dustin : corny

Will : lost

Lucas : brash

https://www.cs.umd.edu/~profk/216/p2.html    46/51
3/5/24, 8:25 PM
CMSC216 Project 2: Bit Ops, Debugging, Data Structures
HM>
get Dustin




FOUND: corny

HM>
get El

NOT
FOUND

HM>
get Lucas

FOUND: brash

HM>
get Jim

NOT
FOUND

HM>
put El weird

HM>
put Steve hairy

HM>
put Nancy torn

HM>
put Barb ran-away?

HM>
print


Mike : DM


Nancy : torn


Barb : ran-away?


Dustin : corny


El : weird


Will : lost


Lucas : brash


Steve : hairy

HM>
hashcode Lucas

1633908044

HM>
hashcode Barb

1651663170

HM>
structure

item_count: 8

table_size: 5

load_factor: 1.6000

0
: {(1701538125) Mike : DM} {(521359221070) Nancy : torn} {(1651663170) Barb : ran-a
1
: {(121399204345156) Dustin : corny}
2
: {(27717) El : weird}

3
: {(1819044183) Will : lost}

4
: {(495555147084) Lucas : brash} {(435778057299) Steve : hairy}
HM>
expand

HM>
structure

item_count: 8

table_size: 11

load_factor: 0.7273

0
: {(1819044183) Will : lost}

1
: {(1701538125) Mike : DM} {(121399204345156) Dustin : corny}
2
: {(435778057299) Steve : hairy}
3
: {(1651663170) Barb : ran-away?}


    • :

5 :

6 : {(521359221070) Nancy : torn}

7 :

8 : {(27717) El : weird} {(495555147084) Lucas : brash}

9 :


https://www.cs.umd.edu/~profk/216/p2.html    47/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


10 :

HM> save stranger.hm

HM> clear

HM> print

HM> structure

item_count: 0

table_size: 5

load_factor: 0.0000

    • :

1 :

2 :

3 :

4 :

HM> put Jim cop

HM> put Joyce worried

HM> print

Joyce : worried

Jim : cop

HM> structure

item_count: 2

table_size: 5

load_factor: 0.4000

0 :

1 : {(435460599626) Joyce : worried}

2 :

3 : {(7170378) Jim : cop}

4 :

HM> get Dustin

NOT FOUND

HM> get Joyce

FOUND: worried

HM> load stranger.hm

HM> print

Will : lost

Mike : DM

Dustin : corny

Steve : hairy

Barb : ran-away?

Nancy : torn

El : weird

Lucas : brash

HM> structure

item_count: 8


table_size: 11

load_factor: 0.7273

0 : {(1819044183) Will : lost}

1 : {(1701538125) Mike : DM} {(121399204345156) Dustin : corny}


2 : {(435778057299) Steve : hairy}

3 : {(1651663170) Barb : ran-away?}

https://www.cs.umd.edu/~profk/216/p2.html    48/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


    • :

5 :

6 : {(521359221070) Nancy : torn}

7 :

8 : {(27717) El : weird} {(495555147084) Lucas : brash}

9 :

10 :

HM> get Dustin

FOUND: corny

HM> get Joyce

NOT FOUND

HM> put Will found

Overwriting previous key/val

HM> put Nancy decided

Overwriting previous key/val

HM> put Mike girl-crazy

Overwriting previous key/val

HM> print

Will : found

Mike : girl-crazy

Dustin : corny

Steve : hairy

Barb : ran-away?

Nancy : decided

El : weird

Lucas : brash

HM> structure

item_count: 8

table_size: 11

load_factor: 0.7273

0 : {(1819044183) Will : found}

1 : {(1701538125) Mike : girl-crazy} {(121399204345156) Dustin : corny}

2 : {(435778057299) Steve : hairy}

3 : {(1651663170) Barb : ran-away?}

    • :

5 :

6 : {(521359221070) Nancy : decided}

7 :

8 : {(27717) El : weird} {(495555147084) Lucas : brash}

9 :

10 :

HM> next_prime 10

11


HM> next_prime 25

29

HM> expand

HM> structure


item_count: 8

table_size: 23

https://www.cs.umd.edu/~profk/216/p2.html    49/51
3/5/24, 8:25 PM    CMSC216 Project 2: Bit Ops, Debugging, Data Structures


load_factor: 0.3478

    • :

1 :

2 : {(27717) El : weird}

3 :

4 : {(1651663170) Barb : ran-away?} {(495555147084) Lucas : brash}

5 :

6 :

7 :

8 : {(121399204345156) Dustin : corny}

9 :

10 : {(521359221070) Nancy : decided}

11 : {(1701538125) Mike : girl-crazy} {(435778057299) Steve : hairy}

12 : {(1819044183) Will : found}

    13 :

    14 :

    15 :

    16 :

    17 :

    18 :

    19 :

    20 :

    21 :

    22 :

HM> save data/other.hm

HM> quit


5.6 Grading Criteria for P3  grading 40

The following criteria will be checked in this problem.


Weight    Criteria


AUTOMATED TESTS via make test-prob3

    20 test_hashmap.org tests

20 tests for hashmap_main executable, exercises functions in hashmap_funcs.c All tests run under Valgrind
1 point per test passed

Code compiles without warnings (make clean followed by make test-prob3 gives no errors/warnings) NOTE: run individual tests via make test-prob3 testnum=4

MANUAL INSPECTION

    15 hashmap_funcs.c

Clear commenting indicating intent during functions "calculate table index" or "iterate through list"

https://www.cs.umd.edu/~profk/216/p2.html    50/51
3/5/24, 8:25 PM
CMSC216 Project 2: Bit Ops, Debugging, Data Structures




Weight
Criteria


Relatively short functions: nothing needs to be too long (50 lines tops)

Clearly written iteration loops to traverse linked lists in hash map functions

Use of strcmp() to check keys during put/get operations

Concise and commented code for hashmap_put() which calculates table position and inserts into the list there

hashmap_free_table() frees all list elements and the table array, assigns 0/NULL to fields

hashmap_save() makes use of hashmap_write() with an open file handle to avoid redundant code

hashmap_load() checks that files open successfully and uses hashmap_free_table() to de-allocate memory File closed after finished during saving and loading
next_prime() is clearly written and easy to follow; the algorithm used is explained in comments

hashmap_expand() uses other functions in such as next_prime(), hashmap_init() and hashmap_free_table() to avoid repeating code.


    • hashmap_main.c

Comments indicating what high-level command is being implemented in each part of main Clear structure of main loop, reading commands, selecting actions
Use of string functions to identify which command to execute Clear efforts to honor -echo option and echo commands

Clear effort to free all memory prior to exit by clearing hashmap on exit































51/51

More products