Stos zapis odczyt z pliku

0

Cześć, mam problem z zapisem elementu stosu na dysk w plik binarny. Według specyfikacji stos podczas zapisu pownien być odzielony od danych
oraz nie powinien nic wiedziec o typie danych natomiast nie rozumiem jak mam odzielić stos od danych dzięki czemu potem mógłbym go odczytać.

Myślałem o czymś takim podczas zapisu w pliku my_stack.c:


void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	MY_STACK* p = first;
	while (p)
	{
		fwrite(p->pData, sizeof(p->pData), 1, pf);
		p = p->next;
	}
	fclose(pf);
}
Stack.c

#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include "stdafx.h"
#include "my_interface.h"
#include "my_stack.h"
#include "my_student.h"
#include "error_handling.h"

int _tmain(int argc, _TCHAR* argv[])
{
	MessageToScreen(COM_NUMB_START);

	MY_STACK_Init(MY_STUDENT_Free);
	size_t op = 0;
	while (op >= INTERF_PUSH && op <= INTERF_STOP)
	{
		menu();
		scanf("%d", &op);
		switch (op)
		{
		case INTERF_PUSH: push();
			break;
		case INTERF_POP: pop();
			break;
		case INTERF_CLEAR: clear();
			break;
		case INTERF_FIND_LASTNAME: find_lastname();
			break;
		case INTERF_SAVE_STACK: save_stack_to_disk();
			break;
		case INTERF_LOAD_STACK: load_stack_from_disk();
			break;
		case INTERF_STOP: 
			clear(); 
			MessageToScreen(COM_NUMB_FINISH);
			return 0;
		default:
			printf("nieuznawany kod operacji\n");
		};
	}
	return 0;
}
my_stack.c

#include <stdlib.h>
#include <stdio.h>
#include "my_stack.h"
#include "my_student.h"
#include "my_interface.h"
#include "string.h"
#include "error_handling.h"

#pragma warning (disable : 4996)

//// Obsluga zapisu-odczytu projektu powinna byc tu.
static FILE* pf = NULL;
static MY_STACK* first = NULL; 
FreeData ptr_free_dat;

void MY_STACK_Init(FreeData pFreeDat)
{
	first = NULL;
	ptr_free_dat = pFreeDat;
}

void MY_STACK_Free()
{
	MY_STACK *p = first, *ptmp = NULL;

	while (p)
	{
		(*ptr_free_dat)(p->pData);

		ptmp = p;

		p = p->next;

		free(ptmp);
	}

	first = NULL;

	MessageToScreen(COM_NUMB_FREE_ALL);
}

MY_STACK* MY_STACK_Push(void* pdat)
{
	MY_STACK* current = (MY_STACK*)malloc(sizeof(MY_STACK));

	if (!current)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	current->next = NULL;
	

	
	if (!first)
		first = current;
	else
		current->next = first;
	
	first = current;
	current->pData = pdat;
	
	return current;

}

MY_STACK MY_STACK_Pop()
{
	MY_STACK rv;

	if (!first)
	{
		rv.pData = NULL;
		rv.next = NULL;
	}
	else
	{
		MY_STACK* next = first->next;
		rv.pData = first->pData;

		rv.next = NULL;

		free(first);

		first = next;
	}
	
	return rv;
}

void* MY_STACK_Search(void* pSearchDat, CompData ptr_comp_fun, int FirstEntry)
{
	static MY_STACK* p;
	MY_STACK* ptmp = NULL;
	
	if (FirstEntry)
		p = first;

	while (p)
	{
		if (!(*ptr_comp_fun)(p->pData, pSearchDat))
		{
			p = p->next;
		}
		else
		{
			ptmp = p;
			p = p->next;
			return ptmp->pData;
		}
	}

	return NULL;
}



void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	MY_STACK* p = first;
	MY_STUDENT* student;  //////stos nie jest oddzielony od danych

	while (p)
	{
		//////Stos nie powinien nic wiedziec o typie danych
		student = (MY_STUDENT*)p->pData;
		MY_STUDENT_SaveToFile(pf, student);
		p = p->next;
	}

	fclose(pf);
}

void MY_STACK_LoadFromFile(const char* filename)
{
	FILE* pf = fopen(filename, "rb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
		return;
	}

	MY_STACK_Free();
	MessageToScreen(COM_NUMB_READ_FILE);
	MY_STUDENT_LoadFromFile(pf);  //////???
	fclose(pf);
}
my_stack.h

#ifndef MY_STACK___H
#define MY_STACK___H

struct MY_STACK
{
	void *pData;
	MY_STACK *next;
};

extern MY_STACK* first;
typedef void (*FreeData)(void* pdat);
typedef int (CompData)(void* pcurData, void *pSearchData);

void MY_STACK_Init(FreeData pFreeDat);
void MY_STACK_Free();

MY_STACK* MY_STACK_Push(void* pdat);
MY_STACK MY_STACK_Pop();
void* MY_STACK_Search(void* pSearchDat, CompData ptr_comp_fun, int FirstEntry);
void MY_STACK_SaveToFile(const char* filename);
void MY_STACK_LoadFromFile(const char* filename);

#endif
my_student.c

#include <stdio.h>
#include <stdlib.h>
#include "my_student.h"
#include "my_interface.h"
#include "string.h"
#include "my_stack.h"
#include "error_handling.h"

// Obsluga IO powinna byc tu.

void* MY_STUDENT_Init(const char* llastname, int birthyear, enum StudyDirection studydirection)
{
	MY_STUDENT* pstudent = (MY_STUDENT*)malloc(sizeof(MY_STUDENT));
	if (!pstudent)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	if (pstudent)
	{
		pstudent->lastname = (char*)malloc((strlen(llastname) + 1) * sizeof(char));
		
		if (!pstudent->lastname)
			MessageToScreen(ERR_NUMB_ALLOC_MEM);

		if (pstudent->lastname)
		{
			strcpy(pstudent->lastname, llastname);
			pstudent->length = strlen(llastname);
			pstudent->lastname[strlen(llastname)] = '\0';
			pstudent->birth_year = birthyear;
			pstudent->study_direction = studydirection;
		}
		else
		{
			free(pstudent);
			pstudent = NULL;
		}
	}
	return (void*)(pstudent);
}

void MY_STUDENT_Free(void* ptr)
{
	MY_STUDENT* pStudent = (MY_STUDENT*)ptr;

	if (pStudent)
	{
		if (pStudent->lastname)
			free(pStudent->lastname);
		free(pStudent);
	}
}

void* MY_STUDENT_Push(const char* llastname, int birthyear, enum StudyDirection studydirection)
{
	return MY_STUDENT_Init(llastname, birthyear, studydirection);
}


void MY_STUDENT_Print(void* ptr)
{
	MY_STUDENT* p = (MY_STUDENT*)ptr;
	if (p)
	{
		printf("Nazwisko     : %s\n", p->lastname);
		printf("Rok urodzenia: %d\n", p->birth_year);
		printf("Kierunek     : %d\n", p->study_direction);
	}
}

int MY_STUDENT_SearchLastName(void* pCurData, void* pSearchStudent)
{
	MY_STUDENT* pcur = (MY_STUDENT*)pCurData;
	MY_STUDENT* psearch = (MY_STUDENT*)pSearchStudent;

	if (strcmp(pcur->lastname, psearch->lastname) == 0)
		return 1;

	return 0;
}

void MY_STUDENT_SaveToFile(FILE *pf, void *student)
{
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}
	MY_STUDENT* s = (MY_STUDENT*)student;
	fwrite(s, sizeof(MY_STUDENT), 1, pf);
	fwrite(s->lastname, sizeof(char), s->length, pf);
}


void MY_STUDENT_LoadFromFile(FILE* pf)
{
	MY_STUDENT student;
	size_t count_read = 1;

	count_read = fread(&student, sizeof(MY_STUDENT), 1, pf);

	if (count_read != 1)
		return;

	int length = student.length;
	student.lastname = (char*)malloc((length + 1) * sizeof(char));

	if (!student.lastname)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	fread(student.lastname, sizeof(char), student.length, pf);
	student.lastname[student.length] = '\0';

	MY_STUDENT_LoadFromFile(pf);

	void* pdat = MY_STUDENT_Push(student.lastname, student.birth_year, student.study_direction);
	if (!MY_STACK_Push(pdat))
		printf("push error\n");

	free(student.lastname);

}
my_student.h

#ifndef MY_STUDENT_H
#define MY_STUDENT_H

enum StudyDirection {
	ELECTRICAL_ENGINEERING,
	MECHANICAL_ENGINEERING,
	COMPUTER_SCIENCE,
	TOTAL_STUDY_DIRECTIONS
};


struct MY_STUDENT
{
	char *lastname;
	int length;
	int birth_year;
	enum StudyDirection study_direction;
};

void* MY_STUDENT_Init(const char* llastname, int birthyear, enum StudyDirection studydirection);
void MY_STUDENT_Free(void *ptr);
void* MY_STUDENT_Push(const char* llastname, int birthyear, enum StudyDirection studydirection);
void MY_STUDENT_Print(void* ptr);
int MY_STUDENT_SearchLastName(void* pCureData, void* pSearchStudent);
void MY_STUDENT_SaveToFile(FILE* pf, void* student);
void MY_STUDENT_LoadFromFile(FILE* pf);

#endif
my_interface.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "my_interface.h"
#include "my_student.h"
#include "my_stack.h"
#include "error_handling.h"

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

static const char* studytab[] =
{
	"ELECTRICAL_ENGINEERING",
	"MECHANICAL_ENGINEERING",
	"COMPUTER_SCIENCE",
};

void menu()
{
	size_t it;
	for (it = 0; it < INTERF_TOT; it++)
	{
		printf("%s\n", strtab[it]);
	}
}


void print_study_directions()
{
	printf("\nDostepne kierunki studiow:\n");
	for (int i = 0; i < TOTAL_STUDY_DIRECTIONS; i++)
	{
		printf("%d - %s\n", i, studytab[i]);
	}
	printf("\nWybierz number kierunku studiow: ");
}

void push()
{
	char lastname[512];
	int birth_year;
	enum StudyDirection study_direction;
	printf("Nazwisko, Rok urodzenia\n");
	scanf_s("%511s", lastname, (unsigned int)sizeof(lastname));
	scanf_s("%d", &birth_year);

	print_study_directions();
	scanf_s("%d", &study_direction);
	
	void* pdat = MY_STUDENT_Push(lastname, birth_year, study_direction);
	if (!MY_STACK_Push(pdat))
		printf("push error\n");
}

void pop()
{
	MY_STACK tmp = MY_STACK_Pop();
	MY_STUDENT_Print(tmp.pData);
	MY_STUDENT_Free(tmp.pData);
}

void find_lastname()
{
	char str[128];
	printf("input lastname\n");
	scanf_s("%s", str, (unsigned int)sizeof(str));

	MY_STUDENT searchDat;
	memset(&searchDat, 0, sizeof(MY_STUDENT));

	searchDat.lastname = (char*)malloc((strlen(str) + 1) * sizeof(char));
	
	if (!searchDat.lastname)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	if (searchDat.lastname != NULL)
	{
		strcpy(searchDat.lastname, str);

		void* pDat = MY_STACK_Search(&searchDat, MY_STUDENT_SearchLastName, 1);

		if (pDat)
		{
			printf("found : \n");
			MY_STUDENT_Print(pDat);
		}

		while (pDat)
		{
			pDat = MY_STACK_Search(&searchDat, MY_STUDENT_SearchLastName, 0);
			if (pDat)
			{
				printf("found : \n");
				MY_STUDENT_Print(pDat);
			}

		}
	}
	free(searchDat.lastname);
}

void save_stack_to_disk()
{
	char filename[128];
	printf("input filename\n");
	scanf_s("%s", filename, (unsigned int)sizeof(filename));
	MY_STACK_SaveToFile(filename);
}

void load_stack_from_disk()
{
	char filename[128];
	printf("input filename\n");
	scanf_s("%s", filename, (unsigned int)sizeof(filename));
	MY_STACK_LoadFromFile(filename);
}

void clear()
{
	MY_STACK_Free();
}
1

Szczerze to nie rozumiem pytania. Ale czasem trzeba dać odpowiedź nawet jak się pytania nie zrozumiało. ;-)

Czyżby chodziło o taki stos, że jak się coś dodaje to ląduje na górze a jak zabiera to znika z wierzchu.
No to normalnie wsadzasz to w uint32_t i zapisujesz do pliku. I tu jest pewien myk z fopen. b chyba faktycznie coś zmienia w otwieraniu w pliku na windowsie - radzę zainteresować się manualem ;-)

Jedyne co to pewnie dobrze by było napisać wyraz na samym dole stosu jako pierwszy w pliku to potem łatwo załadujesz na stosik.

Pewnie nie pomogłem ale przynajmniej coś naklepałem!

0

Szczerze to nie rozumiem odpowiedzi. Ale czasem trzeba dać odpowiedź jak się odpowiedzi nie zrozumiało. xD

Nie rozkminiam właśnie jak zapisać element stosu do pliku, bo tutaj mam studenta ale np jakby ktos chcial zmienic typ danych z my_student na my_triangle to nie powinno spowodować żadnej zmiany w linach kodu obsługi stosu, a ja własnie w funkcji MY_STACK_SaveToFile używam tego typu danych studenta bo nie umiem tego inaczej zrobić i ganią za to, próbuje to zmienić ale mi się wtedy nie chcę odtworzyć z powrotem stos z pliku.

1

Też nie rozumiem pytania.

Kod przypomniał mi z radością, dlaczego nie piszę już w C.

Nie, nie jest to jakiś fatalny kod @helloWorld123 z typowymi błędami początkujących, np zapis binarny pointera, akurat chyba to dobrze zrobiłeś.

mnożenie przez sizeof(char) jest niecelowe, to ze standardu jest jeden, inaczej mówiąc sizeof jest w charach.
Zabezpieczanie przed błędami runtime jest niepełne, typowe dla C, jakieś drukowanie komunikatu ale kontynuacja algorytmu ...

Funkcja zwracające wynik w zmiennych globalnych ... brrr, ale na usprawiedliwienie zwracanie czegoś złożonego w C to robota w pocie czoła, ustalić konwencję, narzuć callerowi i funkcji jakieś operacje (alokowanie i zwalnianie metoda małego Jasia / jedna sztuka statycznie / rotujące kilka sztuk / alokowane).

Oczywiście ten cały misterny plan w ... (wiadomo, kultowe słowa), jest antywątkowy, stos jest jeden i tylko jeden. GDYBY za walizkę dolarów musiał pisać w C, bym pisał w "obiektowym C", odpowiednikiem this'ów w argumencie itd bez zmiennych globalnych...

Funkcje np STYDENT_ z void *, ja bym użył STUDENT *, byłoby jaśniej (dwa rzutowania mniej - choć gdzie indziej rzutowanie)

Traktowanie enumów jak integerów (scanf %d) jest zależne przynajmniej od opcji kompilacji

Dwa typy, być może aby uzyskać to "coś" dynamiczne w typowaniu, tak, ja z płaczem wiem, że w C nie za bardzo da sie inaczej (choć w obiektowym C można użyć prawie dobrych metod wirtualnych, prawie-dziedziczenia co by ratowało ten projekt)
Nie chcę się w to wczytywac, wolę zdrowy sen bez koszmarów, które bym miał po analizie

Sens dydaktyczny tego projektu? Na pewno jest przynajmniej jeden: wiedzieć do czego C sie nie nadaje.

Już sam formalizm C++, nawet nie super ambitny, ale "C z klasami" i kilka tricków, bardzo by ratowały

1
helloWorld123 napisał(a):

Cześć, mam problem z zapisem elementu stosu na dysk w plik binarny. Według specyfikacji stos podczas zapisu pownien być odzielony od danych
oraz nie powinien nic wiedziec o typie danych natomiast nie rozumiem jak mam odzielić stos od danych dzięki czemu potem mógłbym go odczytać.

W bardzo prosty sposób oddzielasz stos od typu danych przechowywanych na stosie podczas zapisu/odczytu do pliku:

  1. W MY_STACK_SaveToFile na początku otwierasz plik (ewentualnie wpisujesz dane nagłówkowe) i w pętli przetwarzasz stos, a na końcu zamykasz plik.
  2. W MY_STUDENT_SaveToFile zapisujesz do pliku dane w specyficzny sposób dla tej struktury danych. Ta funkcja jest wołana w powyższej pętli.

Myślałem o czymś takim podczas zapisu w pliku my_stack.c:


void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	MY_STACK* p = first;
	while (p)
	{
		fwrite(p->pData, sizeof(p->pData), 1, pf);
		p = p->next;
	}
	fclose(pf);
}

Tak się nie da zrealizować, ponieważ w MY_STACK nie masz informacji o typach danych.

void MY_STACK_SaveToFile(const char* filename);
void MY_STACK_LoadFromFile(const char* filename);
void MY_STUDENT_SaveToFile(FILE* pf, void* stack_data);
void MY_STUDENT_LoadFromFile(FILE* pf, void **stack_data);

W zasadzie Twoje zadane pytanie zrozumiałem dopiero po spojrzeniu na deklaracje powyższych funkcji (trochę zmienione przeze mnie).

void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	MY_STACK* p = first;
	MY_STUDENT* student;  //////stos nie jest oddzielony od danych

	while (p)
	{
		//////Stos nie powinien nic wiedziec o typie danych
		student = (MY_STUDENT*)p->pData;
		MY_STUDENT_SaveToFile(pf, student);
		p = p->next;
	}

	fclose(pf);
}

void MY_STACK_LoadFromFile(const char* filename)
{
	FILE* pf = fopen(filename, "rb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
		return;
	}

	MY_STACK_Free();
	MessageToScreen(COM_NUMB_READ_FILE);
	MY_STUDENT_LoadFromFile(pf);  //////???
	fclose(pf);
}

Może żeby stos był oddzielony od danych to trzeba by użyć albo zapisanego (w nagłówku MY_STACK) w enumie typu danych (MY_STUDENT) i zewnętrznej funkcji zwracającej właściwą funkcję zapisu/odczytu na podstawie tego typu, albo wprost wskaźnika do funkcji zapisu/odczytu; ponieważ takich funkcji jak i typów danych może być wiele. Wtedy MY_STACK woła taką funkcję przez wskaźnik, podając jej wskaźnik do danych, i nie wie o typie danych. Trudno powiedzieć, o co mogło chodzić, żeby ‚bardziej’ oddzielić stos od danych.

1

Duże to jest...

Na jeden rzut oka:

void MY_STUDENT_Print(void* ptr)
{
	MY_STUDENT* p = (MY_STUDENT*)ptr;
	if (p)
	{
		printf("Nazwisko     : %s\n", p->lastname);
		printf("Rok urodzenia: %d\n", p->birth_year);
		printf("Kierunek     : %d\n", p->study_direction);
	}
}


Po pierwsze jak coś jest *void to nie trzeba tego castować. To nie C++.

Czyli:

void MY_STUDENT_Print(void* ptr)
{
	MY_STUDENT* p = ptr;
	if (p)
	{
		printf("Nazwisko     : %s\n", p->lastname);
		printf("Rok urodzenia: %d\n", p->birth_year);
		printf("Kierunek     : %d\n", p->study_direction);
	}
}

Po kolejne: sensowniej byłoby:

void MY_STUDENT_Print( MY_STUDENT* p)
{
	if (p)
	{
		printf("Nazwisko     : %s\n", p->lastname);
		printf("Rok urodzenia: %d\n", p->birth_year);
		printf("Kierunek     : %d\n", p->study_direction);
	}
}

I wtedy jak nie przekażesz studenta to kompilator będzie płakał. Ktoś to zresztą wyżej już napisał.

Jak nie rozwiążesz problemu odezwij się pomogę ale dużo tego jest i łatwiej by było jakbyś wydzielił kod który źle działa to bym może coś doradził. tak to nawet nie wiem co ugryźć.

0

Dziękuje za odpowiedzi,

Próbuję zrobić tak jak @overcq zaproponował, przynajmniej tak mi się wydaję.

Dodałem studentowi wskaźniki do funkcji odczytu i zapisu

struct MY_STUDENT
{
	char *lastname;
	int length;
	int birth_year;
	enum StudyDirection study_direction;

    void (*writeFunction)(void* data, FILE* file);
	void (*readFunction)(void* data, FILE* file);

}

Funkcje odczytu i zapisu studenta (zamiast MY_STUDENT_SaveToFile oraz MY_STUDENT_LoadFromFile)

void MY_STUDENT_Write(void* pData, FILE* pf)
{
	MY_STUDENT* student = (MY_STUDENT*)pData;
	fwrite(&student->length, sizeof(int), 1, pf);
	fwrite(student->lastname, sizeof(char), student->length, pf);
	fwrite(&student->birth_year, sizeof(int), 1, pf);
	fwrite(&student->study_direction, sizeof(enum StudyDirection), 1, pf);
}

void MY_STUDENT_Read(void* pData, FILE* pf)
{
	MY_STUDENT* student = (MY_STUDENT*)pData;
	fread(&student->length, sizeof(int), 1, pf);
	student->lastname = (char*)malloc((student->length + 1) * sizeof(char));
	fread(student->lastname, sizeof(char), student->length, pf);
	student->lastname[student->length] = '\0';
	fread(&student->birth_year, sizeof(int), 1, pf);
	fread(&student->study_direction, sizeof(enum StudyDirection), 1, pf);
}

I one są podczas inicjalizacji tego studenta dodawane do studenta

void* MY_STUDENT_Init(const char* llastname, int birthyear, enum StudyDirection studydirection)
{
	MY_STUDENT* pstudent = (MY_STUDENT*)malloc(sizeof(MY_STUDENT));
	if (!pstudent)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	if (pstudent)
	{
		pstudent->lastname = (char*)malloc((strlen(llastname) + 1) * sizeof(char));
		
		if (!pstudent->lastname)
			MessageToScreen(ERR_NUMB_ALLOC_MEM);

		if (pstudent->lastname)
		{
			strcpy(pstudent->lastname, llastname);
			pstudent->length = strlen(llastname);
			pstudent->lastname[strlen(llastname)] = '\0';
			pstudent->birth_year = birthyear;
			pstudent->study_direction = studydirection;

			pstudent->writeFunction = MY_STUDENT_Write; // TUTAJ
			pstudent->readFunction = MY_STUDENT_Read; // TUTAJ
		}
		else
		{
			free(pstudent);
			pstudent = NULL;
		}
	}
	return (void*)(pstudent);
}

Do stosu dodałem wskaźniki do tych funkcji zapisu i odczytu danych elementu (w tym przypadku studenta)

struct MY_STACK
{
	void *pData;
	MY_STACK *next;

	void (*writeFunction)(void* data, FILE* file);
	void (*readFunction)(void* data, FILE* file);
};

I jak sie tworzy stos to tez sa przypisywane te funkcje odczytu i zapisu danych (w tym przypadku studenta)

MY_STACK* MY_STACK_Push(void* pdat, void (*writeFunc)(void* data, FILE* file), void (*readFunc)(void* data, FILE* file))
{
	MY_STACK* current = (MY_STACK*)malloc(sizeof(MY_STACK));

	if (!current)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	current->next = NULL;
	

	
	if (!first)
		first = current;
	else
		current->next = first;
	
	first = current;
	current->pData = pdat;

	current->writeFunction = writeFunc; // TUTAJ
	current->readFunction = readFunc;  // TUTAJ

	return current;

}

I podczas zapisu korzystam z tych funkcji

void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	MY_STACK* p = first;

	while (p)
	{
		
		p->writeFunction(p->pData, pf);
		p = p->next;
	}

	fclose(pf);
}

Mam problem z odczytem teraz tych danych chciałbym użyć tej funkcji readFunction, ale jak tworzę ten newElement podczas to on nie wskazuje na ta funkcje readFunction do studenta on chyba nie wskazuje na żadną funkcje xD. I nie wiem czy oprócz tych danych studenta, nie powinienem zapisywać do pliku jeszcze tego calego elementu stosu z (czyli ten adres gdzie jest nastepny element i te funkcje writefunction oraz readfunction )?

void MY_STACK_LoadFromFile(const char* filename)
{
	FILE* pf = fopen(filename, "rb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
		return;
	}

	MY_STACK_Free();
	MessageToScreen(COM_NUMB_READ_FILE);

	while (1)
	{
		void* loadedData = NULL;

		if (fread(&loadedData, sizeof(void*), 1, pf) != 1)
			break;

		MY_STACK* newElement = (MY_STACK*)malloc(sizeof(MY_STACK));

		if (!newElement)
		{
			MessageToScreen(ERR_NUMB_ALLOC_MEM);
			break;
		}

		newElement->next = NULL;
		newElement->pData = loadedData;

		newElement->readFunction(newElement->pData, pf);

		

		if (!first)
		{
			first = newElement;
		}
		else
		{
			newElement->next = first;
			first = newElement;
		}
	}
	fclose(pf);
}
1
helloWorld123 napisał(a):

Dziękuje za odpowiedzi,

Próbuję zrobić tak jak @overcq zaproponował, przynajmniej tak mi się wydaję.

Dodałem studentowi wskaźniki do funkcji odczytu i zapisu

``

void* MY_STUDENT_Init(const char* llastname, int birthyear, enum StudyDirection studydirection)
{
	MY_STUDENT* pstudent = (MY_STUDENT*)malloc(sizeof(MY_STUDENT));

return (void*)(pstudent);
}

Wymyśliłeś jedną z częsci tego, co powyżej nazwałem "obiektowym C", metody wirtualne

ALE wad jest więcej niż plusów, np nieszczęsne void *, obsługa błędów, konstruktor (bo pora tam mówić o funkcji Init) może nie zwrócić obiektu

Po 10 latach takiej pracy wynajdziesz C++

0

To przecież jest projekt na zajęcia, bez sensu się czepiać o coś takiego, dostał takie i takie instrukcje, jak zrobi inaczej to mu nie zaliczy. — GodOfCode. 38 minut temu

A potem na grupie prowadzący mówi: A teraz ten sam temat w C++, szybciutko na zajeciach
... rozmarzyłem się

0

"zapisywać do pliku jeszcze tego calego elementu stosu z (czyli ten adres gdzie jest nastepny element i"

Tego Ci zrobić Kolego nie wolno.

0

Dobra coś skleiłem, kwestia jest taka, że zapisuję elementy do pliku i potem odczytuje, to wszystko jest w porządku dodają mi się na stos, ale nie moge użyć funkcji clear() oraz gdy odczytuje pliku dwa razy pod rząd wywala mi błąd
HEAP CORRUPTION DETECTED: after Normal block (#143) at 0x0000028C62A6C250.
CRT detected that the application wrote to memory after end of heap. Szukam tego problemu z alokowaniem pamieci i nie moge znalezc. No i co debuger mowi ze jak drugi raz odpalam funkcje MY_STACK_LoadFromFile() to leci do MY_STACK_Free() zeby wyczyscic stos
no i ten leci zeby zwolnic dane elementu stosu (*ptr_free_dat)(p->pData) i to powoduje ze idzie do studenciaka czyli tu MY_STUDENT_Free(), zwalnia mi lastname studenta i chce zwolnic pStudenta i student wylądował 143m. HEAP CORRUPTION DETECTED: after Normal block (#143) at 0x0000028C62A6C250. Ktoś ma jakieś sugestię to byłbym wdzięczny.

void MY_STUDENT_Free(void* ptr)
{
	MY_STUDENT* pStudent = (MY_STUDENT*)ptr;

	if (pStudent)
	{
		if (pStudent->lastname)
			free(pStudent->lastname);
		free(pStudent);
	}
}

void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	// Liczy ile elementow jest na stosie i zapisuje, zebym potem odczytal latwo plik.

	int count = 0;
	MY_STACK* p = first;
	while (p)
	{
		count++;
		p = p->next;
	}

    // tu zapisuje liczbe elementow stosu do pliku
	fwrite(&count, sizeof(int), 1, pf);

	p = first;

	while (p)
	{
		// zapisuje elementy stosu zeby byly oddzielone od danych uzywa tej funkcji writeFunction(tutaj bedzie uzyta MY_STUDENT_WRITE)
		p->writeFunction(p->pData, pf);
		p = p->next;
	}

	fclose(pf);
}

Zmieniłem funkcję odczytu

void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc)
{
	FILE* pf = fopen(filename, "rb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
		return;
	}

	MY_STACK_Free();

    // odczytuje ilosc elementow stosu z pliku
	int numElements;
	fread(&numElements, sizeof(int), 1, pf);

    for (int i = 0; i < numElements; i++)
	{
		MY_STACK* newElement = (MY_STACK*)malloc(sizeof(MY_STACK));

		if (!newElement)
		{
			MessageToScreen(ERR_NUMB_ALLOC_MEM);
			return;
		}

		newElement->next = NULL;
		newElement->pData = malloc(sizeof(void*));

		if (!newElement->pData)
		{
			free(newElement);
			MessageToScreen(ERR_NUMB_ALLOC_MEM);
			return;
		}

        // i tutaj mi odczytuje dane (w moich danych jest student i uzywa se tej funkcji my_student_read)
		readFunc(newElement->pData, pf);

		newElement->writeFunction = writeFunc;
		newElement->readFunction = readFunc;

		MY_STACK_Push(newElement->pData, writeFunc, readFunc);

	}

	fclose(pf);

}

Tutaj plik naglowkowy do funckji my_stack.c
#ifndef MY_STACK___H
#define MY_STACK___H

// Interfejs dla operacji zapisu
typedef void (*WriteFunction)(void* data, FILE* file);

// Interfejs dla operacji odczytu
typedef void (*ReadFunction)(void* data, FILE* file);

struct MY_STACK
{
	void *pData;
	MY_STACK *next;

	WriteFunction writeFunction;
	ReadFunction readFunction;

};


extern MY_STACK* first;
typedef void (*FreeData)(void* pdat);
typedef int (CompData)(void* pcurData, void *pSearchData);

void MY_STACK_Init(FreeData pFreeDat);
void MY_STACK_Free();


MY_STACK* MY_STACK_Push(void* pdat, WriteFunction writeFunc, ReadFunction readFunc);
MY_STACK MY_STACK_Pop();
void* MY_STACK_Search(void* pSearchDat, CompData ptr_comp_fun, int FirstEntry);
void MY_STACK_SaveToFile(const char* filename);

void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc);
void MY_STACK_LoadFromFile_Recursive(FILE* pf, WriteFunction writeFunc, ReadFunction readFunc, int numElements);

#endif

tutaj caly my_stack.c


#include <stdlib.h>
#include <stdio.h>
#include "my_stack.h"
#include "my_student.h"
#include "my_interface.h"
#include "string.h"
#include "error_handling.h"
#include <crtdbg.h>

#pragma warning (disable : 4996)

static FILE* pf = NULL;
static MY_STACK* first = NULL; 
FreeData ptr_free_dat;

void MY_STACK_Init(FreeData pFreeDat)
{
	first = NULL;
	ptr_free_dat = pFreeDat;
}

void MY_STACK_Free()
{
	MY_STACK *p = first, *ptmp = NULL;

	while (p)
	{
		(*ptr_free_dat)(p->pData);

		ptmp = p;

		p = p->next;

		free(ptmp);
	}

	first = NULL;

	MessageToScreen(COM_NUMB_FREE_ALL);

	_CrtDumpMemoryLeaks();
}

MY_STACK* MY_STACK_Push(void* pdat, WriteFunction writeFunc, ReadFunction readFunc)
{
	MY_STACK* current = (MY_STACK*)malloc(sizeof(MY_STACK));

	if (!current)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	current->next = NULL;
	

	
	if (!first)
		first = current;
	else
		current->next = first;
	
	first = current;
	current->pData = pdat;
	current->writeFunction = writeFunc;
	current->readFunction = readFunc;

	return current;

}

MY_STACK MY_STACK_Pop()
{
	MY_STACK rv;

	if (!first)
	{
		rv.pData = NULL;
		rv.next = NULL;
	}
	else
	{
		MY_STACK* next = first->next;
		rv.pData = first->pData;

		rv.next = NULL;

		free(first);

		first = next;
	}
	
	return rv;
}

void* MY_STACK_Search(void* pSearchDat, CompData ptr_comp_fun, int FirstEntry)
{
	static MY_STACK* p;
	MY_STACK* ptmp = NULL;
	
	if (FirstEntry)
		p = first;

	while (p)
	{
		if (!(*ptr_comp_fun)(p->pData, pSearchDat))
		{
			p = p->next;
		}
		else
		{
			ptmp = p;
			p = p->next;
			return ptmp->pData;
		}
	}

	return NULL;
}



void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	// Count the number of elements on stack
	int count = 0;
	MY_STACK* p = first;
	while (p)
	{
		count++;
		p = p->next;
	}

	fwrite(&count, sizeof(int), 1, pf);

	p = first;

	while (p)
	{
		
		p->writeFunction(p->pData, pf);
		p = p->next;
	}

	fclose(pf);
}

void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc)
{
	FILE* pf = fopen(filename, "rb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
		return;
	}


	int numElements;
	fread(&numElements, sizeof(int), 1, pf);

	for (int i = 0; i < numElements; i++)
	{
		MY_STACK* newElement = (MY_STACK*)malloc(sizeof(MY_STACK));

		if (!newElement)
		{
			MessageToScreen(ERR_NUMB_ALLOC_MEM);
			return;
		}

		newElement->next = NULL;
		newElement->pData = malloc(sizeof(void*));

		if (!newElement->pData)
		{
			free(newElement);
			MessageToScreen(ERR_NUMB_ALLOC_MEM);
			return;
		}

		readFunc(newElement->pData, pf);

		newElement->writeFunction = writeFunc;
		newElement->readFunction = readFunc;

		MY_STACK_Push(newElement->pData, writeFunc, readFunc);

		free(newElement);
	}

	fclose(pf);
}

Tu są te funkcje odczytu zapisu i studenta


void MY_STUDENT_Write(void* pData, FILE* pf)
{
	MY_STUDENT* student = (MY_STUDENT*)pData;
	fwrite(&student->length, sizeof(int), 1, pf);
	fwrite(student->lastname, sizeof(char), student->length, pf);
	fwrite(&student->birth_year, sizeof(int), 1, pf);
	fwrite(&student->study_direction, sizeof(enum StudyDirection), 1, pf);
}


void MY_STUDENT_Read(void* pData, FILE* pf)
{
	MY_STUDENT* student = (MY_STUDENT*)pData;

	if (fread(&student->length, sizeof(int), 1, pf) != 1) {
		return;
	}

	student->lastname = (char*)malloc((student->length + 1) * sizeof(char));

	if (!student->lastname) {
		MessageToScreen(COM_NUMB_ALLOC_MEM);
		return;
	}

	if (fread(student->lastname, sizeof(char), student->length, pf) != student->length) {
		free(student->lastname);
		return;
	}

	student->lastname[student->length] = '\0';

	if (fread(&student->birth_year, sizeof(int), 1, pf) != 1) {
		free(student->lastname);
		return;
	}

	if (fread(&student->study_direction, sizeof(enum StudyDirection), 1, pf) != 1) {
		free(student->lastname);
		return;
	}
}

tutaj plik nagłówkowy studenta

#ifndef MY_STUDENT_H
#define MY_STUDENT_H

enum StudyDirection {
	ELECTRICAL_ENGINEERING,
	MECHANICAL_ENGINEERING,
	COMPUTER_SCIENCE,
	TOTAL_STUDY_DIRECTIONS
};


struct MY_STUDENT
{
	char *lastname;
	int length;
	int birth_year;
	enum StudyDirection study_direction;

	void (*writeFunction)(void* data, FILE* file);
	void (*readFunction)(void* data, FILE* file);

};

void* MY_STUDENT_Init(const char* llastname, int birthyear, enum StudyDirection studydirection);
void MY_STUDENT_Free(void *ptr);
void* MY_STUDENT_Push(const char* llastname, int birthyear, enum StudyDirection studydirection);
void MY_STUDENT_Print(void* ptr);
int MY_STUDENT_SearchLastName(void* pCureData, void* pSearchStudent);
void MY_STUDENT_Write(void* pData, FILE* pf);
void MY_STUDENT_Read(void* pData, FILE* pf);

#endif

tutaj cały plik my_student.c

#include <stdio.h>
#include <stdlib.h>
#include "my_student.h"
#include "my_interface.h"
#include "string.h"
#include "my_stack.h"
#include "error_handling.h"

#pragma warning (disable : 4996)


void* MY_STUDENT_Init(const char* llastname, int birthyear, enum StudyDirection studydirection)
{
	MY_STUDENT* pstudent = (MY_STUDENT*)malloc(sizeof(MY_STUDENT));
	if (!pstudent)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	if (pstudent)
	{
		pstudent->lastname = (char*)malloc((strlen(llastname) + 1) * sizeof(char));
		
		if (!pstudent->lastname)
			MessageToScreen(ERR_NUMB_ALLOC_MEM);

		if (pstudent->lastname)
		{
			strcpy(pstudent->lastname, llastname);
			pstudent->length = strlen(llastname);
			pstudent->lastname[strlen(llastname)] = '\0';
			pstudent->birth_year = birthyear;
			pstudent->study_direction = studydirection;

			pstudent->writeFunction = MY_STUDENT_Write;
			pstudent->readFunction = MY_STUDENT_Read;
		}
		else
		{
			free(pstudent);
			pstudent = NULL;
		}
	}
	return (void*)(pstudent);
}

void MY_STUDENT_Free(void* ptr)
{
	MY_STUDENT* pStudent = (MY_STUDENT*)ptr;

	if (pStudent)
	{
		if (pStudent->lastname)
			free(pStudent->lastname);
		free(pStudent);
	}
}

void* MY_STUDENT_Push(const char* llastname, int birthyear, enum StudyDirection studydirection)
{
	return MY_STUDENT_Init(llastname, birthyear, studydirection);
}


void MY_STUDENT_Print(void* ptr)
{
	MY_STUDENT* p = (MY_STUDENT*)ptr;
	if (p)
	{
		printf("Nazwisko     : %s\n", p->lastname);
		printf("Rok urodzenia: %d\n", p->birth_year);
		printf("Kierunek     : %d\n", p->study_direction);
	}
}

int MY_STUDENT_SearchLastName(void* pCurData, void* pSearchStudent)
{
	MY_STUDENT* pcur = (MY_STUDENT*)pCurData;
	MY_STUDENT* psearch = (MY_STUDENT*)pSearchStudent;

	if (strcmp(pcur->lastname, psearch->lastname) == 0)
		return 1;

	return 0;
}

void MY_STUDENT_Write(void* pData, FILE* pf)
{
	MY_STUDENT* student = (MY_STUDENT*)pData;
	fwrite(&student->length, sizeof(int), 1, pf);
	fwrite(student->lastname, sizeof(char), student->length, pf);
	fwrite(&student->birth_year, sizeof(int), 1, pf);
	fwrite(&student->study_direction, sizeof(enum StudyDirection), 1, pf);
}


void MY_STUDENT_Read(void* pData, FILE* pf)
{
	MY_STUDENT* student = (MY_STUDENT*)pData;

	if (fread(&student->length, sizeof(int), 1, pf) != 1) {
		return;
	}

	student->lastname = (char*)malloc((student->length + 1) * sizeof(char));

	if (!student->lastname) {
		MessageToScreen(COM_NUMB_ALLOC_MEM);
		return;
	}

	if (fread(student->lastname, sizeof(char), student->length, pf) != student->length) {
		free(student->lastname);
		return;
	}

	student->lastname[student->length] = '\0';

	if (fread(&student->birth_year, sizeof(int), 1, pf) != 1) {
		free(student->lastname);
		return;
	}

	if (fread(&student->study_direction, sizeof(enum StudyDirection), 1, pf) != 1) {
		free(student->lastname);
		return;
	}
}

no i tak to jest wywolane

void save_stack_to_disk()
{
	char filename[128];
	printf("input filename\n");
	scanf_s("%s", filename, (unsigned int)sizeof(filename));
	MY_STACK_SaveToFile(filename);
}

void load_stack_from_disk()
{
	char filename[128];
	printf("input filename\n");
	scanf_s("%s", filename, (unsigned int)sizeof(filename));
	MY_STACK_LoadFromFile(filename, MY_STUDENT_Write, MY_STUDENT_Read);
}

void clear()
{
	MY_STACK_Free();
}

0
helloWorld123 napisał(a):
void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc)
{
// …
		newElement->pData = malloc(sizeof(void*));

		if (!newElement->pData)
		{
			free(newElement);
			MessageToScreen(ERR_NUMB_ALLOC_MEM);
			return;
		}

        // i tutaj mi odczytuje dane (w moich danych jest student i uzywa se tej funkcji my_student_read)
		readFunc(newElement->pData, pf);
// …
}

Przecież alokujesz pamięć dla studenta o rozmiarze wskaźnika w powyższej funkcji. Nie przeniosłeś do MY_STUDENT_Read.
Wtedy trzeba będzie zmienić deklarację funkcji MY_STUDENT_Read tak, by otrzymywała wskaźnik do wskaźnika, czyli adres pData, gdzie funkcja MY_STUDENT_Read umieści adres nowo alokowanego bloku pamięci dla studenta.

void MY_STUDENT_Read(void** ppData, FILE* pf);
void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc)
{
// …
        // i tutaj mi odczytuje dane (w moich danych jest student i uzywa se tej funkcji my_student_read)
		readFunc(&newElement->pData, pf);
// …
}

Poza tym włączanie nagłówków “my_stack.h” i “my_student.h” krzyżowo w “my_stack.c” i “my_student.c” jest niepotrzebne.
I wskaźniki do funkcji ‘read’/‘write’ są wspólne dla całego stosu, nie trzeba ich przechowywać w każdym elemencie.

0

Dobra wysłałem i dowiedziałem się, że ( obiekty struktury powinni byc zapisywane jak caly obiekt, a nie skladowa-po-skladowej) powinien być zapisany zamiast:

void MY_STUDENT_Write(void* pData, FILE* pf)
{
	// obiekty struktury powinni byc zapisywane jak caly obiekt, a nie skladowa-po-skladowej
	MY_STUDENT* student = (MY_STUDENT*)pData;
	fwrite(&student->length, sizeof(int), 1, pf);
	fwrite(student->lastname, sizeof(char), student->length, pf);
	fwrite(&student->birth_year, sizeof(int), 1, pf);
	fwrite(&student->study_direction, sizeof(enum StudyDirection), 1, pf);
}

to tak chyba tak ma być poprawiłem.

void MY_STUDENT_Write(void* pData, FILE* pf)
{
	// obiekty struktury powinni byc zapisywane jak caly obiekt, a nie skladowa-po-skladowej
	MY_STUDENT* student = (MY_STUDENT*)pData;
	fwrite(student, sizeof(MY_STUDENT), 1, pf);
}

void MY_STUDENT_Read(void** ppData, FILE* pf)
{

	MY_STUDENT* student = (MY_STUDENT*)malloc(sizeof(MY_STUDENT));

	if (!student)
	{
		MessageToScreen(ERR_NUMB_ALLOC_MEM);
		*ppData = NULL;
		return;
	}

	student->lastname = (char*)malloc((student->length + 1) * sizeof(char));
	fread(student, sizeof(MY_STUDENT), 1, pf);
	
	if (!student->lastname)
	{
		MessageToScreen(ERR_NUMB_ALLOC_MEM);
		free(student);
		*ppData = NULL;
		return;
	}

	*ppData = student;
}

I mam pytanie czy jak zapisze tak do pliku jak powyżej takiego studenta:

struct MY_STUDENT
{
	char *lastname;
	int length;
	int birth_year;
	enum StudyDirection study_direction;
};
void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	// Count the number of elements on stack
	int count = 0;
	MY_STACK* p = first;
	while (p)
	{
		count++;
		p = p->next;
	}

	fwrite(&count, sizeof(int), 1, pf);

	p = first;

	while (p)
	{
		
		p->writeFunction(p->pData, pf);
		p = p->next;
	}

	fclose(pf);
}

void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc)
{
	FILE* pf = fopen(filename, "rb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
		return;
	}

	MY_STACK_Free();

	int numElements;
	fread(&numElements, sizeof(int), 1, pf);

	MY_STACK_LoadFromFile_Recursive(pf, writeFunc, readFunc, numElements);

	fclose(pf);
}

void MY_STACK_LoadFromFile_Recursive(FILE* pf, WriteFunction writeFunc, ReadFunction readFunc, int numElements)
{
	if (numElements <= 0) {
		return; 
	}

	MY_STACK* newElement = (MY_STACK*)malloc(sizeof(MY_STACK));

	if (!newElement)
	{
		MessageToScreen(ERR_NUMB_ALLOC_MEM);
		return;
	}

	newElement->next = NULL;
	newElement->pData = malloc(sizeof(void *));

	readFunc(&newElement->pData, pf);

	newElement->writeFunction = writeFunc;
	newElement->readFunction = readFunc;

	MY_STACK_LoadFromFile_Recursive(pf, writeFunc, readFunc, numElements - 1);
	MY_STACK_Push(newElement->pData, writeFunc, readFunc);
}

to jeśli lastname jest dynamicznie alokowany to będę mógł odczytać lastname czy nie, ponieważ próbuje odczytać takie studencika z pliku i length, birth_years, oraz study_direction odczytuje, natomiast z lastname mam problem.

I mam pytanie jeszcze bo usunalem wczesniej z strukury (studenta zapis i odczyt) tak jak @overcq sugerował, zostawiłem tylko w strukturze stos i dostałem komunikat, że "Dla czego wskazniki do funkcji typu WriteFunction, ReadFunction dokladaasz do struktury MY_STACK,
//a FreeData i CompData - nie?". Czy chodzi o to aby kod był spójny, czy o coś innego?
miałem tak:

#ifndef MY_STACK___H
#define MY_STACK___H

// Interfejs dla operacji zapisu
typedef void (*WriteFunction)(void* data, FILE* file);

// Interfejs dla operacji odczytu
typedef void (*ReadFunction)(void** data, FILE* file);

struct MY_STACK
{
	void *pData;
	MY_STACK *next;

	WriteFunction writeFunction;
	ReadFunction readFunction;   

};

// Dla czego wskazniki do funkcji typu WriteFunction, WriteFunction Pan doklada do struktury MY_STACK, 
//a FreeData i CompData - nie?


typedef void (*FreeData)(void* pdat);
typedef int (CompData)(void* pcurData, void *pSearchData);

#endif

i zmieniłem na tak:

#ifndef MY_STACK___H
#define MY_STACK___H

// Interfejs dla operacji zapisu
typedef void (*WriteFunction)(void* data, FILE* file);

// Interfejs dla operacji odczytu
typedef void (*ReadFunction)(void** data, FILE* file);

typedef void (*FreeData)(void* pdat);

typedef int (CompData)(void* pcurData, void* pSearchData);

struct MY_STACK
{
	void *pData;
	MY_STACK *next;

	WriteFunction writeFunction;
	ReadFunction readFunction;  
	FreeData freeData;   
    CompData compData;   
};


#endif

Z innych rzeczy dodałem rekurencje, żeby tylko przywrócić stos taki jaki był przed zapisaniem do pliku:

Moje pliki:

my_stack.h

#ifndef MY_STACK___H
#define MY_STACK___H

// Interfejs dla operacji zapisu
typedef void (*WriteFunction)(void* data, FILE* file);

// Interfejs dla operacji odczytu
typedef void (*ReadFunction)(void** data, FILE* file);

typedef void (*FreeData)(void* pdat);

typedef int (CompData)(void* pcurData, void* pSearchData);

struct MY_STACK
{
	void *pData;
	MY_STACK *next;

	WriteFunction writeFunction;
	ReadFunction readFunction;   
	FreeData freeData;   
    CompData compData;   
};

extern MY_STACK* first;


void MY_STACK_Init(FreeData pFreeDat);
void MY_STACK_Free();


MY_STACK* MY_STACK_Push(void* pdat, WriteFunction writeFunc, ReadFunction readFunc);
MY_STACK MY_STACK_Pop();

void* MY_STACK_Search(void* pSearchDat, CompData ptr_comp_fun, int FirstEntry);

void MY_STACK_SaveToFile(const char* filename);
void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc);
void MY_STACK_LoadFromFile_Recursive(FILE* pf, WriteFunction writeFunc, ReadFunction readFunc, int numElements);

#endif

my_stack.c

#include <stdlib.h>
#include <stdio.h>
#include "my_stack.h"
#include "my_student.h"
#include "my_interface.h"
#include "string.h"
#include "error_handling.h"

#pragma warning (disable : 4996)

static FILE* pf = NULL;
static MY_STACK* first = NULL; 
FreeData ptr_free_dat;

void MY_STACK_Init(FreeData pFreeDat)
{
	first = NULL;
	ptr_free_dat = pFreeDat;
}

void MY_STACK_Free()
{
	MY_STACK *p = first, *ptmp = NULL;

	while (p)
	{
		(*ptr_free_dat)(p->pData);

		ptmp = p;

		p = p->next;

		free(ptmp);
	}

	first = NULL;

	MessageToScreen(COM_NUMB_FREE_ALL);

}

MY_STACK* MY_STACK_Push(void* pdat, WriteFunction writeFunc, ReadFunction readFunc)
{
	MY_STACK* current = (MY_STACK*)malloc(sizeof(MY_STACK));

	if (!current)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	current->next = NULL;
		
	if (!first)
		first = current;
	else
		current->next = first;
	
	first = current;
	current->pData = pdat;
	current->writeFunction = writeFunc;
	current->readFunction = readFunc;

	return current;

}

MY_STACK MY_STACK_Pop()
{
	MY_STACK rv;

	if (!first)
	{
		rv.pData = NULL;
		rv.next = NULL;
	}
	else
	{
		MY_STACK* next = first->next;
		rv.pData = first->pData;

		rv.next = NULL;

		free(first);

		first = next;
	}
	
	return rv;
}

void* MY_STACK_Search(void* pSearchDat, CompData ptr_comp_fun, int FirstEntry)
{
	static MY_STACK* p;
	MY_STACK* ptmp = NULL;
	
	if (FirstEntry)
		p = first;

	while (p)
	{
		if (!(*ptr_comp_fun)(p->pData, pSearchDat))
		{
			p = p->next;
		}
		else
		{
			ptmp = p;
			p = p->next;
			return ptmp->pData;
		}
	}

	return NULL;
}



void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	// Count the number of elements on stack
	int count = 0;
	MY_STACK* p = first;
	while (p)
	{
		count++;
		p = p->next;
	}

	fwrite(&count, sizeof(int), 1, pf);

	p = first;

	while (p)
	{
		
		p->writeFunction(p->pData, pf);
		p = p->next;
	}

	fclose(pf);
}

void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc)
{
	FILE* pf = fopen(filename, "rb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
		return;
	}

	MY_STACK_Free();

	int numElements;
	fread(&numElements, sizeof(int), 1, pf);

	MY_STACK_LoadFromFile_Recursive(pf, writeFunc, readFunc, numElements);

	fclose(pf);
}

void MY_STACK_LoadFromFile_Recursive(FILE* pf, WriteFunction writeFunc, ReadFunction readFunc, int numElements)
{
	if (numElements <= 0) {
		return; 
	}

	MY_STACK* newElement = (MY_STACK*)malloc(sizeof(MY_STACK));

	if (!newElement)
	{
		MessageToScreen(ERR_NUMB_ALLOC_MEM);
		return;
	}

	newElement->next = NULL;
	newElement->pData = NULL;

	readFunc(&newElement->pData, pf);

	newElement->writeFunction = writeFunc;
	newElement->readFunction = readFunc;

	MY_STACK_LoadFromFile_Recursive(pf, writeFunc, readFunc, numElements - 1);
	MY_STACK_Push(newElement->pData, writeFunc, readFunc);
}



my_student.h

#ifndef MY_STUDENT_H
#define MY_STUDENT_H

enum StudyDirection {
	ELECTRICAL_ENGINEERING,
	MECHANICAL_ENGINEERING,
	COMPUTER_SCIENCE,
	TOTAL_STUDY_DIRECTIONS
};


struct MY_STUDENT
{
	char *lastname;
	int length;
	int birth_year;
	enum StudyDirection study_direction;
};

void* MY_STUDENT_Init(const char* llastname, int birthyear, enum StudyDirection studydirection);
void MY_STUDENT_Free(void *ptr);
void* MY_STUDENT_Push(const char* llastname, int birthyear, enum StudyDirection studydirection);
void MY_STUDENT_Print(void* ptr);
int MY_STUDENT_SearchLastName(void* pCureData, void* pSearchStudent);
void MY_STUDENT_Write(void* pData, FILE* pf);
void MY_STUDENT_Read(void** pData, FILE* pf);

#endif


my_student.c

#include <stdio.h>
#include <stdlib.h>
#include "my_student.h"
#include "my_interface.h"
#include "string.h"
#include "my_stack.h"
#include "error_handling.h"

#pragma warning (disable : 4996)


void* MY_STUDENT_Init(const char* llastname, int birthyear, enum StudyDirection studydirection)
{
	MY_STUDENT* pstudent = (MY_STUDENT*)malloc(sizeof(MY_STUDENT));
	if (!pstudent)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	if (pstudent)
	{
		pstudent->lastname = (char*)malloc((strlen(llastname) + 1) * sizeof(char));
		
		if (!pstudent->lastname)
			MessageToScreen(ERR_NUMB_ALLOC_MEM);

		if (pstudent->lastname)
		{
			strcpy(pstudent->lastname, llastname);
			pstudent->length = strlen(llastname);
			pstudent->lastname[strlen(llastname)] = '\0';
			pstudent->birth_year = birthyear;
			pstudent->study_direction = studydirection;

		}
		else
		{
			free(pstudent);
			pstudent = NULL;
		}
	}
	return (void*)(pstudent);
}

void MY_STUDENT_Free(void* ptr)
{
	MY_STUDENT* pStudent = (MY_STUDENT*)ptr;

	if (pStudent)
	{
		if (pStudent->lastname)
			free(pStudent->lastname);
		free(pStudent);
	}
}

void* MY_STUDENT_Push(const char* llastname, int birthyear, enum StudyDirection studydirection)
{
	return MY_STUDENT_Init(llastname, birthyear, studydirection);
}


void MY_STUDENT_Print(void* ptr)
{
	MY_STUDENT* p = (MY_STUDENT*)ptr;

	if (p)
	{
		printf("Nazwisko     : %s\n", p->lastname);
		printf("Rok urodzenia: %d\n", p->birth_year);
		printf("Kierunek     : %s\n", studytab[p->study_direction]);
	}
}

int MY_STUDENT_SearchLastName(void* pCurData, void* pSearchStudent)
{
	MY_STUDENT* pcur = (MY_STUDENT*)pCurData;
	MY_STUDENT* psearch = (MY_STUDENT*)pSearchStudent;

	if (strcmp(pcur->lastname, psearch->lastname) == 0)
		return 1;

	return 0;
}

void MY_STUDENT_Write(void* pData, FILE* pf)
{
	//SF obiekty struktury powinni byc zapisywane jak caly obiekt, a nie skladowa-po-skladowej
	MY_STUDENT* student = (MY_STUDENT*)pData;
	fwrite(student, sizeof(MY_STUDENT), 1, pf);
}

void MY_STUDENT_Read(void** ppData, FILE* pf)
{

	MY_STUDENT* student = (MY_STUDENT*)malloc(sizeof(MY_STUDENT));

	if (!student)
	{
		MessageToScreen(ERR_NUMB_ALLOC_MEM);
		*ppData = NULL;
		return;
	}

	student->lastname = (char*)malloc((student->length + 1) * sizeof(char));
	fread(student, sizeof(MY_STUDENT), 1, pf);
	
	if (!student->lastname)
	{
		MessageToScreen(ERR_NUMB_ALLOC_MEM);
		free(student);
		*ppData = NULL;
		return;
	}

	*ppData = student;
}


no i tak to jest wywolane

void save_stack_to_disk()
{
	char filename[128];
	printf("input filename\n");
	scanf_s("%s", filename, (unsigned int)sizeof(filename));
	MY_STACK_SaveToFile(filename);
}

void load_stack_from_disk()
{
	char filename[128];
	printf("input filename\n");
	scanf_s("%s", filename, (unsigned int)sizeof(filename));
	MY_STACK_LoadFromFile(filename, MY_STUDENT_Write, MY_STUDENT_Read);
}

void clear()
{
	MY_STACK_Free();
}
2
helloWorld123 napisał(a):

Dobra wysłałem i dowiedziałem się, że ( obiekty struktury powinni byc zapisywane jak caly obiekt, a nie skladowa-po-skladowej) powinien być zapisany zamiast:

Tak / nie / zależy

Szkoda, że sprawiałeś do tej pory wrażenie pracującego może nie idealnie, ale rozsądnie i samodzielnie.
Teraz wg pogłosek z netu, których więcej jest głupich ...

Tak: siłowy zapis struktury jest (na jakimś poziomie) łatwiejszy. Zapisuje się dane, ale z gory zaprojektowane, aby były przeznaczone na dysk (daleka analogia: jak w programowaniu obiektowym koncepcja DTA Data Transfer Object)
Nie: nie ma łatwej ścieżki rozwojowej, np struktura jest uzupełniania po czasie. Dane już zapisane na dyskach stają się bezużyteczne
Nie: zmiana platformy Intel / egzotyczne procesory, inna kolejność bajtów
WIELKIE NIE: struktura zawiera wskaźniki (a zawiera). Myślozbrodnia. Nie można sobie bardziej strzelić w stopę

0

Dobra, nie wiem jak inaczej mógłbym to zapisać, żeby struktury były zapisane jako cały obiekt więc użyłem memcpy. Z pliku odczytuje mi normlanie length, lastname, birth_year tylko z study_direction ma problem, sprawdzałem i jako study_direction ma zapisac wartosc 0, 1, 2 (zalezy od kierunku) tylko podczasz odczytu mam problem i odczytuje mi -50331647, wydaje mi się, że wszystko dobrze zapisałem tylko problem jest z tym odczytem. Jeśli ktoś ma sugestię byłbym wdzięczny

void MY_STUDENT_Write(void* pData, char** pBuffer, size_t* bufferSize, FILE* pf)
{
	// obiekty struktury powinni byc zapisywane jak caly obiekt, a nie skladowa-po-skladowej
	MY_STUDENT* student = (MY_STUDENT*)pData;

	*bufferSize = sizeof(int) + student->length + sizeof(int) + sizeof(enum StudyDirection);
	*pBuffer = (char*)malloc(*bufferSize + 1); // Dodatkowy bajt na znak null

	if (*pBuffer)
	{
		char* ptr = *pBuffer;

		memcpy(ptr, &student->length, sizeof(int));
		ptr += sizeof(int);

		// Zapisz lastname
		memcpy(ptr, student->lastname, student->length);
		ptr += student->length;

		ptr++;

		memcpy(ptr, &student->birth_year, sizeof(int));
		ptr += sizeof(int);


		memcpy(ptr, &student->study_direction, sizeof(enum StudyDirection));
		ptr += sizeof(enum StudyDirection);
	}
}
void MY_STUDENT_Read(void** ppData, char* buffer, size_t bufferSize, FILE* pf)
{
	char* ptr = buffer;
	MY_STUDENT* student = (MY_STUDENT*)malloc(sizeof(MY_STUDENT));

	if (student)
	{
		memcpy(&student->length, ptr, sizeof(int));
		ptr += sizeof(int);

		student->lastname = (char*)malloc(student->length + 1); 
		if (student->lastname)
		{
			memcpy(student->lastname, ptr, student->length);
			student->lastname[student->length] = '\0'; 

			ptr += student->length + 1; // 

			memcpy(&student->birth_year, ptr, sizeof(int));
			ptr += sizeof(int);

			
			memcpy(&student->study_direction, ptr, sizeof(enum StudyDirection));
			ptr += sizeof(enum StudyDirection);

			*ppData = student;
		}
	}
	
}
void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	// Count the number of elements on stack
	int count = 0;
	MY_STACK* p = first;
	while (p)
	{
		count++;
		p = p->next;
	}

	fwrite(&count, sizeof(int), 1, pf);

	p = first;

	while (p)
	{
		char* buffer;
		size_t bufferSize;
		p->writeFunction(p->pData, &buffer, &bufferSize, pf);

		fwrite(&bufferSize, sizeof(size_t), 1, pf); // Zapisz rozmiar bufora
		fwrite(buffer, sizeof(char), bufferSize, pf); // Zapisz zawartość bufora

		free(buffer);

		p = p->next;
	}

	fclose(pf);
}

void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc)
{
	FILE* pf = fopen(filename, "rb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
		return;
	}

	MY_STACK_Free();

	int numElements;
	fread(&numElements, sizeof(int), 1, pf);

	MY_STACK_LoadFromFile_Recursive(pf, writeFunc, readFunc, numElements);

	fclose(pf);
}

void MY_STACK_LoadFromFile_Recursive(FILE* pf, WriteFunction writeFunc, ReadFunction readFunc, int numElements)
{
	if (numElements <= 0) {
		return; 
	}

	MY_STACK* newElement = (MY_STACK*)malloc(sizeof(MY_STACK));

	if (!newElement)
	{
		MessageToScreen(ERR_NUMB_ALLOC_MEM);
		return;
	}

	newElement->next = NULL;
	newElement->pData = NULL;

	size_t bufferSize;
	fread(&bufferSize, sizeof(size_t), 1, pf); // Odczytaj rozmiar bufora

	char* buffer = (char*)malloc(bufferSize);
	fread(buffer, sizeof(char), bufferSize, pf); // Odczytaj zawartość bufora

	readFunc(&newElement->pData, buffer, bufferSize, pf); // Odczytaj dane z bufora

	free(buffer);

	newElement->writeFunction = writeFunc;
	newElement->readFunction = readFunc;

	MY_STACK_LoadFromFile_Recursive(pf, writeFunc, readFunc, numElements - 1);
	MY_STACK_Push(newElement->pData, writeFunc, readFunc);
}

Pliki:


my_stack.h
#ifndef MY_STACK___H
#define MY_STACK___H

//typedef void (*WriteFunction)(void* data, FILE* file);
typedef void (*WriteFunction)(void* data, char** pBuffer, size_t* bufferSizeFILE, FILE* file);
typedef void (*ReadFunction)(void** data, char* buffer, size_t bufferSize, FILE* file);


typedef void (*FreeData)(void* pdat);
typedef int (CompData)(void* pcurData, void* pSearchData);

struct MY_STACK
{
	void *pData;
	MY_STACK *next;

	WriteFunction writeFunction;
	ReadFunction readFunction;   
	FreeData freeData;
	CompData compData;
};



extern MY_STACK* first;


void MY_STACK_Init(FreeData pFreeDat);
void MY_STACK_Free();


MY_STACK* MY_STACK_Push(void* pdat, WriteFunction writeFunc, ReadFunction readFunc);
MY_STACK MY_STACK_Pop();
void* MY_STACK_Search(void* pSearchDat, CompData ptr_comp_fun, int FirstEntry);
void MY_STACK_SaveToFile(const char* filename);

void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc);
void MY_STACK_LoadFromFile_Recursive(FILE* pf, WriteFunction writeFunc, ReadFunction readFunc, int numElements);

#endif

my_stack.c
#include <stdlib.h>
#include <stdio.h>
#include "my_stack.h"
#include "my_student.h"
#include "my_interface.h"
#include "string.h"
#include "error_handling.h"

#pragma warning (disable : 4996)

static MY_STACK* first = NULL; 
FreeData ptr_free_dat;

void MY_STACK_Init(FreeData pFreeDat)
{
	first = NULL;
	ptr_free_dat = pFreeDat;
}

void MY_STACK_Free()
{
	MY_STACK *p = first, *ptmp = NULL;

	while (p)
	{
		(*ptr_free_dat)(p->pData);

		ptmp = p;

		p = p->next;

		free(ptmp);
	}

	first = NULL;

	MessageToScreen(COM_NUMB_FREE_ALL);

}

MY_STACK* MY_STACK_Push(void* pdat, WriteFunction writeFunc, ReadFunction readFunc)
{
	MY_STACK* current = (MY_STACK*)malloc(sizeof(MY_STACK));

	if (!current)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	current->next = NULL;
		
	if (!first)
		first = current;
	else
		current->next = first;
	
	first = current;
	current->pData = pdat;
	current->writeFunction = writeFunc;
	current->readFunction = readFunc;

	return current;

}

MY_STACK MY_STACK_Pop()
{
	MY_STACK rv;

	if (!first)
	{
		rv.pData = NULL;
		rv.next = NULL;
	}
	else
	{
		MY_STACK* next = first->next;
		rv.pData = first->pData;

		rv.next = NULL;

		free(first);

		first = next;
	}
	
	return rv;
}

void* MY_STACK_Search(void* pSearchDat, CompData ptr_comp_fun, int FirstEntry)
{
	static MY_STACK* p;
	MY_STACK* ptmp = NULL;
	
	if (FirstEntry)
		p = first;

	while (p)
	{
		if (!(*ptr_comp_fun)(p->pData, pSearchDat))
		{
			p = p->next;
		}
		else
		{
			ptmp = p;
			p = p->next;
			return ptmp->pData;
		}
	}

	return NULL;
}



void MY_STACK_SaveToFile(const char *filename)
{
	FILE* pf = fopen(filename, "wb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
	}

	// Count the number of elements on stack
	int count = 0;
	MY_STACK* p = first;
	while (p)
	{
		count++;
		p = p->next;
	}

	fwrite(&count, sizeof(int), 1, pf);

	p = first;

	while (p)
	{
		char* buffer;
		size_t bufferSize;
		p->writeFunction(p->pData, &buffer, &bufferSize, pf);

		fwrite(&bufferSize, sizeof(size_t), 1, pf); // Zapisz rozmiar bufora
		fwrite(buffer, sizeof(char), bufferSize, pf); // Zapisz zawartość bufora

		free(buffer);

		p = p->next;
	}

	fclose(pf);
}

void MY_STACK_LoadFromFile(const char* filename, WriteFunction writeFunc, ReadFunction readFunc)
{
	FILE* pf = fopen(filename, "rb");
	if (!pf)
	{
		MessageToScreen(ERR_NUMB_OPEN_FILE);
		return;
	}

	MY_STACK_Free();

	int numElements;
	fread(&numElements, sizeof(int), 1, pf);

	MY_STACK_LoadFromFile_Recursive(pf, writeFunc, readFunc, numElements);

	fclose(pf);
}

void MY_STACK_LoadFromFile_Recursive(FILE* pf, WriteFunction writeFunc, ReadFunction readFunc, int numElements)
{
	if (numElements <= 0) {
		return; 
	}

	MY_STACK* newElement = (MY_STACK*)malloc(sizeof(MY_STACK));

	if (!newElement)
	{
		MessageToScreen(ERR_NUMB_ALLOC_MEM);
		return;
	}

	newElement->next = NULL;
	newElement->pData = NULL;

	size_t bufferSize;
	fread(&bufferSize, sizeof(size_t), 1, pf); // Odczytaj rozmiar bufora

	char* buffer = (char*)malloc(bufferSize);
	fread(buffer, sizeof(char), bufferSize, pf); // Odczytaj zawartość bufora

	readFunc(&newElement->pData, buffer, bufferSize, pf); // Odczytaj dane z bufora

	free(buffer);

	newElement->writeFunction = writeFunc;
	newElement->readFunction = readFunc;

	MY_STACK_LoadFromFile_Recursive(pf, writeFunc, readFunc, numElements - 1);
	MY_STACK_Push(newElement->pData, writeFunc, readFunc);
}
my_student.c

#include <stdio.h>
#include <stdlib.h>
#include "my_student.h"
#include "my_interface.h"
#include "string.h"
#include "my_stack.h"
#include "error_handling.h"

#pragma warning (disable : 4996)


void* MY_STUDENT_Init(const char* llastname, int birthyear, enum StudyDirection studydirection)
{
	MY_STUDENT* pstudent = (MY_STUDENT*)malloc(sizeof(MY_STUDENT));
	if (!pstudent)
		MessageToScreen(ERR_NUMB_ALLOC_MEM);

	if (pstudent)
	{
		pstudent->lastname = (char*)malloc((strlen(llastname) + 1) * sizeof(char));
		
		if (!pstudent->lastname)
			MessageToScreen(ERR_NUMB_ALLOC_MEM);

		if (pstudent->lastname)
		{
			strcpy(pstudent->lastname, llastname);
			pstudent->length = strlen(llastname);
			pstudent->lastname[strlen(llastname)] = '\0';
			pstudent->birth_year = birthyear;
			pstudent->study_direction = studydirection;

		}
		else
		{
			free(pstudent);
			pstudent = NULL;
		}
	}
	return (void*)(pstudent);
}

void MY_STUDENT_Free(void* ptr)
{
	MY_STUDENT* pStudent = (MY_STUDENT*)ptr;

	if (pStudent)
	{
		if (pStudent->lastname)
			free(pStudent->lastname);
		free(pStudent);
	}
}

void* MY_STUDENT_Push(const char* llastname, int birthyear, enum StudyDirection studydirection)
{
	return MY_STUDENT_Init(llastname, birthyear, studydirection);
}


void MY_STUDENT_Print(void* ptr)
{
	MY_STUDENT* p = (MY_STUDENT*)ptr;

	if (p)
	{
		printf("Nazwisko     : %s\n", p->lastname);
		printf("Rok urodzenia: %d\n", p->birth_year);
		printf("Kierunek     : %s\n", studytab[p->study_direction]);
	}
}

int MY_STUDENT_SearchLastName(void* pCurData, void* pSearchStudent)
{
	MY_STUDENT* pcur = (MY_STUDENT*)pCurData;
	MY_STUDENT* psearch = (MY_STUDENT*)pSearchStudent;

	if (strcmp(pcur->lastname, psearch->lastname) == 0)
		return 1;

	return 0;
}

void MY_STUDENT_Write(void* pData, char** pBuffer, size_t* bufferSize, FILE* pf)
{
	// obiekty struktury powinni byc zapisywane jak caly obiekt, a nie skladowa-po-skladowej
	MY_STUDENT* student = (MY_STUDENT*)pData;

	*bufferSize = sizeof(int) + student->length + sizeof(int) + sizeof(enum StudyDirection);
	*pBuffer = (char*)malloc(*bufferSize + 1); // Dodatkowy bajt na znak null

	if (*pBuffer)
	{
		char* ptr = *pBuffer;

		memcpy(ptr, &student->length, sizeof(int));
		ptr += sizeof(int);

		// Zapisz lastname
		memcpy(ptr, student->lastname, student->length);
		ptr += student->length;

		ptr++;

		memcpy(ptr, &student->birth_year, sizeof(int));
		ptr += sizeof(int);


		memcpy(ptr, &student->study_direction, sizeof(enum StudyDirection));
		ptr += sizeof(enum StudyDirection);
	}
}

void MY_STUDENT_Read(void** ppData, char* buffer, size_t bufferSize, FILE* pf)
{
	char* ptr = buffer;
	MY_STUDENT* student = (MY_STUDENT*)malloc(sizeof(MY_STUDENT));

	if (student)
	{
		memcpy(&student->length, ptr, sizeof(int));
		ptr += sizeof(int);

		student->lastname = (char*)malloc(student->length + 1); 
		if (student->lastname)
		{
			memcpy(student->lastname, ptr, student->length);
			student->lastname[student->length] = '\0'; 

			ptr += student->length + 1; // 

			memcpy(&student->birth_year, ptr, sizeof(int));
			ptr += sizeof(int);

			
			memcpy(&student->study_direction, ptr, sizeof(enum StudyDirection));
			ptr += sizeof(enum StudyDirection);

			*ppData = student;
		}
	}
	
}
my_student.h

#ifndef MY_STUDENT_H
#define MY_STUDENT_H

enum StudyDirection {
	ELECTRICAL_ENGINEERING,
	MECHANICAL_ENGINEERING,
	COMPUTER_SCIENCE,
	TOTAL_STUDY_DIRECTIONS
};


struct MY_STUDENT
{
	char *lastname;
	int length;
	int birth_year;
	enum StudyDirection study_direction;
};

void* MY_STUDENT_Init(const char* llastname, int birthyear, enum StudyDirection studydirection);
void MY_STUDENT_Free(void *ptr);
void* MY_STUDENT_Push(const char* llastname, int birthyear, enum StudyDirection studydirection);
void MY_STUDENT_Print(void* ptr);
int MY_STUDENT_SearchLastName(void* pCureData, void* pSearchStudent);

void MY_STUDENT_Write(void* pData, char** pBuffer, size_t* bufferSize, FILE* pf);
void MY_STUDENT_Read(void** ppData, char* buffer, size_t bufferSize, FILE* pf);
#endif


my_interface.h

void save_stack_to_disk()
{
	char filename[128];
	printf("input filename\n");
	scanf_s("%s", filename, (unsigned int)sizeof(filename));
	MY_STACK_SaveToFile(filename);
}

void load_stack_from_disk()
{
	char filename[128];
	printf("input filename\n");
	scanf_s("%s", filename, (unsigned int)sizeof(filename));
	MY_STACK_LoadFromFile(filename, MY_STUDENT_Write, MY_STUDENT_Read);
}
1

@helloWorld123:

Co niby memcpy ma polepszać (w stosunku do wersji starszych niż poprzednia) to nie wiem.

Rozmiar enuma zalezy od opcji kompilacji. W onym czasie sie dawało, oprócz używanych opcji enuma, jeden bardzo wysoki NOT_USED = 8888888
A ze study_direction trzeba sie zająć debugerem, to oczywiste

Dalej za dużo - moim zdaniem - void * i dających się uniknąć rzutowań.

helloWorld123 napisał(a):

żeby struktury były zapisane jako cały obiekt więc użyłem memcpy.

Wersje (poza ostatnią) zapisywały dobrze (przynajmniej na ogląd kodu gołym okiem), zupełnie nie rozumiem takiego nowego celu. Zamienić "dobrze" na mityczny nie wiadomo skąd wzięty postulat.
Wmiksowałeś się w sprzeczności, jedną z nich jest słowo "obiekt" ale to tylko jako wisienka na torcie

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