Instantly share code, notes, and snippets.
Forked from anonymous/praktikum_menu_display.c
Last active
December 19, 2015 04:09
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save jamby77/5894754 to your computer and use it in GitHub Desktop.
Sample program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _CRT_SECURE_NO_DEPRECATE | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
// | |
// АКО ПОЛЗВАТЕ НЯКОЯ ЧАСТ ОТ ТОЗИ ФАЙЛ, ПОСТАРАЙТЕ СЕ ДА ИЗТРИЕТЕ КОМЕНТАРИТЕ!!! | |
// | |
const int MENU_LENGTH = 6; // дължина на менюто, по-лесно е за обхождане ако е дефинирана | |
enum menu | |
{ | |
MENU_EXIT = 0, | |
MENU_LIST = 1, | |
MENU_ADD = 2, | |
MENU_FEES = 3, | |
MENU_AVG = 4, | |
MENU_HIGH = 5 | |
}; // списък на възможните команди, може и директно числа да се ползват, но по този начин е по-ясно кое какво значи | |
char * menuItems[] = { | |
"0 - Exit", | |
"1 - List users", | |
"2 - Add user", | |
"3 - Calculate fees", | |
"4 - Total and average call length", | |
"5 - Highest bill" | |
}; // списък на менюто, редактиране, добавяне или махане на елемент от списъка ще се отрази на менюто показано на потребителя | |
FILE * fh; // връзка към файла, когато се отвори файл, достъпа до него става чрез тази връзка | |
char *FILE_NAME = "data.txt"; // име на файла, произволно е, може да се казва по всеки начин | |
void fileOpen(); | |
void fileClose(); | |
typedef enum fileEmpty { | |
NOT_CHECKED = 0, | |
EMPTY = 1, | |
NOT_EMPTY = 2 | |
} Empty; // списък със файл статуси които ни помагат да следим дали има данни във файла | |
Empty fe = NOT_CHECKED; // първоначално файла не е проверен | |
void fileCheckEmpty(); // функция която проверява файла | |
// меню функции, могат да се ползват във вс.задачи като се променят горните списъци според задачата | |
int getMenuOption(); | |
void displayMenu(); | |
// работни функции | |
void listItems(); // тези две най-вероятно могат да се ползват във всички задачи | |
void addItem(); // трябва да се промени използваната структура иначе принципа е същия | |
int loadItems(); // Зареждане на данните | |
int loaded = 0; // колко реда с данни са намерени | |
void fees(); // тези са специфични за тази задача | |
void avg(); | |
void high(); | |
const char *header = "number\tname\tplan\tminutes\tused\n"; // заглавния ред на файла, ще бъде различен за всяка задача!!! | |
typedef struct _abonat | |
{ | |
int number; | |
char *name; | |
float plan; | |
int minutes; | |
int used; | |
} Abonat; // структура за телефонен абонат | |
int main(void) // главна функция. в случай че някой не е сигурен, програмата ТРЯБВА да има тази функция | |
{ | |
int opt; | |
while ((opt = getMenuOption())) // вземаме командата и изпъняваме съответната функция | |
{ | |
switch (opt) | |
{ | |
case MENU_LIST: | |
fileOpen(); // първо отваряме файла | |
listItems(); // правим каквото решим | |
fileClose(); // и го затваряме | |
break; | |
case MENU_ADD: | |
fileOpen(); | |
addItem(); | |
fileClose(); | |
break; | |
case MENU_AVG: | |
fileOpen(); | |
avg(); | |
fileClose(); | |
break; | |
case MENU_FEES: | |
fileOpen(); | |
fees(); | |
fileClose(); | |
break; | |
case MENU_HIGH: | |
fileOpen(); | |
high(); | |
fileClose(); | |
break; | |
default: | |
printf("Command - %d\n", opt); // непозната команда | |
break; | |
} | |
} | |
puts("Exiting\n"); // даваме да се знае че сме приключили | |
return 0; | |
} | |
void displayMenu() | |
{ | |
int i; | |
for (i = 0; i < MENU_LENGTH; i++) | |
{ | |
puts(menuItems[i]); // принтиране на всеки член от списъка с менюто | |
} | |
} | |
int getMenuOption() | |
{ | |
int opt; | |
displayMenu(); | |
scanf("%d", &opt); // принтирали сме, и чакаме за номера на командата, не за името и. | |
if (opt > (MENU_LENGTH - 1) || opt < 0) | |
{ | |
opt = 0; // ако името е невалидно число, правим го 0, което ще прикючи програмата | |
} | |
return opt; | |
} | |
void fileOpen() | |
{ | |
fh = fopen(FILE_NAME, "r+"); // отваряме файла за четене и писане, ако файла не съществува, fh ще е NULL | |
if (NULL == fh) | |
{ | |
fh = fopen(FILE_NAME, "w+");// ако файла не съществува, w+ ще го създаде | |
} | |
if (NULL == fh) // ако до този момент нямаме файл, значи нещо не е наред и няма смисъл да продължава програмата | |
{ | |
puts("File could not be opened or created, check permissions"); | |
exit(1); | |
} | |
fileCheckEmpty(); | |
} | |
void fileClose() | |
{ | |
fclose(fh); // добре е винаги след преключване на работа с файл да го затваряме | |
} | |
void fileCheckEmpty() | |
{ | |
fpos_t pos; | |
if (NULL == fh) | |
{ | |
fileOpen(); | |
} | |
fgetpos(fh, &pos); // вземаме настоящата позиция на курсора във файла | |
fseek(fh, 0, SEEK_END); // отиваме до края на файла | |
if (ftell(fh) == 0) // проверяваме дали края на файла е 0, ако е значи е празен | |
{ | |
fe = EMPTY; | |
} else { | |
fe = NOT_EMPTY; | |
} | |
fsetpos(fh, &pos); // връща ме се на позицията на курсора | |
} | |
void addItem() | |
{ | |
Abonat *ab = (Abonat *) malloc(sizeof(Abonat)); // резервираме си памет | |
char name[50]; | |
if (NULL == ab) | |
{ | |
puts("Could not allocate memory."); | |
return; // ако нямаме резервирана памет, ще ни е трудно да направим каквото и да било | |
} | |
if(fe == NOT_CHECKED){ | |
fileCheckEmpty(); | |
} | |
if (fe == EMPTY) | |
{ | |
fputs(header, fh); // ако файла е празен, записваме заглавния ред | |
} else { // ако не е празен, трябва да добавим към него затова | |
fseek(fh, 0, SEEK_END); // отиваме до края на файла | |
} | |
puts("Enter data:"); | |
scanf("%d %50s %f %d %d", &ab->number, name, &ab->plan, &ab->minutes, &ab->used); // прочитаме данните от клавиатурата | |
ab->name = (char *) malloc(sizeof(name)+1); | |
strcpy(ab->name, name); | |
fprintf(fh, "%d\t%s\t%f\t%d\t%d\n", ab->number, ab->name, ab->plan, ab->minutes, ab->used); // записваме ги във файла разделени с таб (\t) | |
loaded = 0; // зануляваме боряча | |
} | |
Abonat * ab; | |
int loadItems() | |
{ | |
int max = 20, i = 0; | |
const int lineSize = 500; // максимално очаквана дължина на текста на един ред | |
char buff[500]; // временен буфер | |
char name[50]; // буфер за име | |
int number, minutes, used; // числови променливи | |
float plan; | |
if (loaded > 0) // ако вече са заредени данните, не правим опит да ги четем | |
{ | |
return loaded; | |
} | |
ab = (Abonat *) malloc(max * sizeof(Abonat));// заделяме памет за 20 абоната, ако свърши, още ще заделим | |
if (NULL == ab) | |
{ | |
puts("Could not allocate memory."); | |
return 0; | |
} | |
if(fe == NOT_CHECKED){ | |
fileCheckEmpty(); | |
} | |
if (fe == EMPTY) // ако файла е празен няма какво да зареждаме | |
{ | |
printf("% seems to be empty.\n", FILE_NAME); | |
return 0; | |
} | |
rewind(fh); // превъртаме файла до началото му за да заредим всички данни | |
while (fgets(buff, lineSize, fh) != NULL) // четем линия по линия във buff | |
{ | |
if (sscanf(buff, "%d%s%f%d%d", &number, name, &plan, &minutes, &used)) // сканираме всяка линия както със scanf | |
{ | |
ab[i].name = (char *) malloc(sizeof(name)); // ако сме получили валидни данни, създаваме поредна структура | |
strcpy(ab[i].name, name); | |
ab[i].number = number; | |
ab[i].plan = plan; | |
ab[i].minutes = minutes; | |
ab[i].used = used; | |
i++; // качваме брояча | |
} | |
if ((i+1) % max == 0) // ако брояча + 1 е кратно на макс (20, 40, 60 и т.н.) трябва да добавим памет | |
{ | |
max += 10; // добавяме памет за по още 10 записа | |
ab = (Abonat *) realloc(ab, max * sizeof(Abonat)); | |
if (NULL == ab) | |
{ | |
puts("Could not allocate more memory."); // ако няма памет, не можем да четем повече | |
break; | |
} | |
} | |
} | |
loaded = i; // записваме колко записа сме заредили | |
return i; | |
} | |
void listItems() | |
{ | |
int loaded, i; | |
loaded = loadItems(); // получаваме броя на заредените записи | |
if (loaded == 0) // ако няма такива не правим нищо | |
{ | |
puts("There are no items to list."); | |
return; | |
} | |
puts("number\tname\tplan\tminutes\tused"); // ако има, пишем заглавния ред и след това всички записи един след друг | |
for (i = 0; i < loaded; i++) | |
{ | |
printf("%d\t%s\t%.2f\t%d\t%d\n", ab[i].number, ab[i].name, ab[i].plan, ab[i].minutes, ab[i].used); | |
} | |
} | |
// останалите функции са като лист, само че вместо да показвате записите, смятате каквото е нужно от тях и го показвате | |
void fees() | |
{ | |
puts(__FUNCTION__); | |
puts("Not implemented yet"); | |
} | |
void avg() | |
{ | |
puts(__FUNCTION__); | |
puts("Not implemented yet"); | |
} | |
void high() | |
{ | |
puts(__FUNCTION__); | |
puts("Not implemented yet"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment