Skip to content

Instantly share code, notes, and snippets.

@jamby77
Forked from anonymous/praktikum_menu_display.c
Last active December 19, 2015 04:09
Show Gist options
  • Save jamby77/5894754 to your computer and use it in GitHub Desktop.
Save jamby77/5894754 to your computer and use it in GitHub Desktop.
Sample program
#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