[ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Bash, C, C++, Java, PHP, Ruby, GTK, Qt i wiele innych - wszystko tutaj.
goru
Piegowaty Guziec
Piegowaty Guziec
Posty: 4
Rejestracja: 17 lut 2009, 12:09
Płeć: Mężczyzna
Wersja Ubuntu: 9.10
Środowisko graficzne: GNOME
Architektura: x86

[ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Post autor: goru »

Witam,
Tak jak w temacie, muszę zrobić(na uczelnię) pewien program, między innymi ma tam być taka o funkcja:

Kod: Zaznacz cały

UtworzMacierz(float** tab,int x,int y)
Która ma rezerwować pamięć na macierz o wymiarach x, y.
Jedyne rozwiązanie jakie mi przychodzi do głowy to coś w tym stylu:

Kod: Zaznacz cały

float **UtworzMacierz(int x,int y)
{
   int i;
   float **tab;
   tab=(float**)malloc(x*sizeof(float*));
   for(i=0;i<x;++i)
      tab[i]=(float*)malloc(y*sizeof(float));   
   return tab;
};
Ale wtedy nie jest to do końca zgodne z poleceniem. Niby mógłbym tam wrzucić ten dodatkowy argument, a resztę zostawić tak jak jest, ale to by było rozwiązanie trochę na siłę.

Ma ktoś może pomysł, jak zrobić to bardziej w tym stylu:

Kod: Zaznacz cały

void UtworzMacierz(float** tab,int x,int y)
	{
		int i;
		tab=(float**)malloc(x*sizeof(float*));
		for(i=0;i<x;++i)
			tab[i]=(float*)malloc(y*sizeof(float));
	};
tylko tak, żeby działało? Przypominam, że chodzi o ANSI C, więc referencja nie wchodzi w grę.
Awatar użytkownika
Struchu
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 116
Rejestracja: 23 mar 2008, 19:58
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: GNOME
Architektura: x86

Odp: [ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Post autor: Struchu »

A nie można tak:

Kod: Zaznacz cały

void UtworzMacierz(float **tab, int x, int y) 
   { 
          *tab = (float *)malloc(x * y * sizeof(float)); 
   }
 
Ma zielone, kocie oczy...
Czocher
Piegowaty Guziec
Piegowaty Guziec
Posty: 8
Rejestracja: 09 lut 2006, 22:05
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: GNOME
Kontakt:

Odp: [ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Post autor: Czocher »

Struchu pisze:A nie można tak:

Kod: Zaznacz cały

void UtworzMacierz(float **tab, int x, int y) 
   { 
          *tab = (float *)malloc(x * y * sizeof(float)); 
   }
 
Broń Boże, taki kod robi coś dziwnego, aczkolwiek pomysł przekazywania tab przez parametr jest dobry. Warto jednak uważać by alokację pamięci zrobić poprawnie robiąc coś w stylu:

Kod: Zaznacz cały

void
UtworzMacierz(float **tab, int x, int y)
{
    int i=0;
    tab = (int**)calloc(x, sizeof(int*));
    for(i=0;i<x;i++)
        tab[i] = (int*)calloc(y, sizeof(int));
    return;
}
Utworzymy tablicę x na y, ale... lokalną. By przekazać ją przez wskaźnik musimy prawdopodobnie parametr tab przedstawić jako: float ***tab. Oczywiście warto sprawdzić czy się nie mylę bo pewności co do tego nie mam ;).
Awatar użytkownika
dawwin
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 202
Rejestracja: 18 kwie 2009, 09:16
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: GNOME
Architektura: x86
Kontakt:

Odp: [ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Post autor: dawwin »

Musi być taka deklaracja funkcji?
UtworzMacierz(float** tab,int x,int y)
Bo nie da się przekazać w ten sposób wskaźnika do macierzy dwuwymiarowej.
Powinieneś mieć
float ***tab
W funkcji robisz sobie
float **tymczasowy = NULL;
Alokujesz przypisując do zmiennej 'tymczasowy', tak jak już sam wyżej to napisałeś (tylko dodaj jeszcze sprawdzanie, czy wynik funkcji malloc() nie jest NULLem)
I na koniec
*tab = tymczasowy;
I funkcję wywołujesz tak
UtworzMacierz(&tab, x, y);
Moje programy - http://dawwin.users.sourceforge.net/
Nie pomagam na PW
luzakwielki
Wytworny Kaczor
Wytworny Kaczor
Posty: 264
Rejestracja: 19 lis 2008, 11:42
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: [ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Post autor: luzakwielki »

Czocher pisze:Broń Boże, taki kod robi coś dziwnego, aczkolwiek pomysł przekazywania tab przez parametr jest dobry. Warto jednak uważać by alokację pamięci zrobić poprawnie robiąc coś w stylu:
A co w tym dziwnego? Alokuje tyle samo pamięci co twój przykład zupełnie normalnie (tylko oszczędza dużo czasu bo robi to na raz i nie zeruje wartości (jak calloc)). Osobno alokować każdy wiersz tablicy to strata czasu.
Awatar użytkownika
dawwin
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 202
Rejestracja: 18 kwie 2009, 09:16
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: GNOME
Architektura: x86
Kontakt:

Odp: [ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Post autor: dawwin »

luzakwielki pisze:A co w tym dziwnego? Alokuje tyle samo pamięci co twój przykład zupełnie normalnie (tylko oszczędza dużo czasu bo robi to na raz i nie zeruje wartości (jak calloc)). Osobno alokować każdy wiersz tablicy to strata czasu.
Chociażby to, że alokowana miała być tablica 2D, a nie wektor o długości x*y. Wiem, że możnaby to pominąć przypinając odpowiednio wskaźniki, ale to rozwiązanie ma dwie wady:
Pierwsza - Załóżmy, że chcemy zaalokować tablicę 10000x10000. Próba zaalokowania tego, jako wektor może skończyć się niepowodzeniem, bo system może nie przydzielić tyle ciągłego obszaru pamięci, a 10000 mniejszych w przypadku tablicy 2D pewnie się znajdzie.
Druga - Po zaalokowaniu tablicy chciałbym dodać jeszcze jedną kolumnę. W przypadku tablicy 2D użyję po prostu funkcji realloc(), a w przypadku wektora...
Moje programy - http://dawwin.users.sourceforge.net/
Nie pomagam na PW
luzakwielki
Wytworny Kaczor
Wytworny Kaczor
Posty: 264
Rejestracja: 19 lis 2008, 11:42
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: [ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Post autor: luzakwielki »

dawwin pisze:Chociażby to, że alokowana miała być tablica 2D, a nie wektor o długości x*y. Wiem, że możnaby to pominąć przypinając odpowiednio wskaźniki, ale to rozwiązanie ma dwie wady:
Pierwsza - Załóżmy, że chcemy zaalokować tablicę 10000x10000. Próba zaalokowania tego, jako wektor może skończyć się niepowodzeniem, bo system może nie przydzielić tyle ciągłego obszaru pamięci, a 10000 mniejszych w przypadku tablicy 2D pewnie się znajdzie.
Druga - Po zaalokowaniu tablicy chciałbym dodać jeszcze jedną kolumnę. W przypadku tablicy 2D użyję po prostu funkcji realloc(), a w przypadku wektora...
Nigdzie nie widziałem informacji, że to ma być tablica 2d, a tylko, że ma za alokować pamięć na macierz (a do nich najczęściej stosuje się właśnie jednowymiarowo (tak jak są pakowane dane w pamięci ram)) - po za tym co Ci szkodzi zaalokować ciągłą pamięć, a później korzystać z tego jak z tablicy 2d oszczędzając czas na wielokrotne alokacje?.
Po pierwsze mało prawdopodobne w dzisiejszych czasach, aby nie było dostępne niecałe 50mb ciurkiem (tyle zajmuje taka macierz jak powiedziałeś). Przy tak dużych tablicach tym bardziej opłaca się sprawdzić czy znajdzie się taka duża pamięć wolna bo 10001x alokacja po 10000 float będzie trwało bardzo długo (bardziej opłaca się alokować dużą pamięć, a jak się nie mieści (wskaźnik == NULL) to zaalokować ręcznie każdy wiersz (w 99.9% przypadków zaoszczędzisz sporo czasu)).
Po drugie nie ma problemu z realokacją - jednak realokacja całości dużego obszaru pamięci jeśli zaraz za pamięcią coś jest zajmie dużo czasu, dlatego w takim przypadku polecałbym na początku alokować dużą pamięć w wektorze i zmapować ją do tablicy wskaźników

Kod: Zaznacz cały

float* tablica = (float*) malloc(sizeof(float)*N*M);
...
float **tab = (float**) malloc(sizeof(float*) * N);
for(int i = 0; i < N; i++) tab[i] = tablica + i*M;
Dzięki czemu, alokacja idzie bardzo szybko, a w razie konieczności możesz sobie realokować tab i tylko część pamięci mieć w innym miejscu (ofc trzeba sobie już zrobić zarządzanie pamięcią i dobrze odśmiecać to, ale jak najbardziej alokacja dużej ilości pamięci za jednym razem to dobry pomysł - w wielu aplikacjach pisanie własnego GC z prealokacją dużej ilości pamięci, która później jest rozdawana zmiennym, zamiast alokować wiele razy jest wręcz wymogiem).
Awatar użytkownika
dawwin
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 202
Rejestracja: 18 kwie 2009, 09:16
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: GNOME
Architektura: x86
Kontakt:

Odp: [ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Post autor: dawwin »

luzakwielki pisze:Nigdzie nie widziałem informacji, że to ma być tablica 2d, a tylko, że ma za alokować pamięć na macierz
goru pisze:Tak jak w temacie, muszę zrobić(na uczelnię) pewien program, między innymi ma tam być taka o funkcja:
Kod:
UtworzMacierz(float** tab,int x,int y)

Która ma rezerwować pamięć na macierz o wymiarach x, y.
luzakwielki pisze:Po pierwsze mało prawdopodobne w dzisiejszych czasach, aby nie było dostępne niecałe 50mb ciurkiem
Te wymiary, które podałem były tylko dla przykładu. Równie dobrze mógłbym chcieć zaalokować tablicę 2D, która zajmie mi w pamięci 2GB. Jest większe prawdopodobieństwo, że próba zaalokowania dużego ciągłego obszaru zakończy się niepowodzeniem, niż alokacja wielu małych (sprawdzone doświadczalnie)
luzakwielki pisze:Po drugie nie ma problemu z realokacją
Ale jak dodajesz kolumnę do wektora zmapowanego na tablicę 2D to musisz liczyć się z koniecznością przesuwania elementów. Przykład

Kod: Zaznacz cały

Wektor
|1|2|3|4|5|6|
Zmapowana tablica
|1|2|
|3|4|
|5|6|

I teraz chcę dodać kolumnę
|1|2|a|3|4|b|5|6|c|

|1|2|a|
|3|4|b|
|5|6|c|
I wszystkie element za dwójką muszę przenosić, żeby "upchnąć" brakującą kolumnę

Podsumowując, metoda, którą podałeś jest dobra, ale nie sprawdzi się w przypadku dużych tablic i konieczności realokacji
Moje programy - http://dawwin.users.sourceforge.net/
Nie pomagam na PW
Awatar użytkownika
DDAroo
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 107
Rejestracja: 27 cze 2009, 10:47
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: KDE Plasma
Architektura: x86
Lokalizacja: Kraków
Kontakt:

Odp: [ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Post autor: DDAroo »

Jest kilka sposobów dynamicznego alokowania pamięci na tablicę dwuwymiarową (macierz). Każdy z nich ma swoje zalety i wady. Daję link do anglojęzycznej strony, gdzie są one omówione: link
luzakwielki
Wytworny Kaczor
Wytworny Kaczor
Posty: 264
Rejestracja: 19 lis 2008, 11:42
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: [ANSI C] Dynamiczna alokacja pamięci w zewnętrzej funkcji

Post autor: luzakwielki »

dawwin pisze:Te wymiary, które podałem były tylko dla przykładu. Równie dobrze mógłbym chcieć zaalokować tablicę 2D, która zajmie mi w pamięci 2GB. Jest większe prawdopodobieństwo, że próba zaalokowania dużego ciągłego obszaru zakończy się niepowodzeniem, niż alokacja wielu małych (sprawdzone doświadczalnie)
Tak dlatego jeśli nie da się zaalokować na raz warto mieć alternatywę i robić dla każdego osobno.

dawwin pisze:Ale jak dodajesz kolumnę do wektora zmapowanego na tablicę 2D to musisz liczyć się z koniecznością przesuwania elementów. Przykład
Jak alokujesz osobno każdy wiersz to i tak masz prawie pewne, że będą one zaraz przy sobie zaalokowane, więc będziesz musiał alokować, kopiować i zwalniać wszystko razem z 1 i 2, więc przewaga jest czysto teoretyczna.
ODPOWIEDZ

Wróć do „Programowanie”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 15 gości