Programming Essentials in C - Assignment Two ​
Task 1: Store and Display Total Marks Using a 2D Array ​
- Objective: Write a C program to store marks of 5 students in 3 subjects using a 2D array, then calculate and display total marks for each student.
- Code:
c
#include <stdio.h>
int main() {
// 2D array for 5 students, 3 subjects
int marks[5][3];
int total; // Variable for total marks per student
// Input marks
for (int i = 0; i < 5; i++) { // Loop through students
printf("\nEnter marks for student %d:\n", i + 1);
for (int j = 0; j < 3; j++) { // Loop through subjects
printf("Subject %d: ", j + 1);
scanf("%d", &marks[i][j]); // Read marks
}
}
printf("\n"); // Newline for output formatting
// Calculate and display total marks
for (int i = 0; i < 5; i++) { // Loop through students
total = 0; // Reset total for each student
for (int j = 0; j < 3; j++) { // Loop through subjects to sum marks
total += marks[i][j]; // Add subject mark to total
}
// Display total marks for the current student
printf("Total marks for student %d: %d\n", i + 1, total);
}
return 0; // Indicate success
}Task 2: Create and Use a Student Structure ​
- Objective: Define a
studentstructure with ID, name, and three subject marks, then input and display data for 3 students. - Code:
c
#include <stdio.h>
// Define a structure named Student
struct Student {
int id; // Student ID
char name[50]; // Student name (character array to hold the string)
int marks[3]; // Array to hold marks for 3 subjects
};
int main() {
// Declare an array of 3 Student structures
struct Student students[3];
// Input data for 3 students
for (int i = 0; i < 3; i++) { // Loop through each student
printf("Enter details for student %d:\n", i + 1); // Prompt for student details
printf("ID: ");
scanf("%d", &students[i].id); // Read student ID
printf("Name: ");
// Read student name. scanf("%s", ...) reads a single word and stops at whitespace.
// Be cautious with scanf("%s") for names with spaces; fgets is generally safer.
scanf("%s", students[i].name);
// Input marks for the 3 subjects for the current student
for (int j = 0; j < 3; j++) { // Loop through each subject
printf("Subject %d marks: ", j + 1);
scanf("%d", &students[i].marks[j]); // Read subject marks
}
}
printf("---------------------\n"); // Separator line for output
// Display data for the 3 students
for (int i = 0; i < 3; i++) { // Loop through each student
printf("\nStudent %d:\n", i + 1); // Display student number
printf("ID: %d\n", students[i].id); // Display student ID
printf("Name: %s\n", students[i].name); // Display student name
// Display marks for the 3 subjects for the current student
for (int j = 0; j < 3; j++) { // Loop through each subject
printf("Subject %d marks: %d\n", j + 1, students[i].marks[j]); // Display subject marks
}
}
return 0;
}Task 3: Calculate Average with a Function ​
- Objective: Write a
calculateAverage()function that takes astudentstructure, calculates the average of marks, and updates the structure. - Code:
c
#include <stdio.h>
// Define a structure named Student
struct Student {
int id; // Student ID
char name[50]; // Student name
int marks[3]; // Array to hold marks for 3 subjects
float average; // Variable to store the calculated average
};
// Function to calculate the average marks for a student
// Takes a pointer to a Student structure as input
void calculateAverage(struct Student *s) {
float sum = 0; // Initialize sum of marks
// Loop through the marks array to calculate the sum
for (int i = 0; i < 3; i++) {
sum += s->marks[i]; // Add current subject's mark to sum (using pointer dereference ->)
}
// Calculate the average and store it in the average field of the structure
s->average = sum / 3.0; // Use 3.0 for floating-point division
}
int main() {
// Declare and initialize a Student structure variable 's1'
struct Student s1 = {
.id = 1, // Initialize ID
.name = "John", // Initialize name
.marks = { 80, 85, 90 }, // Initialize marks for 3 subjects
.average = 0.0 // Initialize average (will be calculated later)
};
// Display student details before calculating the average
printf("Before\n");
printf("Student ID: %d\nName: %s\nAverage: %.2f\n", s1.id, s1.name, s1.average);
// Call the calculateAverage function, passing the address of s1
// This allows the function to modify the s1 structure directly
calculateAverage(&s1);
// Display student details after calculating the average
printf("\nAfter\n");
printf("Student ID: %d\nName: %s\nAverage: %.2f\n", s1.id, s1.name, s1.average);
return 0;
}Task 4: Use Pointers to Modify Student ID ​
- Objective: Declare a student ID variable and use pointers to modify and display it.
- Code:
c
#include <stdio.h>
int main() {
// Declare an integer variable and initialize it
int studentId = 100;
// Declare an integer pointer and initialize it to point to the memory address of studentId
int* idPtr = &studentId;
// Print the initial value of studentId using the variable name
printf("student ID before edit: %d\n", studentId);
// Change the value of the variable studentId using the pointer
// The '*' operator dereferences the pointer, accessing the value at the memory address it points to
*idPtr = 101;
// Print the updated value of studentId using the variable name
printf("student ID after edit (var): %d\n", studentId);
// Print the updated value of studentId using the pointer dereference
// This shows that the value pointed to by idPtr has also changed
printf("student ID after edit (pointer): %d\n", *idPtr);
return 0;
}Task 5: Compare Arrays and Structures ​
Arrays
- Hold multiple elements of the same type (e.g. all
intor alldouble). - Laid out contiguously in memory—you can index into them (
arr[5]) and perform pointer‑arithmetic. - Good when you need a simple list or table of values, all governed by the same operations.
- Hold multiple elements of the same type (e.g. all
Structures
- Bundle together one or more variables, possibly of different types, under a single name.
- Each member can be accessed by name (
person.age,person.name), improving clarity when you have logically related but type‑varying data. - Memory layout may include padding to satisfy alignment, but you don't lose the benefit of grouping.
When to prefer a
structover separate arrays?
Use astructwhen you're modelling an entity that has multiple attributes—especially if those attributes are not all the same data type. With arrays you'd need parallel arrays (e.g.ages[i],names[i],grades[i]), which is error‑prone and scatters related data. Astructkeeps each "record" intact, makes function interfaces cleaner, and aligns with best practices for data encapsulation.
c
#include <stdio.h>
/* Define a student record with mixed fields */
struct Student {
char name[32];
int age;
float gpa;
} ;
int main() {
/* Array of structures: each element is a complete student record */
struct Student classroom[3] = {
{ "Alice", 20, 3.8f },
{ "Bob", 22, 3.2f },
{ "Cara", 19, 3.9f }
};
/* Print each student's data */
for (int i = 0; i < 3; i++) {
printf(
"Student %d: %s, age %d, GPA %.2f\n",
i + 1,
classroom[i].name,
classroom[i].age,
classroom[i].gpa
);
}
return 0;
}- Why this is better than parallel arrays
- You avoid mistakes like shifting one array and not the others.
- Passing one
Studentto a function is simpler than passing three separate arrays plus an index. - The code is self‑documenting:
student.agevs.ages[i].
Task 6: Dynamic Access with Pointers ​
- Objective: Store marks of 5 students in a 1D array and use pointers to display them.
- Code:
c
#include <stdio.h>
int main() {
// Declare a one-dimensional array to store marks for 5 students in 3 subjects.
// Total elements = 5 students * 3 subjects = 15.
int marks[15];
// Input marks for 5 students (3 subjects each) into the 1D array.
// The index calculation i * 3 + j maps the 2D logic (student i, subject j)
// to the 1D array index.
for (int i = 0; i < 5; i++) { // Loop through each student
printf("Enter marks for student %d:\n", i + 1);
for (int j = 0; j < 3; j++) { // Loop through each subject
printf("Subject %d: ", j + 1);
scanf("%d", &marks[i * 3 + j]); // Read marks into the calculated 1D index
}
}
// Declare an integer pointer and initialize it to point to the beginning of the 'marks' array.
// The array name 'marks' itself acts as a pointer to its first element.
int* ptr = marks;
printf("---------------------\n"); // Separator line for output
// Loop to display marks using the pointer to traverse the array.
for (int i = 0; i < 5; i++) { // Loop through each student
printf("Student %d marks: ", i + 1);
for (int j = 0; j < 3; j++) { // Loop through each subject for the current student
printf("%d ", *ptr); // Dereference the pointer to access the value at the current memory location
ptr++; // Increment the pointer to move to the next integer element in the array
}
printf("\n"); // Newline after displaying marks for each student
}
return 0;
}Task 7: Complete Student Grading System ​
- Objective: Build a system using arrays, structures, functions, and pointers to input, calculate averages, and display a report.
- Code:
c
#include <stdio.h>
#include <string.h> // Include string library for string manipulation functions
// Define a structure named Student
struct Student {
int id; // Student ID
char name[50]; // Student name
int marks[3]; // Array to hold marks for 3 subjects
float average; // Variable to store the calculated average
};
// Function to calculate the average marks for a student
// Takes a pointer to a Student structure as input
void calculateAverage(struct Student *s) {
float sum = 0; // Initialize sum of marks
// Loop through the marks array to calculate the sum
for (int i = 0; i < 3; i++) {
sum += s->marks[i]; // Add current subject's mark to sum (using pointer dereference ->)
}
// Calculate the average and store it in the average field of the structure
s->average = sum / 3.0; // Use 3.0 for floating-point division
}
// Function to read a line from input, removing the newline character
void readline(char* restrict s, int n, FILE *restrict stream) {
fgets(s, n, stream);
s[strcspn(s, "\n")] = '\0'; // Remove the newline '\n' character
}
// Function to clear the input buffer
void clearInputBuffer() {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
int main() {
// Declare an array of 5 Student structures
struct Student students[5];
// Input data for 5 students
for (int i = 0; i < 5; i++) { // Loop through each student
printf("Enter details for student %d:\n", i + 1); // Prompt for student details
printf("ID: ");
scanf("%d", &students[i].id); // Read student ID
clearInputBuffer(); // Clear buffer after reading integer
printf("Name: ");
readline(students[i].name, 50, stdin); // Read student name (handles spaces)
// Input marks for the 3 subjects for the current student
for (int j = 0; j < 3; j++) { // Loop through each subject
printf("Subject %d marks: ", j + 1);
scanf("%d", &students[i].marks[j]); // Read subject marks
}
calculateAverage(&students[i]); // Calculate average for the student
}
printf("\nStudent Grading Report:\n"); // Header for the report
// Display data for the 5 students
for (int i = 0; i < 5; i++) { // Loop through each student
struct Student s = students[i]; // Create a copy for easier access (optional, could use students[i] directly)
printf(
"ID: %d, Name: '%s', Marks: %d, %d, %d, Average: %.2f\n",
s.id, s.name, s.marks[0], s.marks[1], s.marks[2], s.average // Print student details and calculated average
);
}
// Demonstrate updating a student's mark using a pointer
struct Student *p = &students[0]; // Declare a pointer 'p' and point it to the first student structure
p->marks[0] = 90; // Update the first subject's mark for the first student using the pointer
calculateAverage(p); // Recalculate the average for the first student after updating marks
printf("\nAfter updating student 1's subject 1 mark to 90:\n"); // Message indicating the update
printf(
"ID: %d, Name: '%s', Marks: %d, %d, %d, Average: %.2f\n",
p->id, p->name, p->marks[0], p->marks[1], p->marks[2], p->average // Display updated details
);
return 0;
}Task 8: Save Names and Averages to File ​
- Objective: Save student names and averages to
grades.txt. - Code:
c
#include <stdio.h>
#include <string.h> // String manipulation functions
// Define filename as a constant
const char FILENAME[11] = "grades.txt";
// Student structure
struct Student {
char name[50]; // Student name
int marks[3]; // Marks for 3 subjects
float average; // Calculated average
};
// Function to calculate average marks
void calculateAverage(struct Student *s) {
float sum = 0;
for (int i = 0; i < 3; i++) {
sum += s->marks[i];
}
s->average = sum / 3.0;
}
// Function to read a line, removing newline
void readline(char* restrict s, int n, FILE *restrict stream) {
fgets(s, n, stream);
s[strcspn(s, "\n")] = '\0';
}
// Function to clear input buffer
void clearInputBuffer() {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
int main() {
// Open file in write mode ("w"). Creates or overwrites.
FILE *file = fopen(FILENAME, "w");
int character; // Variable for reading characters
// Check if file opened successfully for writing
if (file == NULL) {
printf("Error opening %s!\n", FILENAME);
return 1;
}
// Array of 3 Student structures
struct Student students[3];
// Input data for 3 students
for (int i = 0; i < 3; i++) {
printf("Enter details for student %d:\n", i + 1);
printf("Name: ");
readline(students[i].name, 50, stdin);
for (int j = 0; j < 3; j++) {
printf("Subject %d marks: ", j + 1);
scanf("%d", &students[i].marks[j]);
}
clearInputBuffer(); // Clear buffer after scanf
calculateAverage(&students[i]); // Calculate average
}
// Write student name and average to file
for (int i = 0; i < 3; i++) {
struct Student s = students[i];
fprintf(file,
"Name: '%s', Average: %.2f\n",
s.name, s.average
);
}
// Close the file after writing
fclose(file);
// Reopen the file in read mode ("r")
file = fopen(FILENAME, "r");
// Check if file opened successfully for reading
if (file == NULL) {
printf("Error reading from %s!\n", FILENAME);
return 1;
}
printf("Reading content from %s:\n\n", FILENAME);
// Read and print file content character by character
while ((character = fgetc(file)) != EOF) {
putchar(character);
}
// Close the file after reading
fclose(file);
return 0; // Indicate success
}Task 9: Explain "w" vs. "a" File Modes ​
| Mode | Behavior | Existing file content |
|---|---|---|
"w" | Open for writing. If the file exists, truncate it to zero length (erase all data). If absent, create new file. | Discarded (file is cleared) |
"a" | Open for writing. If the file exists, writing always goes to the end (append). If absent, create new file. | Preserved; new data added at end |
Key point:
- Use
"w"when you want to start fresh and do not care about any previous content.- Use
"a"when you want to preserve existing content and add more data at the end.
- Code:
c
#include <stdio.h>
int main() {
FILE *fp;
// Write mode
fp = fopen("test.txt", "w");
fprintf(fp, "This is write mode.\n");
fclose(fp);
// Append mode
fp = fopen("test.txt", "a");
fprintf(fp, "This is append mode.\n");
fclose(fp);
// Read and display
fp = fopen("test.txt", "r");
char line[100];
while(fgets(line, 100, fp) != NULL) {
printf("%s", line);
}
fclose(fp);
return 0;
}- Output Explanation: First write creates/overwrites with "This is write mode." Append adds "This is append mode." Result: both lines in the file.
Task 10: Read and Display Records from File ​
- Objective: Read student records from
grades.txtand display them. - Code:
c
#include <stdio.h> // Standard I/O library
#include <string.h> // String manipulation functions
// Define filename
const char FILENAME[11] = "grades.txt";
int main() {
// Open file in read mode ("r")
FILE *file = fopen(FILENAME, "r");
// Check for file open errors
if (file == NULL) {
printf("Error opening file.\n");
return 1; // Indicate error
}
char line[100]; // Buffer for reading lines
printf("Student Grades Report:\n"); // Report header
// Read file line by line using fgets
while (fgets(line, 100, file) != NULL) {
char name[50]; // Variable for name
float average; // Variable for average
/*
Parse line using sscanf:
- "Name: %[^,]" extracts name up to comma.
- ", " matches literal comma and space.
- "Average: %f" extracts float after "Average: ".
*/
sscanf(line, "Name: %[^,], Average: %f", name, &average);
// Print extracted data
printf("Name: %s, Average: %.2f\n", name, average);
}
// Close the file
fclose(file);
return 0; // Indicate success
}Task 11: Complete Grading Application with File Handling ​
- Objective: Design an application to load data, update marks, recalculate averages, and save back to a file.
- Code:
c
#include <stdio.h> // Standard I/O library for file operations, printf, scanf
#include <stdlib.h> // Standard library for exit()
#include <string.h> // String manipulation functions for strcspn, strcpy
// Student structure definition
struct Student {
int id; // Student ID
char name[50]; // Student name
int marks[3]; // Marks for 3 subjects
float average; // Calculated average
};
// Function to calculate average marks for a student
void calculateAverage(struct Student *s) {
float sum = 0;
for (int i = 0; i < 3; i++) {
sum += s->marks[i];
}
s->average = sum / 3.0;
}
// Function to read a line from input, removing newline
void readline(char* restrict s, int n, FILE *restrict stream) {
fgets(s, n, stream);
s[strcspn(s, "\n")] = '\0'; // Remove the newline '\n' character
}
// Function to clear input buffer after scanf
void clearInputBuffer() {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
// Function to read student details from user input
void readStudent(struct Student *s) {
printf("\nEnter student ID: ");
scanf("%d", &s->id);
clearInputBuffer(); // Clear buffer after reading integer
printf("Name: ");
readline(s->name, 50, stdin); // Read name (handles spaces)
for (int j = 0; j < 3; j++) {
printf("Subject %d marks: ", j + 1);
scanf("%d", &s->marks[j]); // Read subject marks
}
clearInputBuffer(); // Clear buffer after reading marks
calculateAverage(s); // Calculate average after input
}
// Function to create an empty file
// Returns 0 on success, 1 on failure
int createFile(const char* filename) {
FILE *file;
file = fopen(filename, "w"); // Open file in write mode (creates or clears)
if (file == NULL) {
printf("Error: Could not create file %s\n", filename);
return 1; // Indicate error
}
fclose(file); // Close immediately to leave it empty
return 0; // Indicate success
}
// Function to save student data to a file
void saveData(struct Student students[], int n, const char* filename) {
FILE *file = fopen(filename, "w"); // Open file in write mode
if (file == NULL) {
printf("Error opening file for saving.\n");
exit(1); // Exit on critical error
}
// Write student data in a formatted way
for (int i = 0; i < n; i++) {
fprintf(
file, "%d %s %d %d %d\n", // Format: ID Name Mark1 Mark2 Mark3
students[i].id, students[i].name, students[i].marks[0],
students[i].marks[1], students[i].marks[2]
);
}
fclose(file); // Close file after saving
}
// Function to load student data from a file
// 'checked' flag prevents infinite recursion on file not found
void loadData(struct Student students[], int n, const char* filename, short checked) {
FILE *fp = fopen(filename, "r"); // Open file in read mode
if (fp == NULL) {
if (checked) {
printf("Error opening file for loading.\n");
exit(1); // Exit if file should exist but doesn't
} else {
// If file doesn't exist on first try, create it, get input, save, and try loading again
printf("File not found. Creating new file and getting student data.\n");
createFile(filename);
for (int i = 0; i < n; i++) {
readStudent(&students[i]); // Get student data from user
}
saveData(students, n, filename); // Save the newly entered data
loadData(students, n, filename, 1); // Try loading again (checked is now 1)
return;
}
}
// Read student data from file using fscanf
for (int i = 0; i < n; i++) {
fscanf(
fp, "%d %s %d %d %d", // Format to match saveData
&students[i].id, students[i].name, &students[i].marks[0],
&students[i].marks[1], &students[i].marks[2]
);
calculateAverage(&students[i]); // Calculate average after loading marks
}
fclose(fp); // Close file after loading
}
int main() {
struct Student students[5]; // Array to hold 5 students
const char* filename = "students.txt"; // Data file name
// Load student data from file (or get input if file doesn't exist)
loadData(students, 5, filename, 0);
// Display current student data
printf("\nCurrent Student Data:\n");
for (int i = 0; i < 5; i++) {
printf(
"ID: %d, Name: %s, Marks: %d, %d, %d, Average: %.2f\n",
students[i].id, students[i].name, students[i].marks[0],
students[i].marks[1], students[i].marks[2], students[i].average
);
}
// Update marks section
int id;
printf("\nEnter student ID to update: ");
scanf("%d", &id); // Get ID to update
int index = -1; // Index of student to update
// Find the student by ID
for (int i = 0; i < 5; i++) {
if (students[i].id == id) {
index = i; // Found student, store index
break;
}
}
// Handle student not found
if (index == -1) {
printf("Student not found.\n");
return 1; // Exit or handle error
}
// Get new marks for the selected student
printf("Enter new marks for student %d:\n", id);
for (int j = 0; j < 3; j++) {
printf("Subject %d: ", j + 1);
scanf("%d", &students[index].marks[j]); // Read new marks
}
calculateAverage(&students[index]); // Recalculate average after update
// Display updated student data
printf("\nUpdated Student Data:\n");
for (int i = 0; i < 5; i++) {
printf(
"ID: %d, Name: %s, Marks: %d, %d, %d, Average: %.2f\n",
students[i].id, students[i].name, students[i].marks[0],
students[i].marks[1], students[i].marks[2], students[i].average
);
}
// Save the updated data back to the file
saveData(students, 5, filename);
printf("\nData saved to %s\n", filename);
return 0; // Indicate successful execution
}