[C][C++] Dynamiczna tablica dwuwymiarowa w pliku binarnym.

radzym94
Użytkownik
Użytkownik
Posty: 59
Rejestracja: 14 gru 2009, o 17:12
Płeć: Mężczyzna
Lokalizacja: Gniezno
Podziękował: 24 razy

[C][C++] Dynamiczna tablica dwuwymiarowa w pliku binarnym.

Post autor: radzym94 »

Witam, mam następujący problem.
Napisałem program , który zawiera procedurę (funkcję void) (argumentem jest liczba wierszy tablicy oraz wskaźnik do niej) tworzącą dynamiczną tablicę dwuwymiarową (obiektowy przydział pamięci) natomiast w części main wywołuję tę procedurę i zapisuję powstałą tablicę do pliku binarnego w sposób nieobiektowy (FILE *).
Umiem zapisać taką tablicę do pliku tekstowego, jednak z binarnym mam pewien problem. Napisałem taki kod:

Kod: Zaznacz cały

void Tablica(int w, int **&t)
{
	t = new int*[w];
	for (int i = 0; i < w; i++)
	{
		t[i] = new int[2];
	}
	for (int i = 0; i < w; i++)
	{
		for (int j = 0; j < 2; j++)
		{
			if (j == 0) { t[i][j] = i + 1; }
			if (j == 1) { t[i][j] = i * 2 + 5 % 3; }
		}


	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	int w = 3;
	int **tabi = 0;
	int**tabli = 0;
		Tablica(w,tabi);
		FILE *plik;
fopen_s(&plik, "D:\binarny.bin", " wb");
fwrite(tabi, sizeof(int), w*2, plik);
fclose(plik);
fopen_s(&plik, "D:\binarny.bin", " wr");
fread(tabli, sizeof(tabli), 1, plik);
fclose(plik);

	return 0;
}
Nie jestem pewien ,czy dobrze wykonuję operacje na plikach binarnych w przypadku tablic dwuwymiarowych, więc czy mógłby ktoś rzucić okiem?
Z góry dziękuję za pomoc, pozdrawiam
Awatar użytkownika
Dasio11
Moderator
Moderator
Posty: 10218
Rejestracja: 21 kwie 2009, o 19:04
Płeć: Mężczyzna
Lokalizacja: Wrocław
Podziękował: 40 razy
Pomógł: 2361 razy

[C][C++] Dynamiczna tablica dwuwymiarowa w pliku binarnym.

Post autor: Dasio11 »

Niestety nie.
Pamięć.png
Pamięć.png (8.25 KiB) Przejrzano 2466 razy
Dynamicznie alokowana tablica dwuwymiarowa wygląda tak, jak na obrazku: jest jedna tablica wskaźników, z których każdy wskazuje na jeden wiersz tej tablicy. Te wiersze mogą być umieszczone w pamięci w losowych lokalizacjach, inaczej niż w przypadku statycznych tablic dwuwymiarowych.

Dlatego instrukcja fwrite(tabi, sizeof(int), w*2, plik); nie robi tego, co oczekujesz. Ona traktuje tabi jako tablicę elementów typu int i zapisuje do pliku w*2 tych elementów. Ale w tej tablicy jest tylko w elementów, i to typu int*, więc

1. grozi nam wyjście poza tablicę;
2. nawet jak się uda, to do pliku zostaną zapisane raczej bezwartościowe wskaźniki, które utracą ważność najpóźniej po zakończeniu programu.


Jeszcze parę detali:

1. nadajesz wskaźnikowi tabli wartość 0, więc fread zapisuje dane z pliku pod adres 0x00000000 (co grozi błędem Access Violation)
2. sizeof(tabli) to nie rozmiar tablicy, tylko sizeof(tabli) = sizeof(int**); tak pozostanie nawet jeśli tabli będzie wskazywać na poprawnie zaalokowaną tablicę, bo to nadal będzie tylko wskaźnik typu int**
3. "w" w poleceniu fopen_s(&plik, "D:\binarny.bin", " wr"); powoduje utworzenie pliku D:inarny.bin od nowa z pustą zawartością, więc czytanie zwróci przypadkowe wartości; powinno być "rb"
4. w ramach dobrego nawyku warto na końcu programu zwolnić zaalokowaną pamięć
5. w funkcji Tablica napisałeś t[i][j] = i * 2 + 5 % 3; operator modulo ma wyższy priorytet niż dodawanie, więc zawsze i * 2 + 5 % 3 == i * 2 + 2 - na pewno o to ci chodziło?


Poprawiony kod może wyglądać tak (dodałem wypisanie elementów tabli, żeby było widać efekt).

Kod: Zaznacz cały

int _tmain(int argc, _TCHAR* argv[])
{
    int w = 3;
    int** tabi = 0;
    int** tabli = 0;

    Tablica(w,tabi);
    FILE *plik;

    tabli = new int*[w];
    for (int i = 0; i < w; i++)
    {
      tabli[i] = new int[2];
    }

    fopen_s(&plik, "D:\binarny.bin", "wb");
    for (int i = 0; i < w; ++i)
    {
        fwrite(tabi[i], sizeof(int), 2, plik);
    }
    fclose(plik);

    fopen_s(&plik, "D:\binarny.bin", "rb");
    for (int i = 0; i < w; ++i)
    {
        fread(tabli[i], sizeof(int), 2, plik);
    }
    fclose(plik);


    for( int i = 0; i < w; ++i )
    for( int j = 0; j < 2; ++j )
    {
        printf( "tabli[%d][%d] = %d
", i, j, tabli[i][j] );
    }


    for (int i = 0; i < w; i++)
    {
      delete[] tabli[i];
      delete[] tabi[i];
    }
    delete[] tabli;
    delete[] tabi;


    return 0;
}
ODPOWIEDZ