Naruszenie zasad dostępu do odczytu

0

Stworzyłem stos, który przechowuje dane w postaci struktur. Jedną z funkcji jest zapisywanie i wczytywanie danych z pliku binarnego. Niestety okazuje się, ze danych nie mogę wyświetlić przez 'naruszenie zasad dostępu do odczytu'. Dodam tez, ze problem pojawia się tylko, jeśli zamknę program i próbuję wczytać na nowo dane z pliku. Kiedy zapisuję i wcztuję dane w tej samej sesji wszystko jest ok. Podejrzewam, ze ma to związek z polem lastname alokowanym dynamicznie. Czy ktoś byłby w stanie zdiagnozować problem?

struct MY_STUDENT
{
	char* lastname;
	FIELD field;
	int year;
};

bool MY_STUDENT_Save(void** pdat, FILE* pf)
{
	MY_STUDENT tmp;

	if (pf && *pdat)
	{
		struct MY_STUDENT* ptr = (struct MY_STUDENT*)(*pdat);
		size_t ctrl_len;

		if ((ctrl_len = fwrite((const void*)(ptr), sizeof(MY_STUDENT), 1, pf)) != 1)
			return false;
		return true;
	}
	else
		return false;
}


bool MY_STUDENT_Read(void** pdat, FILE* pf)
{
	if (pf)
	{
		struct MY_STUDENT* ptr = (struct MY_STUDENT*)(*pdat);
		size_t ctrl_len;

		if (!ptr)
		{
			if ((ptr = (struct MY_STUDENT*)malloc(sizeof(struct MY_STUDENT))) == NULL)
				my_mess(MY_MESS_DATA_ERROR);
		}

		*pdat = (void*)ptr;

		if((ctrl_len = fread((void*)(ptr), sizeof(struct MY_STUDENT), 1, pf)) != 1)
			return false;
		
		return true;
	}
	else
		return false;

}


bool MY_STACK_SAVE(struct STACK* top)
{

    struct STACK* p = top;
    unsigned int no_items, ret;
    int i = 0;
    FILE* pFile = fopen("stack.bin", "wb");
    if (!pFile)
        return false;
    no_items = getCount(top);
    if (pFile == NULL)
    {
        my_mess(MY_MESS_FILE_ERROR);
        return false;
    }

    if ((ret = fwrite(&no_items, sizeof(no_items), 1, pFile)) != 1)
        return false;
   

    while (p != NULL)
    {
        
        fseek(pFile, --no_items*sizeof(struct MY_STUDENT)+sizeof(no_items), SEEK_SET);
        
        if(!MY_STUDENT_Save(&p->data,pFile))
            return false;
        MY_STUDENT_Print(p->data);
        p = p->next;

        
    }
   
    fclose(pFile);
    return true;

}

bool MY_STACK_LOAD(struct STACK** top) /*struct STACK** top*/
{

    size_t it = 0;
    unsigned int no_items, ret;
    struct STACK tmp;
    memset((void*)&tmp, 0, sizeof(tmp));

    FILE* pFile = fopen("stack.bin", "rb");
    if (!pFile)
        my_mess(MY_MESS_FILE_ERROR);

    if (top != NULL)
    {
        MY_STACK_FREE(top);
    }
    if ((ret = fread(&no_items, sizeof(no_items), 1, pFile)) != 1)
        return false;
    printf("%u\n", no_items);


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

         tmp.data = NULL;
         if (!MY_STUDENT_Read(&tmp.data, pFile))
             return false;
         if (!MY_STACK_PUSH(top, tmp.data))
             return false;
         MY_STUDENT_Print(tmp.data);
         tmp.data = NULL;
        
    }   
     
    fclose(pFile);
    return true;
}
     
0

A próbowałeś sobie spojrzeć w zapisany plik? Co, widzisz w nim ten napis który wkladałeś uprzednio? Czy może są tam jedynie "śmieci", a plik w ogóle jest za krótki żeby mógł pomieścić wszystko co chciałeś tam wpisać?

3

Jak robisz naiwny zapis do pliku zapisując wskaźniki to tak się to kończy.
To jest źle:

if ((ctrl_len = fwrite((const void*)(ptr), sizeof(MY_STUDENT), 1, pf)) != 1)

to też jest źle:

if((ctrl_len = fread((void*)(ptr), sizeof(struct MY_STUDENT), 1, pf)) != 1)

Twoja struktura MY_STUDENT zawiera wskaźnika na napis, a sam wskaźnik nie wystarczy do odtworzenia napisu.
W nowym procesie wskaźnik ten będzie wskazywał w przypadkowe miejsce pamięci i produkować będzie ten błąd.

Masz dwa wyjścia:

  • porzucić format binarny i zapisywać dane tekstowo (zalecane)
  • napisać funkcje, które potrafią zapisać i odczytać binarnie do/z pliku napis. A potem użyć tej funkcji podczas zapisywania/odczytywania studenta.
0

@MarekR22: Spodziewałem się, ze tam tkwi błąd, ale nie wiem tez w jaki sposób to naprawić..Byłbym wdzięczny za jakieś wskazówki.

1

Zapis odczyt tekstowo

bool MY_STUDENT_Read(struct MY_STUDENT* student, FILE* f)
{
    char name_buffer[256];
    int read_count = fscanf(" %255[^\n] %d %d ", buffer, &student->field, &student->year);
    if (read_count == 3) {
        student->lastname = strdup(name_buffer);
    }
    return read_count == 3;
}

bool MY_STUDENT_Save(struct MY_STUDENT* student, FILE* f)
{
    return fprintf("%s\n%d %d\n",  student->lastname, student->field, student->year) > 0;
}

Do/z takiego formatu tekstowego:

John McClain
12 1955
William Shakespeare
32 1564

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