Πολυδιάστατοι Πίνακες & Οργάνωση Κώδικα με Συναρτήσεις
Καθηγητής: Γιώργος Μπάρδης | Τμήμα: Ψηφιακών Συστημάτων
Σε αυτό το μάθημα θα μάθουμε:
Θέλουμε να δημιουργήσουμε ένα Σύστημα Διαχείρισης Βαθμολογίας για 5 μαθητές που θα:
Ένας πολυδιάστατος πίνακας είναι "πίνακας από πίνακες".
Για να αποθηκεύσουμε πολλά strings (π.χ. ονόματα μαθητών), χρειαζόμαστε:
char names[5][50]; // 5 strings, το καθένα 50 χαρακτήρες
Σημαίνει:
names[0] → Πρώτο string (πρώτος μαθητής)names[1] → Δεύτερο string (δεύτερος μαθητής)names[4] → Πέμπτο string (πέμπτος μαθητής)Πίνακας Ονομάτων: char names[5][50]
| Δείκτης | Περιεχόμενο (String) | Μνήμη |
|---|---|---|
names[0] |
"Γιάννης" → {'Γ','ι','ά','ν','ν','η','ς','\0',...} |
50 bytes |
names[1] |
"Μαρία" → {'Μ','α','ρ','ί','α','\0',...} |
50 bytes |
names[2] |
"Κώστας" → {'Κ','ώ','σ','τ','α','ς','\0',...} |
50 bytes |
names[3] |
"Ελένη" → {'Ε','λ','έ','ν','η','\0',...} |
50 bytes |
names[4] |
"Νίκος" → {'Ν','ί','κ','ο','ς','\0',...} |
50 bytes |
| ΣΥΝΟΛΟ | 250 bytes | |
Οι πίνακες στη C δεν αρχικοποιούνται αυτόματα. Περιέχουν "σκουπίδια" (τυχαία δεδομένα από τη μνήμη).
names[i][0] = '\0'; // Το string γίνεται κενό
grades[i] = 0; // Ο βαθμός γίνεται 0
/*
================================================================================
ΒΗΜΑ 1: ΒΑΣΙΚΗ ΔΟΜΗ - Αρχικοποίηση, Μενού, Εισαγωγή Δεδομένων
================================================================================
*/
#include <stdio.h>
#define NUM_STUDENTS 5
// Πρωτότυπα συναρτήσεων
void displayMenu();
void inputGrades(char names[][50], int grades[]);
/* ΣΗΜΕΙΩΣΗ: Στους πίνακες δύο διαστάσεων, μόνο η πρώτη διάσταση μπορεί να είναι
άγνωστη. Η δεύτερη (το μέγεθος κάθε string) πρέπει να είναι γνωστή στο compile time,
ώστε ο μεταγλωττιστής να ξέρει πόσα bytes χρειάζεται για κάθε γραμμή. */
/*
================================================================================
ΚΥΡΙΑ ΣΥΝΑΡΤΗΣΗ - MAIN
================================================================================
*/
int main() {
// Δήλωση πινάκων για ονόματα και βαθμούς
char names[NUM_STUDENTS][50]; // 5 ονόματα × 50 χαρακτήρες
int grades[NUM_STUDENTS]; // 5 βαθμοί
int choice; // Επιλογή χρήστη
int dataEntered = 0; // Flag: έχουν εισαχθεί δεδομένα;
// ΑΡΧΙΚΟΠΟΙΗΣΗ ΠΙΝΑΚΩΝ
for(int i = 0; i < NUM_STUDENTS; i++) {
names[i][0] = '\0'; // Κενό string
// Άρα τι κάνει το names[i][0] = '\0'; ;
// Βάζει το '\0' στην πρώτη θέση του string. Αυτό σημαίνει:
// Το string είναι άδειο.
grades[i] = 0; // Βαθμός 0
}
// ΚΥΡΙΟΣ ΒΡΟΧΟΣ ΠΡΟΓΡΑΜΜΑΤΟΣ
do {
displayMenu();
printf("Επιλέξτε λειτουργία (1-2): ");
scanf("%d", &choice);
getchar(); // Καθαρισμός buffer
switch(choice) {
case 1:
// Εισαγωγή βαθμών
inputGrades(names, grades);
dataEntered = 1;
break;
case 2:
// Έξοδος
printf("\nΕυχαριστούμε! Το πρόγραμμα τερματίστηκε.\n");
break;
default:
printf("\n❌ Μη έγκυρη επιλογή!\n\n");
}
} while(choice != 2);
return 0;
}
/*
================================================================================
ΣΥΝΑΡΤΗΣΗ: displayMenu
Περιγραφή: Εμφανίζει το κύριο μενού του προγράμματος
Παράμετροι: Καμία
Επιστρέφει: void (τίποτα)
================================================================================
*/
void displayMenu() {
printf("\n====================================\n");
printf(" ΣΥΣΤΗΜΑ ΔΙΑΧΕΙΡΙΣΗΣ ΒΑΘΜΟΛΟΓΙΑΣ \n");
printf("====================================\n");
printf("\n--- ΜΕΝΟΥ ---\n");
printf("1. Εισαγωγή βαθμών\n");
printf("2. Έξοδος\n");
printf("\n");
}
/*
================================================================================
ΣΥΝΑΡΤΗΣΗ: inputGrades
Περιγραφή: Διαβάζει τα ονόματα και τους βαθμούς των μαθητών
Παράμετροι:
- names[][50]: Πίνακας για ονόματα (2D array)
- grades[]: Πίνακας για βαθμούς (1D array)
Επιστρέφει: void (τίποτα)
Σημείωση: Τροποποιεί τους πίνακες που περνάνε ως παράμετροι
================================================================================
*/
void inputGrades(char names[][50], int grades[]) {
printf("\n====================================\n");
printf(" ΕΙΣΑΓΩΓΗ ΒΑΘΜΩΝ \n");
printf("====================================\n\n");
for(int i = 0; i < NUM_STUDENTS; i++) {
// Εισαγωγή ονόματος
printf("Εισάγετε όνομα μαθητή %d: ", i + 1);
scanf("%s", &names[i][0]); // Διάβασμα string
// Το &names[i][0] είναι η διεύθυνση του πρώτου χαρακτήρα,
// δηλαδή η αρχή της μνήμης του string.
// Εισαγωγή βαθμού με έλεγχο ορίων (0-100)
do {
printf("Εισάγετε βαθμό (0-100): ");
scanf("%d", &grades[i]);
getchar(); // Καθαρισμός buffer
if(grades[i] < 0 || grades[i] > 100) {
printf("❌ Μη έγκυρος βαθμός! Πρέπει να είναι 0-100.\n");
}
} while(grades[i] < 0 || grades[i] > 100);
printf("\n");
}
printf("✅ Οι βαθμοί αποθηκεύτηκαν επιτυχώς!\n");
}
/*
================================================================================
ΤΕΛΟΣ ΒΗΜΑΤΟΣ 1
================================================================================
*/
Για να εμφανίσουμε πλήρη στατιστικά, χρειαζόμαστε:
Τώρα θα προσθέσουμε τη δυνατότητα εμφάνισης στατιστικών. Η συνάρτηση displayStatistics θα:
/*
================================================================================
ΒΗΜΑ 2: ΠΡΟΣΘΗΚΗ ΣΤΑΤΙΣΤΙΚΩΝ
Προσθέτουμε: displayStatistics, calculateAverage, findMinMax,
countPassed, sortGrades
================================================================================
*/
#include <stdio.h>
#define NUM_STUDENTS 5
// Πρωτότυπα συναρτήσεων
void displayMenu();
void inputGrades(char names[][50], int grades[]);
void displayStatistics(char names[][50], int grades[]);
float calculateAverage(int grades[]);
void findMinMax(int grades[], int results[2], char names[][50],
char minName[], char maxName[]);
int countPassed(int grades[]);
void sortGrades(int grades[], int sorted[]);
/*
================================================================================
ΚΥΡΙΑ ΣΥΝΑΡΤΗΣΗ - MAIN (με προσθήκη επιλογής στατιστικών)
================================================================================
*/
int main() {
char names[NUM_STUDENTS][50];
int grades[NUM_STUDENTS];
int choice;
int dataEntered = 0;
// Αρχικοποίηση
for(int i = 0; i < NUM_STUDENTS; i++) {
names[i][0] = '\0';
grades[i] = 0;
}
do {
displayMenu();
printf("Επιλέξτε λειτουργία (1-3): ");
scanf("%d", &choice);
getchar();
switch(choice) {
case 1:
inputGrades(names, grades);
dataEntered = 1;
break;
case 2:
// ΝΕΑ ΕΠΙΛΟΓΗ: Εμφάνιση Στατιστικών
if(dataEntered) {
displayStatistics(names, grades);
} else {
printf("\n⚠️ Εισάγετε πρώτα τους βαθμούς!\n\n");
}
break;
case 3:
printf("\nΕυχαριστούμε!\n");
break;
default:
printf("\n❌ Μη έγκυρη επιλογή!\n\n");
}
} while(choice != 3);
return 0;
}
/* displayMenu - ΕΝΗΜΕΡΩΜΕΝΟ */
void displayMenu() {
printf("\n====================================\n");
printf(" ΣΥΣΤΗΜΑ ΔΙΑΧΕΙΡΙΣΗΣ ΒΑΘΜΟΛΟΓΙΑΣ \n");
printf("====================================\n");
printf("\n--- ΜΕΝΟΥ ---\n");
printf("1. Εισαγωγή βαθμών\n");
printf("2. Εμφάνιση στατιστικών\n"); // ΝΕΟ
printf("3. Έξοδος\n");
printf("\n");
}
/* inputGrades - ΙΔΙΑ ΜΕ ΠΡΙΝ */
void inputGrades(char names[][50], int grades[]) {
printf("\n====================================\n");
printf(" ΕΙΣΑΓΩΓΗ ΒΑΘΜΩΝ \n");
printf("====================================\n\n");
for(int i = 0; i < NUM_STUDENTS; i++) {
printf("Εισάγετε όνομα μαθητή %d: ", i + 1);
scanf("%s", &names[i][0]);
do {
printf("Εισάγετε βαθμό (0-100): ");
scanf("%d", &grades[i]);
getchar();
if(grades[i] < 0 || grades[i] > 100) {
printf("❌ Μη έγκυρος βαθμός!\n");
}
} while(grades[i] < 0 || grades[i] > 100);
printf("\n");
}
printf("✅ Οι βαθμοί αποθηκεύτηκαν επιτυχώς!\n");
}
/*
================================================================================
ΣΥΝΑΡΤΗΣΗ: displayStatistics (ΝΕΑ!)
Περιγραφή: Εμφανίζει πλήρη στατιστικά για τους βαθμούς
Παράμετροι:
- names[][50]: Πίνακας ονομάτων
- grades[]: Πίνακας βαθμών
Επιστρέφει: void
================================================================================
*/
void displayStatistics(char names[][50], int grades[]) {
float average;
int min, max;
char minName[50], maxName[50];
int passed;
float passRate;
int sortedGrades[NUM_STUDENTS];
int results[2]; // results[0]=min, results[1]=max
printf("\n====================================\n");
printf(" ΣΤΑΤΙΣΤΙΚΑ ΒΑΘΜΟΛΟΓΙΑΣ \n");
printf("====================================\n\n");
// 1. ΛΙΣΤΑ ΜΑΘΗΤΩΝ
printf("📊 ΛΙΣΤΑ ΜΑΘΗΤΩΝ:\n");
printf("------------------------------------\n");
/* Τι είναι το names[i][0];
Το names[i][0] είναι ο πρώτος χαρακτήρας του ονόματος.
Το &names[i][0] είναι η διεύθυνσή του, δηλαδή ένας δείκτης (pointer)
στη θέση που ξεκινά η συμβολοσειρά. */
for(int i = 0; i < NUM_STUDENTS; i++) {
printf("%d. %-15s : %3d\n",
i + 1, &names[i][0], grades[i]);
}
// 2. ΓΕΝΙΚΑ ΣΤΑΤΙΣΤΙΚΑ
printf("\n📈 ΓΕΝΙΚΑ ΣΤΑΤΙΣΤΙΚΑ:\n");
printf("------------------------------------\n");
// Υπολογισμός μέσου όρου
average = calculateAverage(grades);
printf("Μέσος όρος : %.2f\n", average);
// Εύρεση min και max ΧΩΡΙΣ pointers
findMinMax(grades, results, names, minName, maxName);
min = results[0];
max = results[1];
printf("Μέγιστος βαθμός: %d - %s\n", max, maxName);
printf("Ελάχιστος βαθμός: %d - %s\n", min, minName);
// 3. ΕΠΙΤΥΧΟΝΤΕΣ
printf("\n✅ ΕΠΙΤΥΧΟΝΤΕΣ:\n");
printf("------------------------------------\n");
passed = countPassed(grades);
passRate = ((float)passed / NUM_STUDENTS) * 100;
printf("Αριθμός επιτυχόντων: %d/%d μαθητές\n",
passed, NUM_STUDENTS);
printf("Ποσοστό επιτυχίας : %.2f%%\n", passRate);
// 4. ΤΑΞΙΝΟΜΗΜΕΝΟΙ ΒΑΘΜΟΙ
printf("\n📋 ΤΑΞΙΝΟΜΗΜΕΝΟΙ ΒΑΘΜΟΙ:\n");
printf("------------------------------------\n");
sortGrades(grades, sortedGrades);
for(int i = 0; i < NUM_STUDENTS; i++) {
printf("%d", sortedGrades[i]);
if(i < NUM_STUDENTS - 1) {
printf(", ");
}
}
printf("\n");
}
/*
================================================================================
ΣΥΝΑΡΤΗΣΗ: calculateAverage (ΝΕΑ!)
Περιγραφή: Υπολογίζει τον μέσο όρο των βαθμών
Παράμετροι: grades[] - Πίνακας βαθμών
Επιστρέφει: float - Ο μέσος όρος
================================================================================
*/
float calculateAverage(int grades[]) {
int sum = 0;
// Άθροισμα όλων των βαθμών
for(int i = 0; i < NUM_STUDENTS; i++) {
sum += grades[i];
}
// Διαίρεση με το πλήθος (προσοχή: float!)
return (float)sum / NUM_STUDENTS;
}
/*
================================================================================
ΣΥΝΑΡΤΗΣΗ: findMinMax (ΝΕΑ!)
Περιγραφή: Βρίσκει τον μέγιστο και ελάχιστο βαθμό + ονόματα
ΧΩΡΙΣ pointers - χρησιμοποιεί πίνακα results[2]
Παράμετροι:
- grades[]: Πίνακας βαθμών
- results[2]: Πίνακας για επιστροφή (0=min, 1=max)
- names[][50]: Πίνακας ονομάτων
- minName[]: String για όνομα ελάχιστου
- maxName[]: String για όνομα μέγιστου
Επιστρέφει: void (τα αποτελέσματα στους πίνακες)
================================================================================
*/
void findMinMax(int grades[], int results[2], char names[][50],
char minName[], char maxName[]) {
// Αρχικοποίηση με τον πρώτο βαθμό
results[0] = grades[0]; // min
results[1] = grades[0]; // max
// Αντιγραφή πρώτου ονόματος σε minName και maxName
int k = 0; // Μεταβλητή για να διαβάζουμε χαρακτήρα-χαρακτήρα
while(names[0][k] != '\0') { // Όσο ο k-οστός χαρακτήρας του ονόματος δεν είναι '\0' (δηλαδή δεν τελείωσε το string)
minName[k] = names[0][k]; // Αντιγράφουμε τον χαρακτήρα στο minName
maxName[k] = names[0][k]; // Αντιγράφουμε τον ίδιο χαρακτήρα και στο maxName
k++; // Πάμε στον επόμενο χαρακτήρα
}
minName[k] = '\0'; // Βάζουμε τερματικό χαρακτήρα στο τέλος του minName (τέλος string)
maxName[k] = '\0'; // Βάζουμε τερματικό χαρακτήρα στο τέλος του maxName (τέλος string)
// Αναζήτηση min και max
for(int i = 1; i < NUM_STUDENTS; i++) { // Από τον δεύτερο μαθητή (i = 1) μέχρι τον τελευταίο
if(grades[i] < results[0]) { // Εάν ο βαθμός του μαθητή i είναι μικρότερος από το τωρινό min
results[0] = grades[i]; // Τότε ο νέος min βαθμός είναι αυτός
// Αντιγραφή ονόματος μαθητή με ελάχιστο βαθμό
int j = 0; // j = 0 για να αντιγράψουμε χαρακτήρα-χαρακτήρα
while(names[i][j] != '\0') { // Διαβάζουμε το όνομα του μαθητή i μέχρι να βρούμε το '\0'
minName[j] = names[i][j]; // Αντιγράφουμε κάθε χαρακτήρα στο minName
j++; // Προχωράμε στον επόμενο χαρακτήρα
}
minName[j] = '\0'; // Βάζουμε '\0' στο τέλος του minName (τέλος string)
}
if(grades[i] > results[1]) { // Εάν ο βαθμός του μαθητή i είναι μεγαλύτερος από το τωρινό max
results[1] = grades[i]; // Τότε ο νέος max βαθμός είναι αυτός
// Αντιγραφή ονόματος μαθητή με μέγιστο βαθμό
int j = 0; // j = 0 για να αντιγράψουμε χαρακτήρα-χαρακτήρα
while(names[i][j] != '\0') { // Διαβάζουμε το όνομα του μαθητή i μέχρι να βρούμε το '\0'
maxName[j] = names[i][j]; // Αντιγράφουμε κάθε χαρακτήρα στο maxName
j++; // Προχωράμε στον επόμενο χαρακτήρα
}
maxName[j] = '\0'; // Βάζουμε '\0' στο τέλος του maxName (τέλος string)
}
}
}
/*
================================================================================
ΣΥΝΑΡΤΗΣΗ: countPassed (ΝΕΑ!)
Περιγραφή: Μετράει πόσοι μαθητές πέρασαν (βαθμός >= 50)
Παράμετροι: grades[] - Πίνακας βαθμών
Επιστρέφει: int - Πλήθος επιτυχόντων
================================================================================
*/
int countPassed(int grades[]) {
int count = 0;
for(int i = 0; i < NUM_STUDENTS; i++) {
if(grades[i] >= 50) {
count++;
}
}
return count;
}
/*
================================================================================
ΣΥΝΑΡΤΗΣΗ: sortGrades (ΝΕΑ!)
Περιγραφή: Ταξινομεί τους βαθμούς (Bubble Sort)
Παράμετροι:
- grades[]: Αρχικός πίνακας (δεν αλλάζει)
- sorted[]: Πίνακας για ταξινομημένους βαθμούς
Επιστρέφει: void (το αποτέλεσμα στον sorted[])
================================================================================
*/
void sortGrades(int grades[], int sorted[]) {
// Αντιγραφή πίνακα
for(int i = 0; i < NUM_STUDENTS; i++) { // Για κάθε θέση μέχρι τον αριθμό μαθητών
sorted[i] = grades[i]; // Αντιγράφουμε την τιμή από τον grades στον sorted (ώστε να μην αλλάξει ο αρχικός πίνακας)
}
// Bubble Sort (αύξουσα σειρά)
for(int i = 0; i < NUM_STUDENTS - 1; i++) { // Εξωτερικός βρόχος (περνάει πολλές φορές τον πίνακα)
for(int j = 0; j < NUM_STUDENTS - i - 1; j++) { // Εσωτερικός βρόχος (συγκρίνει γειτονικά στοιχεία κάθε φορά)
if(sorted[j] > sorted[j + 1]) { // Αν το τρέχον στοιχείο είναι μεγαλύτερο από το επόμενο...
// Swap (αντιστροφή τιμών)
int temp = sorted[j]; // Αποθηκεύουμε προσωρινά την τιμή sorted[j]
sorted[j] = sorted[j + 1]; // Βάζουμε στο sorted[j] την μικρότερη τιμή
sorted[j + 1] = temp; // Βάζουμε στο sorted[j+1] την παλιά μεγαλύτερη τιμή
}
}
}
}
/*
================================================================================
ΤΕΛΟΣ ΒΗΜΑΤΟΣ 2
================================================================================
*/
int j = 0;
while(names[i][j] != '\0') {
minName[j] = names[i][j];
j++;
}
minName[j] = '\0'; // Τερματισμός string
int results[2];
findMinMax(grades, results, ...);
min = results[0]; // Πρώτη τιμή
max = results[1]; // Δεύτερη τιμή
Συγκρίνει γειτονικά στοιχεία και τα ανταλλάσσει αν είναι λάθος σειρά.
Στα εκπαιδευτικά συστήματα, οι βαθμοί συχνά μετατρέπονται σε γράμματα:
| Βαθμός | Γράμμα | Αξιολόγηση |
|---|---|---|
| 90-100 | A | Άριστα |
| 80-89 | B | Πολύ Καλά |
| 70-79 | C | Καλά |
| 60-69 | D | Μέτρια |
| 0-59 | F | Αποτυχία |
Για να βρούμε έναν μαθητή, πρέπει να συγκρίνουμε strings χαρακτήρα-χαρακτήρα.
/*
================================================================================
ΒΗΜΑ 3: ΒΟΗΘΗΤΙΚΕΣ ΣΥΝΑΡΤΗΣΕΙΣ
Προσθέτουμε: gradeToLetter, findStudent
================================================================================
*/
/* ... (όλες οι προηγούμενες συναρτήσεις) ... */
// Προσθήκη στα πρωτότυπα:
char gradeToLetter(int grade);
void findStudent(char names[][50], int grades[]);
/* Στο main(), προσθήκη case 3: */
case 3:
if(dataEntered) {
findStudent(names, grades);
} else {
printf("\n⚠️ Εισάγετε πρώτα τους βαθμούς!\n\n");
}
break;
/*
================================================================================
ΣΥΝΑΡΤΗΣΗ: gradeToLetter (ΝΕΑ!)
Περιγραφή: Μετατρέπει αριθμητικό βαθμό σε γράμμα (A-F)
Παράμετροι: grade - Ο βαθμός (0-100)
Επιστρέφει: char - Το γράμμα (A, B, C, D ή F)
Λογική: Χρησιμοποιεί if-else if για διαστήματα τιμών
================================================================================
*/
char gradeToLetter(int grade) {
if(grade >= 90 && grade <= 100) {
return 'A'; // Άριστα
} else if(grade >= 80 && grade < 90) {
return 'B'; // Πολύ Καλά
} else if(grade >= 70 && grade < 80) {
return 'C'; // Καλά
} else if(grade >= 60 && grade < 70) {
return 'D'; // Μέτρια
} else {
return 'F'; // Αποτυχία
}
}
/*
================================================================================
ΣΥΝΑΡΤΗΣΗ: findStudent (ΝΕΑ!)
Περιγραφή: Αναζητά μαθητή με βάση το όνομά του (γραμμική αναζήτηση)
Παράμετροι:
- names[][50]: Πίνακας ονομάτων
- grades[]: Πίνακας βαθμών
Επιστρέφει: void
Λογική: Σύγκριση strings χαρακτήρα-χαρακτήρα ΧΩΡΙΣ strcmp
================================================================================
*/
void findStudent(char names[][50], int grades[]) {
char searchName[50]; // Το όνομα που θα πληκτρολογήσει ο χρήστης για αναζήτηση
int found = 0; // Σημαία (0 = δεν βρέθηκε, 1 = βρέθηκε)
printf("\n====================================\n");
printf(" ΑΝΑΖΗΤΗΣΗ ΜΑΘΗΤΗ \n");
printf("====================================\n\n");
printf("Εισάγετε όνομα μαθητή: ");
scanf("%s", searchName); // Το όνομα διαβάζεται πριν από την αναζήτηση
// LINEAR SEARCH - Γραμμική Αναζήτηση
for(int i = 0; i < NUM_STUDENTS; i++) { // Περνάμε έναν-έναν όλους τους μαθητές
// Σύγκριση strings χαρακτήρα-χαρακτήρα
int j = 0; // Μετρητής για σύγκριση κάθε χαρακτήρα
int isEqual = 1; // Υποθέτουμε αρχικά ότι τα δύο ονόματα είναι ίδια (1 = true)
// Όσο και τα δύο ονόματα δεν έφτασαν στο τέλος τους ('\0')
while(names[i][j] != '\0' && searchName[j] != '\0') {
if(names[i][j] != searchName[j]) { // Αν ένας χαρακτήρας δεν ταιριάζει...
isEqual = 0; // ...δεν είναι ίδιο όνομα
break; // Σταματάμε τη σύγκριση
}
j++; // Πήγαινε στον επόμενο χαρακτήρα
}
// Έλεγχος αν τελικά έχουμε πλήρη ταύτιση ονομάτων
if(isEqual && names[i][j] == '\0' && searchName[j] == '\0') {
found = 1; // Το όνομα βρέθηκε!
char letter = gradeToLetter(grades[i]);
printf("\n✓ Μαθητής βρέθηκε!\n");
printf("------------------------------------\n");
printf("Όνομα: %s\n", &names[i][0]);
printf("Βαθμός: %d\n", grades[i]);
printf("Αξιολόγηση: %c (", letter);
switch(letter) {
case 'A': printf("Άριστα)\n"); break;
case 'B': printf("Πολύ Καλά)\n"); break;
case 'C': printf("Καλά)\n"); break;
case 'D': printf("Μέτρια)\n"); break;
case 'F': printf("Αποτυχία)\n"); break;
}
break; // ΣΤΑΜΑΤΑ! Βρέθηκε, δεν χρειάζεται να συνεχίσουμε!
}
}
if(!found) {
printf("\n❌ Ο μαθητής '%s' δεν βρέθηκε.\n", searchName);
}
}
/*
================================================================================
ΤΕΛΟΣ ΒΗΜΑΤΟΣ 3
================================================================================
*/
Βήμα-βήμα διαδικασία:
names[i][j] με searchName[j]isEqual = 0, σταμάταΑναζήτηση: "Μαρία"
names[1] = "Μαρία"
j=0: 'Μ' == 'Μ' ✓
j=1: 'α' == 'α' ✓
j=2: 'ρ' == 'ρ' ✓
j=3: 'ί' == 'ί' ✓
j=4: 'α' == 'α' ✓
j=5: '\0' == '\0' ✓ → ΒΡΕΘΗΚΕ!
Στην τελική έκδοση, ενοποιούμε όλες τις λειτουργίες και προσθέτουμε:
/*
================================================================================
ΠΛΗΡΗΣ ΛΥΣΗ - ΣΥΣΤΗΜΑ ΔΙΑΧΕΙΡΙΣΗΣ ΒΑΘΜΟΛΟΓΙΑΣ
Όλες οι λειτουργίες ενοποιημένες
================================================================================
*/
#include <stdio.h>
#define NUM_STUDENTS 5
// Πρωτότυπα συναρτήσεων
void displayMenu();
void inputGrades(char names[][50], int grades[]);
void displayStatistics(char names[][50], int grades[]);
char gradeToLetter(int grade);
void findStudent(char names[][50], int grades[]);
void sortGrades(int grades[], int sorted[]);
float calculateAverage(int grades[]);
void findMinMax(int grades[], int results[2], char names[][50],
char minName[], char maxName[]);
int countPassed(int grades[]);
// MAIN με όλες τις επιλογές
int main() {
char names[NUM_STUDENTS][50];
int grades[NUM_STUDENTS];
int choice;
int dataEntered = 0;
// Αρχικοποίηση
for(int i = 0; i < NUM_STUDENTS; i++) {
names[i][0] = '\0';
grades[i] = 0;
}
// Κύριος βρόχος
do {
displayMenu();
printf("Επιλέξτε λειτουργία (1-4): ");
scanf("%d", &choice);
getchar();
switch(choice) {
case 1:
inputGrades(names, grades);
dataEntered = 1;
break;
case 2:
if(dataEntered) {
displayStatistics(names, grades);
} else {
printf("\n⚠️ Εισάγετε πρώτα βαθμούς!\n\n");
}
break;
case 3:
if(dataEntered) {
findStudent(names, grades);
} else {
printf("\n⚠️ Εισάγετε πρώτα βαθμούς!\n\n");
}
break;
case 4:
printf("\nΕυχαριστούμε!\n");
break;
default:
printf("\n❌ Μη έγκυρη επιλογή!\n\n");
}
} while(choice != 4);
return 0;
}
/* displayMenu */
void displayMenu() {
printf("\n====================================\n");
printf(" ΣΥΣΤΗΜΑ ΔΙΑΧΕΙΡΙΣΗΣ ΒΑΘΜΟΛΟΓΙΑΣ \n");
printf("====================================\n");
printf("\n--- ΜΕΝΟΥ ---\n");
printf("1. Εισαγωγή βαθμών\n");
printf("2. Εμφάνιση στατιστικών\n");
printf("3. Αναζήτηση μαθητή\n");
printf("4. Έξοδος\n\n");
}
/* ... (Όλες οι άλλες συναρτήσεις όπως στα προηγούμενα βήματα) ... */
/*
================================================================================
ΤΕΛΟΣ ΠΡΟΓΡΑΜΜΑΤΟΣ
================================================================================
*/
| Έννοια | Περιγραφή |
|---|---|
| Πολυδιάστατοι Πίνακες | char names[5][50] - Πίνακας από strings |
| Αρχικοποίηση | names[i][0] = '\0', grades[i] = 0 |
| Οργάνωση με Συναρτήσεις | displayMenu(), inputGrades(), displayStatistics() |
| Στατιστική Ανάλυση | Μέσος όρος, min/max, ταξινόμηση |
| String Handling | Χειροκίνητη σύγκριση και αντιγραφή |
| Grading System | Μετατροπή βαθμών σε γράμματα (A-F) |
| 🔬 Bubble Sort | Αλγόριθμος ταξινόμησης |
| 🔬 Linear Search | Αλγόριθμος αναζήτησης |
| 🔬 Find Min/Max | Αλγόριθμος εύρεσης ακραίων |
| 🔬 String Comparison | Αλγόριθμος σύγκρισης |
💡 Σημαντικό: Μάθαμε να αναγνωρίζουμε και να υλοποιούμε κλασικούς αλγόριθμους της επιστήμης υπολογιστών! Αυτοί οι αλγόριθμοι χρησιμοποιούνται παντού στον προγραμματισμό.
Κατηγοριοποίηση συναρτήσεων ανά σκοπό:
displayMenu() - Εμφάνιση μενούinputGrades() - Εισαγωγή δεδομένωνdisplayStatistics() - Εμφάνιση αποτελεσμάτωνfindStudent() - Αναζήτηση και εμφάνισηcalculateAverage() - Υπολογισμός μέσου όρουfindMinMax() - Εύρεση ακραίων τιμώνcountPassed() - Μέτρηση επιτυχόντωνsortGrades() - ΤαξινόμησηgradeToLetter() - Μετατροπή βαθμούΣτο πρόγραμμά μας χρησιμοποιούμε κλασικούς αλγόριθμους της επιστήμης των υπολογιστών. Είναι σημαντικό να τους αναγνωρίζετε και να καταλαβαίνετε πότε και πώς εφαρμόζονται!
Στη συνάρτηση sortGrades() για να ταξινομήσουμε τους βαθμούς.
Ο Bubble Sort είναι ένας απλός αλγόριθμος ταξινόμησης που:
Ας δούμε πώς ταξινομεί τους βαθμούς: [92, 45, 85, 78, 95]
| Πέρασμα | Κατάσταση Πίνακα | Ενέργεια |
|---|---|---|
| Αρχική | [92, 45, 85, 78, 95] |
- |
| Πέρασμα 1.1 | [45, 92, 85, 78, 95] |
Swap: 92 > 45 |
| Πέρασμα 1.2 | [45, 85, 92, 78, 95] |
Swap: 92 > 85 |
| Πέρασμα 1.3 | [45, 85, 78, 92, 95] |
Swap: 92 > 78 |
| Πέρασμα 1.4 | [45, 85, 78, 92, 95] |
Όχι swap: 92 < 95 |
| Το 95 βρίσκεται στη σωστή θέση! | ||
| Πέρασμα 2.1 | [45, 78, 85, 92, 95] |
Swap: 85 > 78 |
| ... | ||
| Τελικό | [45, 78, 85, 92, 95] |
✅ Ταξινομημένο! |
void sortGrades(int grades[], int sorted[]) {
// Αντιγραφή πίνακα
for(int i = 0; i < NUM_STUDENTS; i++) {
sorted[i] = grades[i];
}
// BUBBLE SORT - Ταξινόμηση Φυσαλίδας
for(int i = 0; i < NUM_STUDENTS - 1; i++) { // Εξωτερικός βρόχος
for(int j = 0; j < NUM_STUDENTS - i - 1; j++) { // Εσωτερικός βρόχος
if(sorted[j] > sorted[j + 1]) { // Σύγκριση γειτονικών
// Swap (Ανταλλαγή)
int temp = sorted[j];
sorted[j] = sorted[j + 1];
sorted[j + 1] = temp;
}
}
}
}
Στη συνάρτηση findStudent() για να βρούμε έναν μαθητή από το όνομά του.
Η Γραμμική Αναζήτηση είναι ο πιο απλός αλγόριθμος αναζήτησης:
Αναζητούμε το όνομα: "Κώστας"
| Βήμα | Έλεγχος | Αποτέλεσμα |
|---|---|---|
| 1 | names[0] = "Γιάννης" |
❌ Διαφορετικό |
| 2 | names[1] = "Μαρία" |
❌ Διαφορετικό |
| 3 | names[2] = "Κώστας" |
✅ ΒΡΕΘΗΚΕ! |
| Η αναζήτηση σταματά εδώ | ||
Σημείωση: Στη δική μας υλοποίηση, κάνουμε και σύγκριση strings χαρακτήρα-χαρακτήρα, που είναι επίσης μια γραμμική αναζήτηση μέσα σε κάθε string!
void findStudent(char names[][50], int grades[]) {
char searchName[50];
int found = 0;
// ... (εισαγωγή ονόματος προς αναζήτηση)
// LINEAR SEARCH - Γραμμική Αναζήτηση
for(int i = 0; i < NUM_STUDENTS; i++) { // Ελέγχουμε κάθε μαθητή
// Σύγκριση strings χαρακτήρα-χαρακτήρα
int j = 0;
int isEqual = 1;
while(names[i][j] != '\0' && searchName[j] != '\0') {
if(names[i][j] != searchName[j]) {
isEqual = 0;
break;
}
j++;
}
if(isEqual && names[i][j] == '\0' && searchName[j] == '\0') {
found = 1;
// ... (εμφάνιση αποτελεσμάτων)
break; // ΣΤΑΜΑΤΑ! Βρέθηκε!
}
}
}
Στη συνάρτηση findMinMax() για να βρούμε τον μικρότερο και μεγαλύτερο βαθμό.
Αυτός ο αλγόριθμος:
Στη δική μας υλοποίηση, επιστρέφουμε ΧΩΡΙΣ pointers χρησιμοποιώντας έναν πίνακα results[2]!
Βαθμοί: [85, 92, 78, 95, 45]
| Βήμα | Τρέχουσα Τιμή | Min | Max | Ενέργεια |
|---|---|---|---|---|
| Αρχή | 85 | 85 | 85 | Αρχικοποίηση |
| 1 | 92 | 85 | 92 | 92 > 85 → Νέο Max |
| 2 | 78 | 85 | 92 | Καμία αλλαγή |
| 3 | 95 | 85 | 95 | 95 > 92 → Νέο Max |
| 4 | 45 | 45 | 95 | 45 < 85 → Νέο Min |
| Τελικό | 45 ✅ | 95 ✅ | Ολοκληρώθηκε! | |
void findMinMax(int grades[], int results[2], ...) {
// FIND MIN/MAX - Εύρεση Ελάχιστου & Μέγιστου
// Αρχικοποίηση με την πρώτη τιμή
results[0] = grades[0]; // min
results[1] = grades[0]; // max
// Διάσχιση του πίνακα
for(int i = 1; i < NUM_STUDENTS; i++) {
if(grades[i] < results[0]) { // Νέο ελάχιστο;
results[0] = grades[i];
// ... (αντιγραφή ονόματος)
}
if(grades[i] > results[1]) { // Νέο μέγιστο;
results[1] = grades[i];
// ... (αντιγραφή ονόματος)
}
}
}
Στη συνάρτηση findStudent() για να συγκρίνουμε ονόματα.
Η σύγκριση strings χαρακτήρα-χαρακτήρα:
Για εκπαιδευτικούς λόγους! Έτσι μαθαίνουμε πώς λειτουργούν οι strings "από μέσα".
| Θέση (j) | String 1 | String 2 | Σύγκριση |
|---|---|---|---|
| 0 | 'Μ' | 'Μ' | ✅ Ίδια |
| 1 | 'α' | 'α' | ✅ Ίδια |
| 2 | 'ρ' | 'ρ' | ✅ Ίδια |
| 3 | 'ί' | 'ί' | ✅ Ίδια |
| 4 | 'α' | 'α' | ✅ Ίδια |
| 5 | '\0' | '\0' | ✅ ΚΑΙ ΤΑ ΔΥΟ ΤΕΛΕΙΩΣΑΝ! |
→ Αποτέλεσμα: ΤΑ STRINGS ΕΙΝΑΙ ΙΔΙΑ!
| Θέση (j) | String 1 | String 2 | Σύγκριση |
|---|---|---|---|
| 0 | 'Μ' | 'Μ' | ✅ Ίδια |
| 1 | 'α' | 'α' | ✅ Ίδια |
| 2 | 'ρ' | 'ρ' | ✅ Ίδια |
| 3 | 'ί' | 'ί' | ✅ Ίδια |
| 4 | 'α' | 'ν' | ❌ ΔΙΑΦΟΡΕΤΙΚΑ! |
| Η σύγκριση σταματά εδώ (break) | |||
→ Αποτέλεσμα: ΤΑ STRINGS ΕΙΝΑΙ ΔΙΑΦΟΡΕΤΙΚΑ!
| Αλγόριθμος | Χρήση | Συνάρτηση |
|---|---|---|
| Bubble Sort | Ταξινόμηση | sortGrades() |
| Linear Search | Αναζήτηση | findStudent() |
| Find Min/Max | Στατιστικά | findMinMax() |
| String Comparison | Σύγκριση | findStudent() |
Σημείωση: Για μεγάλα datasets, θα χρησιμοποιούσαμε πιο αποδοτικούς αλγόριθμους (Quick Sort για ταξινόμηση, Binary Search για αναζήτηση σε ταξινομημένους πίνακες).
Προσθέστε μια νέα συνάρτηση displayTopStudents() που:
Τροποποιήστε τη findStudent() ώστε:
Δημιουργήστε συνάρτηση displayByGrade() που:
Τροποποιήστε το πρόγραμμα ώστε:
Υλοποιήστε τον αλγόριθμο Selection Sort και συγκρίνετε τον με το Bubble Sort:
selectionSort()Υπόδειξη: Ο Selection Sort βρίσκει το ελάχιστο στοιχείο και το τοποθετεί στην αρχή κάθε φορά.
Μετά την ταξινόμηση, υλοποιήστε Binary Search για αναζήτηση βαθμών:
binarySearchGrade()