CMSC216 Project 2: Bit Ops, Debugging, Data Structures

$45.00 $39.00

This project addresses more advanced C programming topics each in its own problem. 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. Debugging is also a critical skill enabled by the debugger. The second problem in the assignment…

5/5 – (2 votes)

You’ll get a: zip file solution

 

Categorys:
Tags:

Description

5/5 – (2 votes)

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.

  1. 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”.

  2. 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

  1. 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

  1. -45.0 Remainder rounded down

  1. -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.

  1. 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.

  2. Account for the offset from -45.0 deg C by subtracting.

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

  1. 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

  1. 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 :

    1. :

  • 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}

  1. :

  1. :

  1. :

  1. :

  1. :

  1. :

  1. :

  1. :

  1. :

  1. :

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

  1. 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}

  1. :

  1. :

  1. :

  1. :

  1. :

  1. :

  1. :

  1. :

  1. :

  1. :

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

  1. 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

  1. 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

CMSC216 Project 2: Bit Ops, Debugging, Data Structures
$45.00 $39.00