Stos, funkcje zapisu i odczytu pliku binarnego

0

Witam, moim zadaniem było stworzenie programu, który obsługuje stos: operacje typu: "dodaj element" "usuń element", "zapisz do pliku", "odczytaj z pliku itd, mam napisany kod jednak przy uruchomieniu i np. próba zapisania na plik kończy się fiaskiem, czy ktoś mógłby spojrzeć na kod, i pomóc w rozwiązaniu problemu?

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "stack.h"
#include "interface.h"
#include "student.h"
#include "errory.h"



int main()
{
	stack_init(STUDENT_free);
	int wybor=-1;
	int check;
	while (wybor != 6)
	{
		menu();
		check=scanf_s("%d", &wybor);
		if (check != 1)
			errorprint(INPUT_ERROR);

		switch (wybor)
		{
		case 0:
			push();
			break;
		case 1:
			pop();
			break;
		case 2:
			find();
			break;
		case 3:
			display_stack();
			break;
		case 4:
			save();
			break;
		case 5:
			load();
			break;
		case 6:
			exit();
			break;
		default:
			break;
		}
	}

}
interface.cpp
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#include "interface.h"
#include "student.h"
#include "errory.h"



#pragma warning (disable : 4996)

static const char* strtab[] =
{
	"0 - push",
	"1 - pop",
    "2 - find",
	"3 - display stack",
	"4 - save to file",
	"5 - load from file",
	"6 - exit"
};

void exiterrorstack(FILE* file, __int64* arr)
{
	if (file)
		fclose(file);
	if (arr)
		free(arr);
	errorprint(FATAL_ERROR);
}


void exiterror(FILE* file, void* pom, __int64* arr, FreeData wskFree)
{
	if (file)
		fclose(file);
	if (arr)
		free(arr);
	wskFree(pom);
	errorprint(FATAL_ERROR);
}

void menu() {
	size_t tabsize=sizeof(strtab)/sizeof(strtab[0]);
	int i;
	for (i = 0; i < tabsize; ++i) {
		printf("%s\n", strtab[i]);
	}
	printf("Wybor:");


}

void push()
{
	char lastname[256];
	printf("Nazwisko: ");
	scanf("%s", &lastname);
	int rok, kier, blad = 0;
	printf("Rok:\n");
	while (!blad)
	{
		if (scanf("%d", &rok) && rok >= 0)
			blad = 1;
		else
			printf("ERROR - podano nieprawidłowe dane!!\n");

		while (getchar() != '\n');
	}
	printf("\n");
	printf("Podaj kierunek:\n[1] - Informatyka\n[2] - Elektornika i Telekomunikacja\n[3] - Automatyka i Robotyka\n\n");
	blad = 0;
	while (!blad)
	{
		if (scanf("%d", &kier) && kier >= 1 && kier <= 3)
			blad = 1;
		else
			printf("ERROR - podano nieprawidłowe dane!!\n");
		while (getchar() != '\n');
	}


}

void pop()
{
	stackData_free();
}
void display_stack()
{
	display_Stack();
}
int find()
{
	//stack_search();
	return 0;
}
void exit()
{
	exit(1);
	stackData_free();
}
void load()
{
	stack_read();
}
void save()
{
	stack_save();
}
stack.cpp
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>
#include "stack.h"
#include "interface.h"
#include "errory.h"


#pragma warning (disable : 4996)

static STACK* head = NULL;
static FreeData wskFree;
static DisplayData wskDisplay;
static SaveToFile wskSave;
static ReadFromFile wskRead;

void stack_init(FreeData wFree)
{
	head = NULL;
	wskFree = wFree;
}

void stack_free()
{
	STACK* pomoc;
	while ((pomoc = head) != NULL)
	{
		head = head->next;
		wskFree(pomoc->Data);
		free(pomoc);
	}
}

void display_Stack()
{
	STACK* pomoc = head;
	if (pomoc != NULL)
	{
		puts("                 Zawartość stosu                ");
		do {
			wskDisplay(pomoc->Data);
			pomoc = pomoc->next;
		} while (pomoc != NULL);

	}
	else
		printf("STOS JEST PUSTY\n");
}

STACK* stack_push(void* data)
{
	STACK* ielem = (STACK*)malloc(sizeof(STACK));
	if (!ielem)
	{
		errorprint(BLAD_ALOKACJI);
		return NULL;
	}
	if (head == NULL)
		ielem->Data = data;
	if (head == NULL)
	{
		ielem->next = NULL;
		head = ielem;
	}
	else
	{
		ielem->next = head;
		head = ielem;
	}
	return head;
}

STACK* stack_pop()
{
	if (head == NULL)
	{
		printf("STOS JEST PUSTY\n");
		return NULL;
	}
	STACK* pomoc = head;
	head = pomoc->next;
	pomoc->next = NULL;
	free(head);
	return pomoc;
}

void stackData_free()
{
	STACK* pomoc = stack_pop();
	if (pomoc != NULL) {
		wskFree(pomoc->Data);
		free(pomoc);
	}
}

void* stack_search(void* wSearch, CompData compfun, int pierwsze)
{
	static STACK* p;
	STACK* pomoc = NULL;
	if (pierwsze)
		p = head;
	while (p) {
		if (!(compfun)(p->Data, wSearch))
			p = p->next;
	else
	{
		pomoc = p;
		p = p->next;
		return pomoc->Data;
	}
	}
	return NULL;
}

static int iloscelementow()
{
	STACK* pomocnicza = head;
	int ilo = 0;
	if (pomocnicza != NULL)
	{
		while (pomocnicza != NULL)
		{
			ilo++;
			pomocnicza = pomocnicza->next;
		}
	}
	return ilo;
}

void stack_save()
{
	FILE* save;
	save = fopen("stos.bin", "wb");
	if (!save)
		errorprint(NO_FILE);
	STACK* pomocnicza = head;

	int noitem = iloscelementow();
	__int64* arr = (__int64*)malloc((noitem + 1) * sizeof(__int64));
	if (!arr) 
	{
		exiterror(save, pomocnicza->Data, arr, wskFree);
	}

	if (fwrite(&noitem, sizeof(unsigned int), 1, save) != 1) {
		exiterror(save, pomocnicza->Data, arr, wskFree);
	}
	_fseeki64(save, (noitem + 1) * sizeof(__int64), SEEK_CUR);

	size_t i = 0;
	if (pomocnicza != NULL) {
		do {
			arr[i] = ftell(save);
			wskSave(pomocnicza->Data, save);
			pomocnicza = pomocnicza->next;
			i++;
		} while (pomocnicza != NULL);
	}
	arr[i] = ftell(save);
	_fseeki64(save, sizeof(unsigned int), SEEK_SET);
	if (fwrite(arr, sizeof(__int64), noitem + 1, save) != noitem + 1) 
	{
		exiterror(save, pomocnicza->Data, arr, wskFree);
	}

	if (save)
		fclose(save);
	save = NULL;

	if (arr)
		free(arr);
	arr = NULL;
	
}

void stack_read()
{
	stack_free();

	FILE* read = fopen("stos.bin", "rb");
	if (!read) {
		errorprint(NO_FILE);
	}

	unsigned int noitem = 0, it, rec;
	__int64* arr = NULL;


	if (fread(&noitem, sizeof(unsigned int), 1, read) != 1) {
		exiterrorstack(read, arr);
	}
	arr = (__int64*)malloc((noitem + 1) * sizeof(__int64));

	if (!arr) {
		exiterrorstack(read, arr);
	}

	if (fread(arr, sizeof(arr[0]), noitem + 1, read) != noitem + 1) {
		exiterrorstack(read, arr);
	}

	for (it = 0; it < noitem; ++it) {

		rec = noitem - it - 1;
		_fseeki64(read, arr[rec], SEEK_SET);

		void* pDat = wskRead(read);

		if (!stack_push(pDat)) {
			exiterrorstack(read, arr);
		}
	}
	if (arr)
		free(arr);
	arr = NULL;

	if (read)
		fclose(read);
	read = NULL;
}
student.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "stack.h"
#include "interface.h"
#include "errory.h"
#include "student.h"




void* STUDENT_Init(char* lastname, int year, size_t sizenazwisko, enum KIERUNEK kier)
{
	STUDENT* ptr = (STUDENT*)malloc(sizeof(STUDENT));
	if (!ptr) 
	{
		errorprint(BLAD_ALOKACJI);
	}
		ptr->nazwisko = (char*)malloc((sizenazwisko) * sizeof(char));
		if (!ptr->nazwisko) 
		{
			errorprint(BLAD_ALOKACJI);
		}
		strcpy_s(ptr->nazwisko, (sizenazwisko) * sizeof(char), lastname);
		ptr->rok = year;
		switch (kier)
		{
		case informatyka:
			ptr->kierunek = informatyka;
			break;
		case elektronika_i_telekomunikacja:
			ptr->kierunek = elektronika_i_telekomunikacja;
			break;
		case automatyka_i_robotyka:
			ptr->kierunek = automatyka_i_robotyka;
			break;
		default:
			errorprint(INPUT_ERROR);
			break;
		}

	return(void*)(ptr);	
}

void* STUDENT_Push(char* lastname, int year, size_t sizenazwisko, enum KIERUNEK kier)
{
	return STUDENT_Init(lastname, year, sizenazwisko, kier);
}

void STUDENT_Print(void* ptr)
{
	STUDENT* pomocnicza = (STUDENT*)ptr;
	if (pomocnicza)
	{
		printf("|%-10s     ", pomocnicza -> nazwisko);
		printf("|%-10d     ", pomocnicza -> rok);
		switch (pomocnicza->kierunek)
		{
		case 1:
			printf("|%-13s   |\n", "Informatyka");
			break;
		case 2:
			printf("|%-13s   |\n", "Elektronika i Telekomunikacja");
			break;
		case 3:
			printf("|%-13s   |\n", "Automatyka i Robotyka");
			break;
		};
	}
}
void STUDENT_save(void* ptr, FILE* save, __int64* arr) 
{

	STUDENT* temp = (STUDENT*)ptr;
	size_t len;
	if (temp) {
		len = strlen(temp->nazwisko);
		if (fwrite(&len, sizeof(len), 1, save) != 1) {
			exiterror(save, temp, arr, STUDENT_free);
		}

		if (fwrite(temp->nazwisko, sizeof(temp->nazwisko[0]), (len + 1), save) != len + 1) {
			exiterror(save, temp, arr, STUDENT_free);
		}


		if (fwrite(&temp->rok, sizeof(temp->rok), 1, save) != 1) {
			exiterror(save, temp, arr, STUDENT_free);

		}
		if (fwrite(&temp->kierunek, sizeof(temp->kierunek), 1, save) != 1) {
			exiterror(save, temp, arr, STUDENT_free);
		}
	}
}

void* STUDENT_read(FILE* read, __int64* arr, unsigned int rec, unsigned int noItems) {

	STUDENT* temp = NULL;

	temp = (STUDENT*)malloc((noItems) * sizeof(STUDENT));

	memset(temp, 0, noItems * sizeof(STUDENT));

	int len = 0;
	if (fread(&len, sizeof(int), 1, read) != 1) {
		exiterror(read, temp, arr, STUDENT_free);
	}
	temp[rec].nazwisko = (char*)malloc((len + 1) * sizeof(char));

	if (fread(temp[rec].nazwisko, sizeof(temp[rec].nazwisko[0]), len + 1, read) != len + 1) {
		exiterror(read, temp, arr, STUDENT_free);
	}
	if (fread(&len, sizeof(int), 1, read) != 1) {
		exiterror(read, temp, arr, STUDENT_free);
	}
	

	if (fread(&temp[rec].rok, sizeof(temp[rec].rok), 1, read) != 1) {
		exiterror(read, temp, arr, STUDENT_free);
	}

	if (fread(&temp[rec].kierunek, sizeof(temp[rec].kierunek), 1, read) != 1) {
		exiterror(read, temp, arr, STUDENT_free);
	}
	
	void* pDat = STUDENT_Push(temp[rec].nazwisko, temp[rec].rok, strlen(temp[rec].nazwisko), temp[rec].kierunek);

	STUDENT_free(temp);

	return pDat;
}



void STUDENT_free(void* ptr)
{
	STUDENT* wsk = (STUDENT*)ptr;
	if (!wsk)
		return;
	if (wsk->nazwisko)
		free(wsk->nazwisko);
	wsk->nazwisko = NULL;

	free(wsk);
}

2

wskSave(pomocnicza->Data, save); - jak działa ta funkcja?

2

Nie wiem jak inni, ale na moje to strasznie przekombinowany ten kod jak na zwykłą implementację stosu.
Może taka cecha C, nie wiem bo klepię w CPP.

2

Zmienne globalne i do tego jeszcze zmienne static wewnątrz funkcji bez wyraźnego uzasadnienia.
Na dodatek kod jest niekompletny (np nie ma definicji STACK).

To też jest fajny kwiatek:

void display_stack()
{
    display_Stack();
}

Żeby to ogarnąć potrzeba sporo czasu. Chyba prościej by było napisać samemu od nowa.

0

@MarekR22: Dokładnie, masa zbędnego kodu.
Albo coś takiego:

void* STUDENT_Push(char* lastname, int year, size_t sizenazwisko, enum KIERUNEK kier)
{
    return STUDENT_Init(lastname, year, sizenazwisko, kier);
}

Po co ci funkcja do wywołania innej funkcji?

1

Wysiliłem się trochę.
Popatrz na to, nie ma to więcej sensu? Nie łatwiej to czytać, od razu wiadomo co się dzieje!
Detale są odizolowane od ogółu, zero zmiennych globalnych.

#ifndef My_Universal_Stack_h
#define My_Universal_Stack_h

struct UniversalStack;
typedef struct UniversalStack *UniversalStackPtr;
typedef void (*UniversalStackFreeItemFunction)(void *);
typedef void (*UniversalStackForEachFunction)(void * item, void *context);

UniversalStackPtr UniversalStackMake(UniversalStackFreeItemFunction onFree);
void UniversalStackFree(UniversalStackPtr stack);

int UniversalStackIsEmpty(UniversalStackPtr stack);
void UniversalStackPush(UniversalStackPtr stack, void *);
void* UniversalStackPopAndReturnItem(UniversalStackPtr stack);
void UniversalStackPopAndFreeItem(UniversalStackPtr stack);

void UniversalStackForEachItemDo(UniversalStackPtr stack, UniversalStackForEachFunction f, void *context);

#endif // My_Universal_Stack_h
#include "UniversalStack.h"

#include <stdlib.h>

struct _UniversalStackItem
{
    struct _UniversalStackItem* next;
    void *value;
};

struct UniversalStack
{
    struct _UniversalStackItem* head;
    UniversalStackFreeItemFunction itemFreeFun;
};

UniversalStackPtr UniversalStackMake(UniversalStackFreeItemFunction onFree)
{
    UniversalStackPtr r = malloc(sizeof(struct UniversalStack));
    if (r)
    {
        r->head = NULL;
        r->itemFreeFun = onFree;
    }
    return r;
}

void UniversalStackFree(UniversalStackPtr stack)
{
    while(!UniversalStackIsEmpty(stack)) {
        UniversalStackPopAndFreeItem(stack);
    }
    free(stack);
}

int UniversalStackIsEmpty(UniversalStackPtr stack)
{
    return stack->head == NULL;
}

void UniversalStackPush(UniversalStackPtr stack, void *value)
{
    struct _UniversalStackItem* item = malloc(sizeof(*stack->head));
    if (item)
    {
        item->next = stack->head;
        stack->head = item;
        item->value = value;
    }
}

void* UniversalStackPopAndReturnItem(UniversalStackPtr stack)
{
    void* item = NULL;
    struct _UniversalStackItem* node = NULL;
    if (stack->head)
    {
        node = stack->head;
        item = node->value;
        stack->head = node->next;
        free(node);
    }
    return item;
}

void UniversalStackPopAndFreeItem(UniversalStackPtr stack)
{
    void* item = UniversalStackPopAndReturnItem(stack);
    stack->itemFreeFun(item);
}

void UniversalStackForEachItemDo(UniversalStackPtr stack, UniversalStackForEachFunction f, void *context)
{
    struct _UniversalStackItem* node = stack->head;
    while(node)
    {
        f(node->value, context);
        node = node->next;
    }
}

https://wandbox.org/permlink/KOaWBEZGsSh7cnd9

1

Też proponuje wywalić i napisać ponownie.
Bo w tym kodzie totalny bajzel.
Zrób przynajmniej stos porządnie;

typedef struct stos_item
{
    struct stos_item *next;
    void *userdata; // tu będziesz mógł podpiąć studenta, czy cokolwiek innego
} stos_item;

typedef struct stos
{
    size_t count; // zwiększać po każdym dodaniu i zmniejszać przy usunięciu
    stos_item *head;
} stos_item;

void stosInit(stos *s) { s->head=s->count=0; }
void stosFree(stos *s)
{
    while(s->head)
    {
        stos_item *next=s->head->next;
        free(s->head->userdata); // zauważ że nie musisz wiedzieć czym jest ten user->data;
        free(s->head);
        s->head=next;
    }
    s->count=0; 
}


Oraz może zrób menu porządnie, np tak:

#include <stdio.h>

typedef struct
  {

  } SharedData;

typedef void Execute(SharedData *sd,int opt); // deklaracja funkci wykonującej menu

typedef struct Menu
  {
   const char *text; // tekst menu
   struct Menu *menu; // podmenu
   Execute *exec; // funkcja wykonująca polecenie menu
   int opt; // ewentualny parametr
  } Menu;

void RunMenu(const char *name,Menu *menu,SharedData *sd) // funkcja obslugujaca menu
  {
   unsigned nr,w;
   int ret;
   Menu *tmp;
   for(;;)
     {

      printf("-- %s:\n",name);
      for(nr=1,tmp=menu;(tmp->menu!=NULL)||(tmp->exec!=NULL);++nr,++tmp)
        {
         printf("%d. %s\n",nr,tmp->text);
        }
      printf("0. %s\nWybierz opcje: ",tmp->text);
      ret=scanf("%u",&w);
      while(getchar()!='\n') {}
      if((ret==1)&&(w<nr))
        {
         tmp=menu+(w+nr-1)%nr;
         if(tmp->menu)
           {
            printf("\n");
            RunMenu(tmp->text,tmp->menu,sd);
           }
         else if(tmp->exec)
           {
            printf("\n");
            tmp->exec(sd,tmp->opt);
           }
         else break;         
        }
      else printf("blad: nalezy wpisac jeden z numerkow menu\n");
      printf("\n");
     }
  }

void SortExec(SharedData *sd,int opt)
  {
   printf("REALIZACJA: Sortowanie wg %c\n\n",'A'+opt);
  }

void FindExec(SharedData *sd,int opt)
  {
   printf("REALIZACJA: Szukaj wg %c\n\n",'A'+opt);
  }

void AddExec(SharedData *sd,int opt)
  {
   printf("REALIZACJA: Dodaj\n\n");
  }

void ShowExec(SharedData *sd,int opt)
  {
   printf("REALIZACJA: Przegladaj\n\n");
  }

void SaveExec(SharedData *sd,int opt)
  {
   printf("REALIZACJA: Zapisz\n\n");
  }

void LoadExec(SharedData *sd,int opt)
  {
   printf("REALIZACJA: Wczytaj\n\n");
  }

void DeleteExec(SharedData *sd,int opt)
  {
   printf("REALIZACJA: Usun\n\n");
  }

Menu Sort[]=
  {
   {"Sortowanie wg A",NULL,SortExec,0},
   {"Sortowanie wg B",NULL,SortExec,1},
   {"Sortowanie wg C",NULL,SortExec,2},
   {"Powrot",NULL,NULL,0},
  };

Menu Find[]=
  {
   {"Szukaj wg A",NULL,FindExec,0},
   {"Szukaj wg B",NULL,FindExec,1},
   {"Szukaj wg C",NULL,FindExec,2},
   {"Powrot",NULL,NULL,0},
  };

Menu Main[]=
  {
   {"Dodaj",NULL,AddExec,0},
   {"Przegladaj",NULL,ShowExec,0},
   {"Zapisz",NULL,SaveExec,0},
   {"Sortuj",Sort,NULL,0},
   {"Szukaj",Find,NULL,0},
   {"Usun",NULL,DeleteExec,0},
   {"Wczytaj",NULL,LoadExec,0},
   {"Koniec",NULL,NULL,0},
  };

int main()
  {
   SharedData sd;
   RunMenu("Menu glowne",Main,&sd);
   return 0;
  }

1 użytkowników online, w tym zalogowanych: 0, gości: 1