[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Chungu
Użytkownik
Użytkownik
Posty: 121
Rejestracja: 21 paź 2016, o 20:57
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 42 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: Chungu »

Witam.

Uczę się alokowania dynamicznych tablic. W programie próbuję stworzyć 2 tablicę - jedna o rozmiarze [rozmiar1][50] i 2 o rozmiarze [rozmiar2][rozmiar3] 1 stworzyłem w taki sposób:

Kod: Zaznacz cały

int ilosc;
	printf("Prosze podac ile wyrazow chcesz wprowadzic:");
	scanf("%d",&ilosc);
	char (*ptr)[50];
	ptr=(char(*)[50])malloc(ilosc*sizeof(char));
free(ptr);
Nie rozumiem trochę tego zapisu (*ptr)[50]//znalazłem go w książce Praty a wyjaśnienie tam zawarte niezbyt do mnie przemówiło -czy samo free(ptr) w tym przypadku wystarczy?

jak zrobić drugą tablicę o obu rozmiarach podanych przez użytkownika i jak potem "wyczyścić" pamięć?
Pomoże ktoś?
Dzięki.
Gouranga
Użytkownik
Użytkownik
Posty: 1592
Rejestracja: 16 maja 2013, o 17:56
Płeć: Mężczyzna
Lokalizacja: Trójmiasto
Podziękował: 11 razy
Pomógł: 246 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: Gouranga »

nie do końca kumam po co chcesz to alokować dynamicznie jeśli użytkownik podaje rozmiar z góry, przecież można zrobić tak:

Kod: Zaznacz cały

scanf("%i", &rozmiar1);
char ptr[rozmiar1][50];
dynamiczna alokacja ma sens jeśli np. w locie masz dodawać kolejne wyrazy nie wiedząc ile ich ma być
ale ok, powiedzmy, że z jakiegoś powodu chcesz dynamicznie, proszę bardzo:

Kod: Zaznacz cały

scanf("%i", &rozmiar1);
char **ptr;
ptr = (char**)malloc(rozmiar1*sizeof(char*));
for (i=0; i<rozmiar1; i++){
  ptr[i] = (char*)malloc(50*sizeof(char));
}
...
for (i=0; i<rozmiar1; i++){
  free(ptr[i]);
}
free(ptr);
Chungu
Użytkownik
Użytkownik
Posty: 121
Rejestracja: 21 paź 2016, o 20:57
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 42 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: Chungu »

Dziękuję. A taka deklaracja ze zmienną nie jest czasem od jakiegoś standardu C11 albo C90 coś (nie pamiętam ale chyba widziałem coś takiego w książce) i nie wszystkie kompilatory na to pozwalają? W każdym razie u mnie prowadząca chciała z dynamiczną alokacją mimo, że kompilator pozwalał na rozwiązanie ze zmienną. :/
Gouranga
Użytkownik
Użytkownik
Posty: 1592
Rejestracja: 16 maja 2013, o 17:56
Płeć: Mężczyzna
Lokalizacja: Trójmiasto
Podziękował: 11 razy
Pomógł: 246 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: Gouranga »

kompilator w zasadzie tłumaczy taką deklarację ze zmienną i tak na malloc, a co do standardu, w C89 na pewno działa a nikt raczej nie używa starszego niż ten.
kalwi
Użytkownik
Użytkownik
Posty: 1931
Rejestracja: 29 maja 2009, o 11:58
Płeć: Mężczyzna
Lokalizacja: Warszawa
Podziękował: 145 razy
Pomógł: 320 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: kalwi »

Gouranga pisze:nie do końca kumam po co chcesz to alokować dynamicznie jeśli użytkownik podaje rozmiar z góry, przecież można zrobić tak:

Kod: Zaznacz cały

scanf("%i", &rozmiar1);
char ptr[rozmiar1][50];
Nie powinno tak się robić.
Gouranga pisze:kompilator w zasadzie tłumaczy taką deklarację ze zmienną i tak na malloc, a co do standardu, w C89 na pewno działa a nikt raczej nie używa starszego niż ten.
- nie, kompilator nie tłumaczy tego na malloc
- nie, w C89 to nie zadziała (VLA jest dostępne tylko w C99, w C11 to wywalili)
- to jest jakiś standard starszy niż C89? Ciekawe...
Gouranga
Użytkownik
Użytkownik
Posty: 1592
Rejestracja: 16 maja 2013, o 17:56
Płeć: Mężczyzna
Lokalizacja: Trójmiasto
Podziękował: 11 razy
Pomógł: 246 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: Gouranga »

to wytłumacz mi, dlaczego na studiach takie deklaracje nam działały, a pisaliśmy w C89 i mieliśmy kompilator GCC pod C89
Afish
Moderator
Moderator
Posty: 2828
Rejestracja: 15 cze 2008, o 15:45
Płeć: Mężczyzna
Lokalizacja: Seattle, WA
Podziękował: 3 razy
Pomógł: 356 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: Afish »

kalwi pisze:- nie, w C89 to nie zadziała (VLA jest dostępne tylko w C99, w C11 to wywalili)
W C11 jest opcjonalne.
kalwi pisze:- to jest jakiś standard starszy niż C89? Ciekawe...
Standard de jure nie, ale standard de facto starszy od C89 tak, K&R.
Gouranga pisze:to wytłumacz mi, dlaczego na studiach takie deklaracje nam działały, a pisaliśmy w C89 i mieliśmy kompilator GCC pod C89
Rozszerzenia GCC lub przypadek (że działało). — w C++ nie ma VLA, a ten kod się kompiluje i nie wysypuje Ideone.
Awatar użytkownika
miki999
Użytkownik
Użytkownik
Posty: 8691
Rejestracja: 28 lis 2007, o 18:10
Płeć: Mężczyzna
Lokalizacja: Gdańsk
Podziękował: 36 razy
Pomógł: 1001 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: miki999 »

Nie rozumiem trochę tego zapisu (*ptr)[50]//znalazłem go w książce Praty a wyjaśnienie tam zawarte niezbyt do mnie przemówiło -czy samo free(ptr) w tym przypadku wystarczy?
char (*ptr)[50] oznacza wskaźnik na tablicę charów o rozmiarze 50. Czyli chcąc wziąć np. piąty element tej tablicy, musisz napisać (*ptr)[5].

Powróćmy do twojego kodu z pierwszego posta i przeanalizujmy:

Kod: Zaznacz cały

   int ilosc;
   printf("Prosze podac ile wyrazow chcesz wprowadzic:");
   scanf("%d",&ilosc);
   char (*ptr)[50];
   ptr=(char(*)[50])malloc(ilosc*sizeof(char));
   free(ptr);
Pomijasz jeden "stopień" wskaźnika. Alokujesz tablicę w miejsce wskaźnika na tablicę. Pamiętasz pewnie, że każdy wskaźnik jest rozmiaru inta. Zatem robiąc ptr[0], ptr[1], ptr[2], ... nie skaczesz po tablicy charów a po tablicy wskaźników na tablice (czyli zwiększając indeks modyfikujesz adres pamięci o rozmiar inta).

Ten wcześniej zaproponowany kod jest również niefajny:

Kod: Zaznacz cały

scanf("%i", &rozmiar1);
char **ptr;
ptr = (char**)malloc(rozmiar1*sizeof(char*));
for (i=0; i<rozmiar1; i++){
  ptr[i] = (char*)malloc(50*sizeof(char));
}
...
for (i=0; i<rozmiar1; i++){
  free(ptr[i]);
}
free(ptr);
Kontynuując metodologię z pierwszego posta, można przecież napisać:

Kod: Zaznacz cały

int rozmiar1= 20;
int rozmiar2 = 50;

char (*tab)[rozmiar2] = ( char (*)[rozmiar2] ) malloc(rozmiar1 * rozmiar2 * sizeof(char));
Chociaż prawda, że VLA (variable length array) może nie być wspierane przez kompilator, ale gdy jeden wymiar jest stały, to zgodność jest zapewniona.
kalwi
Użytkownik
Użytkownik
Posty: 1931
Rejestracja: 29 maja 2009, o 11:58
Płeć: Mężczyzna
Lokalizacja: Warszawa
Podziękował: 145 razy
Pomógł: 320 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: kalwi »

Afish pisze:W C11 jest opcjonalne.
Tylko po to, aby móc zachować zgodność wsteczną z C99.
Afish pisze:Standard de jure nie, ale standard de facto starszy od C89 tak, K&R.
Odpowiedniejsze słowo to dokumentacja (która potem się przerodziła w coś ala standard, ale nim nie jest per se).
Afish pisze:Rozszerzenia GCC lub przypadek (że działało). — w C++ nie ma VLA, a ten kod się kompiluje i nie wysypuje Ideone.
VLA zawsze było rozszerzeniem w GCC i zostało potem zaimplementowane w C99 (co było błędem). Przypadków nie ma. Ten kod się kompiluje dlatego, że wybrałeś akurat g++ tam. Jakby dodać flagę -pedantic to by wywaliło warning.-- 7 mar 2017, o 12:55 --
miki999 pisze:Czyli chcąc wziąć np. piąty element tej tablicy, musisz napisać (*ptr)[5]
Nieprawda
miki999 pisze:Pamiętasz pewnie, że każdy wskaźnik jest rozmiaru inta
Nieprawda. Rozmiar wskaźnika zależy od architektury i jej implementacji, a nie jest równy intowi.
Ewentualnie jest coś takiego jak intptr_t.
miki999 pisze:nie skaczesz po tablicy charów a po tablicy wskaźników na tablice
Raczej: tablicy wskaźników na char
miki999 pisze:Chociaż prawda, że VLA (variable length array) może nie być wspierane przez kompilator, ale gdy jeden wymiar jest stały, to zgodność jest zapewniona.
Nieprawda.

Kod: Zaznacz cały

const int x = 5;
int a[x]; 
To jest VLA w C (w C++ już nie).
Afish
Moderator
Moderator
Posty: 2828
Rejestracja: 15 cze 2008, o 15:45
Płeć: Mężczyzna
Lokalizacja: Seattle, WA
Podziękował: 3 razy
Pomógł: 356 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: Afish »

kalwi pisze:Tylko po to, aby móc zachować zgodność wsteczną z C99.
Pobudki nie są zanadto istotne.
kalwi pisze:Odpowiedniejsze słowo to dokumentacja (która potem się przerodziła w coś ala standard, ale nim nie jest per se).
Logomachia, wszyscy traktowali to jako faktyczny standard.
kalwi pisze:VLA zawsze było rozszerzeniem w GCC i zostało potem zaimplementowane w C99 (co było błędem). Przypadków nie ma. Ten kod się kompiluje dlatego, że wybrałeś akurat g++ tam. Jakby dodać flagę -pedantic to by wywaliło warning.
Program mający UB, a mimo to działający bez wysypania się działa przypadkiem.
Awatar użytkownika
miki999
Użytkownik
Użytkownik
Posty: 8691
Rejestracja: 28 lis 2007, o 18:10
Płeć: Mężczyzna
Lokalizacja: Gdańsk
Podziękował: 36 razy
Pomógł: 1001 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: miki999 »

kalwi pisze:
miki999 pisze:Czyli chcąc wziąć np. piąty element tej tablicy, musisz napisać (*ptr)[5]
Nieprawda
Zatem popraw mnie, proszę, żebym coś też wyniósł z tego wątku.
kalwi pisze:Nieprawda. Rozmiar wskaźnika zależy od architektury i jej implementacji, a nie jest równy intowi.
Tu się zgodzę, to było nadużycie z mojej strony.
kalwi pisze:
miki999 pisze: Chociaż prawda, że VLA (variable length array) może nie być wspierane przez kompilator, ale gdy jeden wymiar jest stały, to zgodność jest zapewniona.
Nieprawda.

Kod: Zaznacz cały

const int x = 5;
int a[x];
To jest VLA w C (w C++ już nie).
Punkt dla Gryffindoru za dociekliwość.
Gouranga
Użytkownik
Użytkownik
Posty: 1592
Rejestracja: 16 maja 2013, o 17:56
Płeć: Mężczyzna
Lokalizacja: Trójmiasto
Podziękował: 11 razy
Pomógł: 246 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: Gouranga »

nie musisz pisać (*ptr)[5] bo zadziała też *ptr[5], operator wyłuskania ma wyższy priorytet niż indeksowanie tablicy, więc i tak zadziała pierwszy, nawiasy będą konieczne dopiero, gdybyś z jakichś powodów chciał napisać tak: *(ptr[5]).
Awatar użytkownika
miki999
Użytkownik
Użytkownik
Posty: 8691
Rejestracja: 28 lis 2007, o 18:10
Płeć: Mężczyzna
Lokalizacja: Gdańsk
Podziękował: 36 razy
Pomógł: 1001 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: miki999 »

Oj, Gouranga, nie zgodzę się. Tutaj link do poparcia moich słów: ... precedence oraz krótki kod:

edit: Jeszcze jeden edukacyjny przykład: https://goo.gl/mLhk10
kalwi
Użytkownik
Użytkownik
Posty: 1931
Rejestracja: 29 maja 2009, o 11:58
Płeć: Mężczyzna
Lokalizacja: Warszawa
Podziękował: 145 razy
Pomógł: 320 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: kalwi »

miki999 pisze:
kalwi pisze:
miki999 pisze:Czyli chcąc wziąć np. piąty element tej tablicy, musisz napisać (*ptr)[5]
Nieprawda
Zatem popraw mnie, proszę, żebym coś też wyniósł z tego wątku.
iterujemy od 0, nie od 1
Awatar użytkownika
miki999
Użytkownik
Użytkownik
Posty: 8691
Rejestracja: 28 lis 2007, o 18:10
Płeć: Mężczyzna
Lokalizacja: Gdańsk
Podziękował: 36 razy
Pomógł: 1001 razy

[C] Dynamiczna alokacja pamięci dla tablicy dwuwymiarowej

Post autor: miki999 »

kalwi pisze: iterujemy od 0, nie od 1
Mówiąc "piąty element" miałem na myśli piąty licząc od zera. Chyba każdy zrozumiał o co chodziło.
ODPOWIEDZ