THE SYLLABUS TASK
What you need to solve
Implement the Division Method hash function.
Two integers: nonnegative key (0–1,000,000), then table size m (1–1000). Prints an index only; collision resolution belongs to Week 12.
UNDERSTAND THE IDEA
Explanation
The division method maps a key k to k % m. The result is the remainder after division by the table size, so accepted nonnegative keys produce indexes 0…m−1.
Different keys can share a remainder. A hash function chooses an initial location; it does not by itself store values or resolve collisions.
Table-size choices interact with patterns in the keys. A prime size is often useful, but distribution depends on the actual data.
TURN THE IDEA INTO STEPS
Step-by-step algorithm
- Read the key and table size.
- Reject a negative key or zero/out-of-range size.
- Compute key % size.
- Print the resulting index.
SEE THE CONTROL FLOW
Flowcharts
Diamonds show decisions; labeled arrows select a branch. Returning arrows repeat work. Helper-function steps group the operations explained above and in the code. These charts focus on the named core operation. On a phone, scroll within the diagram or open the full-size version.
Compute one hash index
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
/* Read one entire token; reject malformed, oversized and out-of-range input. */
int readToken(char text[], size_t capacity) {
int ch; size_t used = 0; int fits = 1;
while ((ch = getchar()) != EOF && isspace((unsigned char)ch)) { }
if (ch == EOF) return 0;
do {
if (ch == 0) fits = 0;
if (used + 1 < capacity) text[used++] = (char)ch;
else fits = 0;
ch = getchar();
} while (ch != EOF && !isspace((unsigned char)ch));
text[used] = '\0';
return fits;
}
int readInt(int *value) {
char token[64], *end;
if (!readToken(token, sizeof token)) return 0;
errno = 0; long result = strtol(token, &end, 10);
if (errno || end == token || *end || result < -1000000 || result > 1000000) return 0;
*value = (int)result; return 1;
}
int invalid(void) { puts("Invalid or incomplete input."); return 1; }
int hash(int key, int size) { return key % size; }
/* Nonnegative key (0..1,000,000), table size (1..1000). Index only, no table insertion. */
int main(void) {
int key, size;
if (!readInt(&key) || !readInt(&size) || key < 0 || size < 1 || size > 1000) return invalid();
printf("Hash index: %d\n",hash(key,size)); return 0;
}
Local compile: gcc -std=c17 division-hash.c -o program -lm
Open in C compiler transfers the source. Copy the sample input into the compiler’s input box separately before running.
UNDERSTAND THE CODE
Line-by-line explanation
Follow the exact source above, from input handling through the algorithm and its result. Line numbers count blank lines; related statements are grouped into steps. Start with main to follow execution, then open the functions it calls.
Start with main → · Algorithm and data structure →
Lines 1–5Include input, conversion and validation declarations
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>stdio.h supplies terminal input/output. stdlib.h declares conversion and allocation functions. string.h supplies string and memory utilities. ctype.h supplies isspace, and errno.h supplies conversion error reporting. Headers declare facilities; including them does not execute an operation.
Lines 7–9Define a complete-token reader and initialise its state
/* Read one entire token; reject malformed, oversized and out-of-range input. */
int readToken(char text[], size_t capacity) {
int ch; size_t used = 0; int fits = 1;readToken receives a writable buffer and its capacity. ch is int so it can represent EOF as well as input characters. used counts stored characters, and fits starts as a success flag. One slot must remain for the null terminator.
Lines 10–11Skip leading whitespace and recognise end-of-file
while ((ch = getchar()) != EOF && isspace((unsigned char)ch)) { }
if (ch == EOF) return 0;Read until a non-whitespace character appears. The unsigned-char cast supplies an allowed value to isspace. Return 0 if EOF arrives before a token begins.
Lines 12–15Collect a token without silently truncating it
do {
if (ch == 0) fits = 0;
if (used + 1 < capacity) text[used++] = (char)ch;
else fits = 0;The do body handles the character already read. An embedded zero byte marks the token invalid. Store a character only while there is room for it and a null terminator; otherwise clear fits. Continue reading even after the buffer fills.
Lines 16–20Consume the full token and terminate the buffer
ch = getchar();
} while (ch != EOF && !isspace((unsigned char)ch));
text[used] = '\0';
return fits;
}Read through the next whitespace or EOF, add a null character after the stored prefix, then return fits. A too-long token returns 0 rather than pretending that its stored prefix is the complete token.
Lines 21–23Wrap token input as a checked integer read
int readInt(int *value) {
char token[64], *end;
if (!readToken(token, sizeof token)) return 0;value is an output address. A 64-slot local buffer receives the token; a failed token read returns 0 before attempting conversion.
Lines 24–25Convert base-ten text and check the whole result
errno = 0; long result = strtol(token, &end, 10);
if (errno || end == token || *end || result < -1000000 || result > 1000000) return 0;Reset errno before strtol. &end receives the stopping address. Reject conversion errors, no converted digits, leftover characters, or values outside -1,000,000 to 1,000,000. Thus 12x is not accepted as the integer 12.
Lines 26–28Return the accepted value or a standard error status
*value = (int)result; return 1;
}
int invalid(void) { puts("Invalid or incomplete input."); return 1; }Store a validated integer through *value and return 1 from readInt. invalid is a separate helper that prints the error and returns 1 as main’s failure status; the same number has different roles in these two function contracts.
Line 30Use the remainder as the table index
int hash(int key, int size) { return key % size; }key % size maps the accepted nonnegative key into indexes 0 through size - 1. For key 25 and size 11, the result is 3. The caller ensures size is positive.
Lines 31–32Document an index-only hash demonstration
/* Nonnegative key (0..1,000,000), table size (1..1000). Index only, no table insertion. */
int main(void) {The input is a nonnegative key followed by a table size. The program calculates an index only; it does not store keys or resolve collisions.
Lines 33–34Read a valid key and positive table size
int key, size;
if (!readInt(&key) || !readInt(&size) || key < 0 || size < 1 || size > 1000) return invalid();readInt already limits integer magnitude. Require key >= 0 and size from 1 to 1000, preventing zero-divisor calculations and negative table indexes.
Lines 35–36Print the calculated index and finish
printf("Hash index: %d\n",hash(key,size)); return 0;
}Call hash(key,size), display the returned index and return success. A valid hash index need not be unique: different keys can still collide.
FOLLOW THE VALUES
Dry run
- For key 1234 and m = 100, division gives 12 with remainder 34.
- Therefore h(1234) = 34.
- Key 1334 also maps to 34, demonstrating a collision.
CHECK THE BEHAVIOUR
Sample input & output
These outputs were captured by running the exact C source shown above. Commands use the stated input format; the programs omit repeated menu prompts so the same sample can be pasted and run.
Sample 1
1234 100
Hash index: 34
Sample 2
0 11
Hash index: 0
Sample 3
1000000 97
Hash index: 27
Common mistakes
- Never divide by a zero table size.
- Negative C remainder can be negative; this version rejects negative keys.
- A matching hash index is not evidence of equal keys.
WHY THIS GROWTH RATE?
Time and space complexity
O(1) time and O(1) extra space under fixed-width arithmetic.
The calculation uses one integer remainder operation, followed by output; its operation count does not depend on how many keys a separate table stores.
This assumes bounded machine integers. Arbitrary-precision keys would require accounting for their digit or bit length.
This page computes a single index rather than inserting into an allocated hash table.
Big-O describes growth in the stated input quantity. The educational limits keep examples safe; complexity discussions state which bounds depend on a generalized input size. Arithmetic on the accepted native numeric types is treated as constant-time.
PREPARE FOR YOUR LAB VIVA
Related viva questions & answers
Try answering aloud, then expand the answer to check your reasoning. These questions focus on the concepts used in this program.
Why is k % m a valid index for accepted inputs?
With a nonnegative key and positive m, the remainder lies from zero through m - 1. Those are exactly the indexes of a table with m slots.
Can keys that differ by exactly m collide?
Yes. Adding a multiple of m leaves the remainder unchanged, so k and k + m map to the same initial slot.
What happens if the table size is one?
Every accepted key maps to index zero. The calculation remains valid, although a stored table would place every key in the same bucket.
Why can a power-of-ten table size be sensitive to key endings?
Remainder by 10 or 100 is controlled by the final decimal digits. Keys sharing those endings can cluster despite differing significantly elsewhere.
Does choosing a prime table size eliminate all collisions?
No. There are still only m possible indexes, and sufficiently many distinct keys must share one. A prime can improve some distributions but cannot make the mapping universally unique.
Why are negative keys excluded from this division example?
C can produce a negative remainder for a negative dividend. Exclusion keeps the index contract simple; a signed-key variant would normalize the remainder explicitly.