C-1
C-1
TRIBHUVAN UNIVERSITY
INSTITUTE OF ENGINNERING
PULCHOWK CAMPUS
PROJECT REPORT ON
EDUQUIZ SYSTEM
SUBMITTED BY:
SUBMITTED TO:
HIMANSHU CHAND(081BCT034)
DEPARTMENT OF
ISHAN GAUTAM(081BCT035) ELECTRONICS
AND
JANAK BHATTA(081BCT036) COMPUTER
ENGINEERING
2|Page
ACKNOWLEDGEMENT
We would like to express our sincere gratitude to our instructor Santosh
Giri for providing us with guidance and encouragement throughout this
project. We also extend our appreciation to the Institute of Engineering,
Pulchowk Campus, for offering the necessary resources and environment
to complete this project.
Additionally, we thank our friends and family for their unwavering support
and motivation, which played a crucial role in the successful completion of
this project.
Lastly, we express our gratitude to the countless authors, researchers, and
professionals whose work served as a foundation for our project. Their
contributions have been instrumental in shaping our understanding and
approach to the subject matter.
This project would not have been possible without the support,
guidance, and inspiration of all those mentioned above.
Sincerely,
Himanshu Chand
Ishan Gautam
Janak Bhatta
i|Page
TABLE OF CONTENTS
ii | P a g e
Algorithm 6: Input Validation
Algorithm
Algorithm 7: Question File Handling
Algorithm
Algorithm 8: Quiz Score Calculation
Algorithm
iii | P a g e
ABSTRACT
The Quiz Game System is a C-based console application designed to
provide an interactive quiz experience for players and a secure
management interface for administrators. Developed as part of a practical
exploration of C programming, it aims to enhance user engagement
through timed gameplay while offering a platform for administrators to
update content. This dual-purpose tool reflects its educational intent,
fostering both technical skill development and knowledge assessment
within a campus environment.
iv | P a g e
v|Page
INTRODUCTION
1. Background and Problem Statements:
The growing emphasis on interactive learning tools and engaging
educational experiences has spurred the need for innovative software
solutions in academic settings. To address this, we developed the Quiz
Game System using the C programming language, aiming to create a
structured, real-time quiz platform that captivates players while
integrating essential programming concepts. The system targets both
entertainment and education, offering a dynamic alternative to traditional,
static quiz methods that often lack immediacy and interactivity.
2. Objectives:
To enhance logical reasoning and problem-solving skills through C
programming.
To apply theoretical knowledge of C in a real-world application.
To develop a mini database system for storing quiz questions using
file handling.
To foster teamwork and task division among group members.
1|Page
To simplify complex problems, such as time management, using C
constructs.
3. Features:
The Interactive Quiz System includes the following features to ensure
efficiency and usability:
Password-protected admin module for adding questions.
Timed quiz gameplay with a 20-second limit per question,
implemented using threading.
File handling for persistent storage of questions in a binary file.
Real-time scoring and feedback during quiz play.
4. Limitations:
PROBLEM ANALYSIS
1. Understanding the problem:
Our team aimed to create a reliable, interactive quiz system. We decided
to use C’s file handling for data persistence, threading for time limits, and
string operations for user interaction, ensuring a professional and
engaging application.
2. Feasibility:
The project required foundational C programming skills, teamwork, and
logical reasoning. Time management was critical amidst regular
coursework. We ensured feasibility by leveraging classroom knowledge
and supplementing it with online resources.
3. Input requirements:
Users input menu choices (1-3), admin passwords, quiz answers (1-4), and
question details (text and correct options). The system must handle these
inputs robustly.
4. Processing Requirements:
2|Page
A 32-bit or higher OS is needed, with support for threading (Windows-
specific in this case). The system processes inputs, manages timers, and
updates files without crashing on invalid inputs.
5. Output Requirements:
Outputs include menu prompts, quiz questions with options, real-time
timer updates, and final scores, all displayed clearly on the screen.
THEORY OVERVIEW
C is a general-purpose, procedural programming language developed by
Dennis Ritchie at Bell Labs in the early 1970s. Renowned for its efficiency,
portability, and ability to access low-level memory through pointers, C is
extensively utilized in system programming, embedded systems, and
performance-critical applications. It has significantly influenced modern
languages such as C++, C#, and Objective-C, offering a balance between
high-level abstraction and low-level control. However, C lacks modern
safety features like automatic memory management, placing the burden
on programmers to manage resources meticulously. This section explores
essential C concepts, including preprocessor directives, input/output,
control statements, functions, arrays, strings, structures, pointers, and file
handling, providing a foundation for understanding its theory and
application. These concepts are exemplified in practical contexts, such as
the library management system header (headers.h) provided, which uses
structures, pointers, and standard library functions to manage users,
books, and transactions.
1. Preprocessor Directives:
Preprocessor directives are instructions beginning with the # symbol,
executed before the compilation process begins. They modify the source
code by including external files, defining constants, or enabling conditional
compilation.
#include: Incorporates external files into the program. For
instance,#include<stdio.h> includes the standard input/output library,
providing access to functions like printf and scanf.
#define: Defines macros, which can represent constants or expressions.
For example, #define PI 3.14159 creates a constant, while #define
SQUARE(x) ((x) * (x)) defines a macro to compute the square of a value.
#ifdef, #ifndef, #endif: Facilitate conditional compilation, allowing code
blocks to be included or excluded based on whether a macro is defined.
Example:
#define VALUE 10
3|Page
#include<stdio.h>
int main{
printf(“value: %d”, VALUE);
return 0;
}
In this code, the preprocessor replaces VALUE with 10 before compilation,
and stdio.h provides the printf function to display the value.
2. Input and Output:
Input and output (I/O) operations in C are facilitated by functions from the
stdio.h header, categorized into unformatted and formatted I/O. These
operations enable interaction between the program and external devices,
such as the keyboard (input) and screen (output).
2.1. Unformatted I/O:
Unformatted I/O functions handle raw data without specific formatting,
offering simplicity but limited control.
getchar():Reads a single character from the standard input (typically
the keyboard) and returns it as an integer value. This function is
useful for character-by-character input processing.
putchar(ch): Outputs a single character, specified by the variable ch,
to the standard output (typically the screen). It is often used in loops
to display strings character by character.
puts(str): Writes a string, followed by a newline character (\n), to the
standard output. It is a convenient way to output messages or
prompts.
Example:
#include<stdio.h>
int main{
char ch;
printf(“Enter a character\n”);
ch=getchar();
printf(“You’ve entered\n”);
putchar(ch);
return 0;
4|Page
}
Here, getchar() captures a character entered by the user, putchar(ch)
displays it, and puts adds a message with a newline. This demonstrates
basic unformatted I/O for character and string manipulation. Note that
getchar() returns an integer to accommodate special values like EOF (end-
of-file), which is useful in file operations.
5|Page
In this program, scanf reads an integer (age), a float (height), and a string
(name) from the user, using & for age and height to specify their memory
addresses.
For name, no & is needed because name is already a pointer to the array's
first element. printf then displays these values, formatting height to two
decimal places. The format specifiers ensure that the input is parsed
correctly and the output is presented in a readable form. In headers.h,
printf is used for user interaction (e.g., in print header), and scanf may be
used to input user data like username or book_id.
Key Note: Omitting the & in scanf for non-pointer variables can lead to
runtime errors or undefined behavior, as it expects memory addresses
rather than values. Additionally, scanf can fail if the input does not match
the expected format, so robust programs should check its return value (the
number of successfully assigned items).
3. Pointers:
Pointers are variables that store memory addresses, offering powerful
capabilities for direct memory manipulation, dynamic memory allocation,
and efficient data handling. They are a cornerstone of C programming,
enabling low-level control and distinguishing C from higher-level
languages.
3.1. Declaration and Initialization:
A pointer is declared with an asterisk (*) and must point to a specific data
type, ensuring type safety when accessing the data it addresses. It is
initialized with the address of a variable using the address-of operator (&).
Declaration: int *ptr; declares a pointer to an integer. The asterisk
indi-cates that ptr will hold the address of an integer, not the integer
itself.
Initialization: int x 10; ptr &x; assigns the address of x to ptr. The &
operator retrieves the memory address of x, which is typically a hex-
adecimal value (e.g., 0x7ffee).
3.2. Dereferencing:
Dereferencing a pointer with the asterisk (*) accesses the value stored at
the address it points to, allowing both reading and writing of the data.
Dereference: *ptr retrieves or modifies the value of x (e.g., reading
yields 10, writing *ptr = 20 changes x to 20).
Example:
#include <stdio.h>
6|Page
int main() {
int x 10; int *ptr &x; printf(" Address of x: %p\n", (void*)ptr);
printf("Value of x via pointer: %d\n", *ptr);
*ptr 20; // Modify x via pointer
printf("New value of x: %d\n", x);
return 0;
}
Here, ptr holds the memory address of x, displayed using the %p specifier
(with a cast to void* to ensure portability). Dereferencing *ptr yields the
value 10, and assigning *ptr 20 updates x, illustrating how pointers
provide indirect access to data. The output shows the address, the initial
value, and the modified value, demonstrating pointer manipulation.
3.3. Pointer Arithmetic:
Pointers can be incremented or decremented to navigate memory
locations, with the offset scaled by the size of the data type (e.g., 4 bytes
for an integer on most systems). This is particularly useful for array
traversal, where array elements are stored contiguously.
Increment: ptr + 1 moves the pointer to the next integer's memory
loca-tion, adding 4 bytes to the address if int is 4 bytes.
Decrement: ptr 1 moves it backward similarly.
#include <stdio.h>
int main() {
int arr[3] = {10, 20, 30};
int *ptrarr; // Points to arr[0]
for (int i=0; i < 3; i++) {
printf("%d", *ptr);
ptr++; // Moves to the next integer
return 0;
}
In this array example, ptr initially points to arr[0]. Each ptr++ advances it
to the next element, printing 10, 20, and 30. This demonstrates pointer
arithmetic in traversing arrays, where the array name arr acts as a pointer
to its first element. Pointer arithmetic is scaled automatically by the
7|Page
compiler, so ptr++ adds the size of int, not just 1 byte, ensuring correct
alignment with data elements.
3.4. Pointers in Function:
Pointers enable pass-by-reference, allowing functions to modify the
original vari-ables passed to them, unlike pass-by-value, where only copies
are modified. This is achieved by passing the addresses of variables, which
the function dereferences to access and alter the original data.
Function Definition: void swap(int *a, int *b) { int temp =* a ; *a *b: *
b = temp; }
Function Call: swap(&x, &y); passes the addresses of x and y.
Example:
#include <stdio.h>
void swap(int *a, int b) {
int temp *a;
* a =*b;
* b = temp;
}
int main() {
int x = 5 , y = 10;
printf(" Before swap: x =\%d, y =\%d backslash n^ prime prime ,x,y) ;
swap(&x, &y);
printf(" After swap: x =\%d y =\%d backslash n^ " ,x,y) // Outputs: x: 10,
y:5
return 0;
}
The swap function uses pointers to exchange the values of x and y by
accessing and modifying their memory locations directly. Without pointers,
swap would only modify local copies, leaving x and y unchanged. This
example highlights the power of pointers in enabling efficient, direct data
manipulation. In headers.h, pointers to structures (e.g., User *user in
authenticate_user) allow functions to modify user data directly.
3.5. Dynamic memory allocation:
8|Page
Pointers facilitate runtime memory allocation using functions from stdlib.h,
such as malloc, calloc, and realloc. These functions allocate memory
dynamically, allowing programs to adapt to variable data sizes, unlike
static arrays with fixed sizes.
Allocation: int *p= malloc(sizeof(int) * 5); allocates memory for 5
integers and returns a pointer to the first byte. malloc does not
initialize the memory, so it may contain garbage values.
Initialization: int *p = calloc(5, sizeof(int)); allocates and initializes
the memory to zero.
Reallocation: p= realloc(p, sizeof(int) 10); resizes the memory block,
preserving existing data if possible.
Deallocation: free(p); releases the memory, preventing leaks.
#include <stdio.h>
#include <stdlib.h>
int main() {
int * p = malloc(sizeof(int) * 3); printf ("Memory allocation failed\n");
if (p NULL) {
return 1;
} for (int i = 0 i < 3 i++) {
p[i] = i + 1;
}
for (int i = 0 ; i < 3 i++) {
printf("%d", p[i]);
}
free (p);
return 0;
}
This program allocates memory for 3 integers, initializes them, prints them
(1, 2, 3), and frees the memory. The if (p== NULL) check ensures
robustness, as malloc returns NULL if allocation fails (e.g., due to
insufficient memory). The sizeof operator is used here to determine the
size of int, ensuring portable memory allocation.
9|Page
Key Point: Always free dynamically allocated memory when it is no longer
needed to avoid memory leaks, a common issue in C programming where
allocated memory is not released, leading to resource exhaustion over
time.
4. Control Statements:
Control statements direct the flow of execution through decision-making
and repetition, allowing programs to make choices or repeat actions based
on conditions.
4.1. Selective Structures:
Selective structures evaluate conditions to determine which code block to
execute.
if: Executes code if a condition is true. For example, if (x > 0) printf
("Positive"); checks if x is positive and prints a message if true.
if-else: Provides an alternative for false conditions. For example, else
printf("Non-positive"); prints a message if x is not positive.
if-else-if: Handles multiple conditions. For example, if (x > 0)
printf("Positive"); else if (x < 0) printf("Negative"); else printf("Zero");
categorizes x as positive, negative, or zero.
4.2. Looping Structures:
Looping structures repeat a block of code until a condition is met or for a
specified number of iterations.
for: Executes a fixed number of iterations, typically using a loop
counter. For example, for (int i = 0 i < 5 i++) loops 5 times,
incrementing i from 0 to 4.
while: Repeats while a condition is true, checking the condition
before each iteration. For example, while (i < 5) continues as long as
i is less than 5.
do-while: Similar to while, but ensures at least one execution by
checking the condition after each iteration. For example, do {...}
while (i < 5); executes the block at least once.
Example:
#include <stdio.h>
int main() {
for (int i=0; i<10; i++) {
10 | P a g e
if (i==5) break; // Exits loop at 5
printf("%d", i);
}
return 0;
}
This loop prints 0 to 4, terminating early with break when i equals 5. The
break statement is useful for exiting loops prematurely based on a
condition, such as finding a specific value in a search.
5. Functions:
Functions modularize code, enhancing reusability and organization. Every
C program starts execution with the main function, and additional
functions can be defined to perform specific tasks. Functions consist of a
declaration, definition, and call.
Declaration: Specifies the function's interface, including its return
type, name, and parameters. For example, int add(int a, int b);
declares a function that returns an integer and takes two integer
parameters.
Definition: Implements the function's logic. For example, int add(int
a, int b) { return a+b; } defines the add function to return the sum of
its parameters.
Call: Invokes the function, passing arguments. For example, add (3,
4); calls add with 3 and 4, returning 7.
Functions can be categorized as library functions (predefined in standard
libraries) or user-defined functions (created by the programmer). They
support pass-by-value (where arguments are copied) and pass-by-
reference (using pointers, as dis-cussed earlier). In headers.h, function
prototypes void AddQuestions() and void CheckPassword() declare user-
defined functions for adding questions and checking password
respectively.
Example (Recursion):
#include <stdio.h>
int factorial (int n) {
if (n <= 1) return 1; // Base case
return n*factorial (n-1); // Recursive call
}
11 | P a g e
int main() {
printf("Factorial of 5: %d\n", factorial (5)); // Outputs: 120
return 0;
}
This recursive function computes 5! (5 x 4 x 3 x 2 x1=120). Recursion
involves a function calling itself with a modified parameter until a base
case is reached, here n <= 1. Recursive functions are powerful for
problems with a recursive structure, like factorials or tree traversals, but
require careful design to avoid infinite recursion or stack overflow.
6. Arrays:
Arrays store elements of the same type in contiguous memory locations,
accessed by zero-based indices. They are useful for managing collections
of data, such as lists of numbers or characters.
Declaration: int arr [5] = {1, 2, 3, 4, 5); declares an array of 5
integers, initializing it with values. Uninitialized elements are set to 0
if the array is partially initialized, or contain garbage values if not
initialized at all.
Access: arr[0] retrieves the first element (1), arr[1] the second (2),
and so on. Indices range from 0 to size-1, and accessing beyond
these bounds causes undefined behavior, a common source of bugs
in C.
Arrays can be multidimensional, such as two-dimensional arrays for
matrices (e.g., int matrix [3] [4];). In headers.h, arrays are used within
structures (e.g., char option), defining fixed-size buffers for strings like
questions and options.
Example:
#include <stdio.h>
int main() {
int arr [3] {10, 20, 30};
for (int i=0; i < 3; i++) {
printf("%d", arr[i]);
}
return 0;
}
12 | P a g e
This program prints 10, 20, and 30, iterating over the array using a for
loop. The array name arr is a pointer to its first element, enabling pointer
arithmetic as shown in the pointers section.
7. Strings and Manipulation:
Strings in C are character arrays terminated by a null character (10), which
marks the end of the string. They are manipulated using functions from
the string.h header, providing operations like copying, concatenation, and
comparison.
Declaration: char str[10]= "Hello"; declares a string with space for 10
characters, including the 0. The string "Hello" occupies 6 bytes (5
letters + \0).
Manipulation Functions:
- strcpy(dest, src): Copies the string src (including (0) to dest. The
destination must have enough space, or a buffer overflow occurs.
- strcat (dest, src): Concatenates src to the end of dest, overwriting
dest's 0 and adding a new one.
- strlen(str): Returns the length of str, excluding 0.
- strcmp(str1, str2): Compares str1 and str2 lexicographically, re-
turning 0 if equal, a negative value if str1 < str2, and a positive
value if str1> str2.
Example:
#include <stdio.h>
include <string.h> #
int main() {
char str[20];
strcpy(str, "Hello");
printf("Length: %zu\n", strlen(str)); // Outputs: 5
strcat(str, "World");
printf("Concatenated: %s\n", str); // Outputs: Hello World
return 0;
}
This program copies "Hello" into str, prints its length (5), and appends"
World", demonstrating string manipulation. Note that str must be large
13 | P a g e
enough to hold the concatenated result (11 characters, including (\0), or
undefined behavior occurs.
8. Structures:
Structures group variables of different types under a single name, useful
for repre-senting complex data entities like records or objects. They
enhance code readability and organization by allowing related data to be
managed together.
Definition:
struct Student {
char name [50];
int age;
};
Defines a structure Student with two members: a character array name
and
an integer age.
Declaration and Initialization: struct Students = {"Alice", 20};
declares a variable s of type Student and initializes it.
Access: Members are accessed using the dot operator (.), e.g., s.
name or s.age.
Structures can be nested (a structure within a structure) or used in arrays
(e.g., struct Student class [10]; for a class of 10 students).
Example:
#include<stdio.h>
struct Student{
char name [50];
int age;
};
int main() {
struct Students = {"Alice", 20};
printf("%s, %d\n", s.name, s.age);
return 0;
}
14 | P a g e
This program defines a Student structure, initializes an instance, and prints
its members, outputting "Alice, 20". Structures are particularly useful in
applications requiring grouped data, such as databases or configuration
settings.
9. File handling:
File handling in C enables reading from and writing to files, allowing data
persis-tence beyond program execution. Operations are performed using
FILE pointers and functions from stdio.h.
Opening a File: FILE *fp = fopen("file.txt", "mode"); opens a file in a
specified mode (e.g., "r" for reading, "w" for writing, "a" for
appending). If the file cannot be opened (e.g., due to non-existence
in read mode), fopen returns NULL.
Closing a File: fclose(fp); closes the file, flushing any buffered data
and freeing resources.
Formatted I/O:
- fprintf(fp, "format", var1, var2, ...): Writes formatted data to the file,
similar to printf.
- fscanf (fp, "format", &var1, &var2, ...): Reads formatted data from
the file, similar to scanf.
String I/O:
- fputs(str, fp): Writes a string to the file.
- fgets(str, size, fp): Reads up to size-1 characters or until a new-line
or end-of-file, storing the result in str.
End of File (EOF): EOF is a macro indicating the end of a file, typically
-1. Functions like fscanf return EOF when no more data can be read.
Example:
#include <stdio.h>
int main() {
FILE *fp fopen("test.txt", "w");
if (fp== NULL)
{
printf("Error opening file\n");
return 1;
}
15 | P a g e
fprintf(fp, "Hello, File!");
fclose(fp);
fpfopen("test.txt", "r");
if (fp ==NULL) {
printf("Error opening file\n");
return 1;
}
char buffer [50];
fgets (buffer, 50, fp);
printf("Read from file: %s\n", buffer);
fclose(fp);
return 0;
}
This program writes "Hello, File!" to test.txt, then reads and prints it. The if
(fp==NULL) checks ensure robustness by handling file opening failures,
which could occur due to permission issues or file non-existence. File
handling is crucial for applications requiring data storage.
16 | P a g e
Outputs formatted text to the console.
Uses format specifiers (%s for strings, %d for integers, etc.).
Returns the number of characters printed or a negative value on
error.
Example (Displaying quiz question):
printf("\n%s", q.question);
Usage in Project: Used to display quiz questions and options.
1.2. scanf()
syntax:
scanf ("format", &var1, &var2, ...);
Functionality:
Reads formatted input from the user and stores values in variables.
Requires & for passing addresses of variables (except for strings).
Returns the number of successfully assigned items or EOF on failure.
Example (Getting user input for answer selection):
scanf("%d", &answer);
Usage in Project: Captures user answers in the quiz.
1.3. fopen()
Syntax:
FILE *fopen(const char *filename, const char *mode);
Functionality:
Opens a file in the specified mode ("r", "w", "a", "rb", "wb", etc.).
Returns a pointer to FILE or NULL on failure.
Example (Opening quiz file for reading):
FILE* fp = fopen("quiz.dat", "rb");
Usage in Project: Reads quiz questions stored in a binary file.
1.4. fwrite()
syntax:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
17 | P a g e
Functionality:
Writes data from memory (ptr) to a file.
Returns the number of elements written successfully.
Example (Saving quiz questions to a file):
fwrite(&q, sizeof(QUESTIONS), 1, fp);
Usage in Project: Used in AddQuestions() to store quiz data persistently.
1.5. fread()
Syntax:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
Functionality:
Reads data from a file into memory.
Returns the number of elements successfully read.
Example (Reading quiz questions from a file):
fread(&q, sizeof(QUESTIONS), 1, fp);
Usage in Project: Retrieves stored quiz data for gameplay.
1.6. fclose()
Syntax:
int fclose(FILE *stream);
Functionality:
Closes a file and flushes the output buffer.
Returns 0 on success or EOF on error.
Example (Closing the file after writing questions):
fclose(fp);
Usage in Project: Ensures proper file handling to avoid memory leaks.
18 | P a g e
2.1. strcmp()
Syntax:
int strcmp(const char *str1, const char *str2);
Functionality:
Compares two strings lexicographically.
Returns 0 if they are equal, a negative value if str1 is less than str2,
and a positive value if str1 is greater.
Example (Checking if user input matches password):
if (strcmp(input_pass, PASSWORD) != 0) {
printf("Wrong password\n");
}
Usage in Project: Used for password verification in CheckPassword().
2.2. strcpy()
Syntax:
char *strcpy(char *dest, const char *src);
Functionality:
Copies the string src into dest, including the null terminator (\0).
The destination buffer must be large enough to hold the copied
string.
Example (Copying a question into a structure):
strcpy(q.question, "What is 2+2?");
Usage in Project: Used when adding new questions.
2.3. strlen()
Syntax:
19 | P a g e
size_t strlen(const char *str);
Functionality:
Returns the length of a string (excluding the null terminator).
Example (Validating password length):
if (strlen(input_pass) < 6) {
printf("Password too short!\n");
}
Usage in Project: Ensures valid input length.
20 | P a g e
Syntax:
void *malloc(size_t size);
void free(void *ptr);
Functionality:
malloc() dynamically allocates memory.
free() deallocates memory to prevent leaks.
Example (Allocating memory for a question):
QUESTIONS *q = (QUESTIONS*) malloc(sizeof(QUESTIONS));
Usage in Project: Could be used for dynamically handling quiz data.
21 | P a g e
Creates a new thread to run a function concurrently.
Example (Starting a countdown timer in a separate thread):
HANDLE timerThread = CreateThread(NULL, 0, countdownTimer, NULL, 0,
&threadID);
Usage in Project: Runs the countdown timer while waiting for user input.
5. time.h-Time Management:
The time.h library provides functions to manage and track time.
5.1. time()
Syntax:
time_t time(time_t *timer);
Functionality:
Gets the current system time.
Usage in Project: Could be used to track quiz duration or timestamps.
22 | P a g e
6.2. #define(Macro definition)
Syntax:
#define MACRO_NAME value
Functionality:
Defines a macro or constant for use throughout the program.
Replaces instances of MACRO_NAME with value during
preprocessing.
Example (Defining constants for password and time limit):
#define PASSWORD "IMGROOT"
#define TIME_LIMIT 20
Usage in Project:
Used to set predefined values like the admin password and quiz
timer.
23 | P a g e
#define TIME_LIMIT 20
#endif
Usage in Project:
Protects header files from being included multiple times, preventing
compilation errors.
7. Main Algorithm
The Quiz Game System begins its execution in the main.c file, where the
program continuously displays a menu for the user. The user can choose to
add quiz questions (if they have admin access), play the quiz, or exit the
program. If the user selects the admin function, they must enter a
password before they are allowed to add new quiz questions. If they
choose to play the quiz, the program reads questions from a binary file
(quiz.dat) and starts the game. This main loop continues running until the
user selects the exit option, ensuring a structured and interactive
experience.
9. Menu Functions
The Quiz Game System features a structured menu that allows users to
navigate through different functionalities. The main menu provides three
primary options: adding quiz questions (admin-only), playing the quiz, and
exiting the program. If the user is an admin, they can access a submenu
where they can input new quiz questions along with four answer choices
and specify the correct option. Meanwhile, players who choose to take the
quiz are directed to a separate section where questions are loaded from a
file and presented one by one. This menu-driven approach enhances
24 | P a g e
usability, ensuring that both administrators and players can efficiently
interact with the system.
25 | P a g e
The system relies on file handling to store and retrieve quiz questions
efficiently. When an administrator adds new questions, they are written to
a binary file (quiz.dat) using the fwrite() function. During gameplay, the
quiz questions are loaded from the same file using fread(), ensuring that
the stored data remains intact across multiple quiz sessions. Proper file
handling techniques are used to prevent errors, such as ensuring that the
file is successfully opened before attempting to read or write data. By
using a binary file format, the system optimizes storage space and
enhances data integrity.
26 | P a g e
2. Get User Input for Choice
3. If choice = 1,
Execute CheckPassword()
4. Else if choice = 2,
Execute PlayQuiz()
5. Else if choice = 3,
print exit message and break loop.
6. Else,
print an invalid input message and repeat.
7. End Program
27 | P a g e
5. End
28 | P a g e
2. Prompt user for input (1-4)
3. Repeat until input is valid:
If input is not an integer or not in range, display an error and ask
again.
If time runs out, skip input validation.
4. Return valid input.
5.end
29 | P a g e
Flowchart for Main Program
Start
Display Main
Menu:
1.Add Questions
2.Play Quiz
3.Quit
30 | P a g e
Read
Choice
from user
Call Call
CheckPasswor PlayQuiz( Stop
d() )
31 | P a g e
Flowchart for AddQuestions()
Start
Open file in
Appending
Mode
Input
Question
Input
Options (1-
4)
Input Correct
Option
Yes
Add
more?
No
Back to Main
Menu
32 | P a g e
Flowchart for PlayQuiz()
Start
Open Question
file in reading
mode
Display
Questions and
Options
Time Answer
up? received?
Yes Yes
Next
Questio
n?
No
Display Final Stop
Score
33 | P a g e
Flowchart for Timer Thread
Start
Start 20 second
countdown
Yes Stop
Set time up
Flag
Stop
34 | P a g e
Flowchart for CheckPassword()
Start
Read
password
from user
No
Password
== Display
‘IMGROO Error
T’
Yes
Go to
Call main
AddQuestions menu
()
SOURCE CODE
35 | P a g e
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <windows.h>
typedef struct {
char question[100];
char option[4][100];
int correctopt;
} QUESTIONS;
36 | P a g e
Sleep(1000);
}
timeUp = 1;
printf("\nTime's up! Moving to next question...\n");
return 0;
}
void AddQuestions();
void CheckPassword();
void PlayQuiz();
void ReviewIncorrectAnswers();
int main() {
int choice;
while (1) {
printf("\nWhat do you want to do?\n1. Add questions (Only admins)\
n2. Play Quiz\n3. Quit\nYour choice: ");
choice = getValidInteger();
if (choice == 1)
37 | P a g e
CheckPassword();
else if (choice == 2)
PlayQuiz();
else if (choice == 3) {
printf("\nExiting.....\n");
break;
}
else {
printf("Enter a proper number.\n");
}
}
return 0;
}
void AddQuestions() {
FILE* fp = fopen("quiz.dat", "ab");
if (!fp) {
printf("\nError opening file.....\n");
return;
}
QUESTIONS q;
char opt;
do {
getchar(); // Clear leftover newline
printf("Enter question: ");
fgets(q.question, sizeof(q.question), stdin);
q.question[strcspn(q.question, "\n")] = 0; // Remove newline
38 | P a g e
for (int i = 0; i < 4; i++) {
printf("Enter option %d: ", i + 1);
fgets(q.option[i], sizeof(q.option[i]), stdin);
q.option[i][strcspn(q.option[i], "\n")] = 0; // Remove newline
}
fclose(fp);
}
void CheckPassword() {
printf("Enter password: ");
char input_pass[20];
39 | P a g e
scanf("%s", input_pass);
if (strcmp(input_pass, PASSWORD) != 0) {
printf("Wrong password! Returning to main menu...\n");
return;
} else {
AddQuestions();
}
}
void PlayQuiz() {
FILE* fp = fopen("quiz.dat", "rb");
if (!fp) {
printf("Error opening file. Returning to main menu...\n");
return;
}
QUESTIONS q;
int score = 0, total = 0, answer;
HANDLE timerThread;
DWORD threadID;
timeUp = 0;
printf("\n%s", q.question);
strncpy(questionsList[total], q.question, 100); // Save question
40 | P a g e
// Save options for this question
for (int i = 0; i < 4; i++) {
strncpy(optionsList[total][i], q.option[i], 100);
printf("\n%d. %s", i + 1, q.option[i]);
}
if (!timeUp) {
TerminateThread(timerThread, 0);
CloseHandle(timerThread);
if (answer == q.correctopt) {
printf("Correct!\n");
score++;
} else {
41 | P a g e
printf("Wrong! Correct answer was %s\n", q.option[q.correctopt -
1]);
}
} else {
userAnswers[total] = 0; // Mark unanswered questions as 0
correctAnswers[total] = q.correctopt;
}
total++;
}
fclose(fp);
totalQuestions = total; // Store total questions for review
42 | P a g e
printf("\nYour answer: %s",
userAnswers[i] ? optionsList[i][userAnswers[i] - 1] : "No
answer");
// Show correct answer
printf("\nCorrect answer: %s\n", optionsList[i][correctAnswers[i] -
1]);
}
}
if (!found) {
printf("Great job! You got all answers correct!\n");
}
}
OUTPUT
Home page:
Add questions:
43 | P a g e
Wrong password:
Play quiz:
44 | P a g e
CONCLUSION
45 | P a g e
In conclusion, the implementation of the EduQuiz System marks a pivotal
step forward in revolutionizing educational assessment and engagement
within academic environments. Designed as a comprehensive and user-
centric platform, the EduQuiz System empowers students and educators
alike by simplifying the process of quiz participation and management,
while enhancing the overall learning experience through structured and
interactive means.
46 | P a g e