• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Wskaźniki na tablice, elementy tablic, etc.

Object Storage Arubacloud
0 głosów
1,138 wizyt
pytanie zadane 29 grudnia 2016 w C i C++ przez Sinnley Stary wyjadacz (12,810 p.)
edycja 29 grudnia 2016 przez Sinnley

To pytanie sprawiło, że mam pewne wątpliwości co do kilku kwestii.

Załóżmy, że mamy:

int * ptr;  // wskaznika na inta
int * array_of_ptrs[5]; // tablica pięciu wskaźników na inta
int (*ptr_to_array)[5]; // wskaznik na tablice pięcioelementową

Teraz:

int b = 5;
ptr = &b; // wskaznik na inta wskazuje na inta

A teraz:

ptr = new int [5]; // wskaznik na inta wskazuje na... na co?

Na co wobec tego wskazuje teraz ptr? Skoro jest wskaznikiem na pojedynczego inta, to chyba nie może wskazywać na całą tablicę? Wobec tego wskazuje na pierwszy element?

4 odpowiedzi

0 głosów
odpowiedź 29 grudnia 2016 przez Knayder Nałogowiec (37,640 p.)

Nazwa tablicy to jednocześnie wskaźnik na pierwszy jej element;
A więc
 

int tab[100];

*tab == tab[0];
 

komentarz 29 grudnia 2016 przez Sinnley Stary wyjadacz (12,810 p.)
Nie, nazwa tablicy nie jest wskaźnikiem na jej pierwszy element. Jest po cichu konwertowana na adres, ale nie jest wskaźnikiem. Nie można na niej stosować arytmetyki wskaźników etc.
komentarz 29 grudnia 2016 przez erx700 Gaduła (3,430 p.)
Dla normalnych kompilatorów wskaźnik i tablica różnią się zapisem. Po skompilowaniu wychodzi to samo.
komentarz 29 grudnia 2016 przez Sinnley Stary wyjadacz (12,810 p.)
komentarz 29 grudnia 2016 przez erx700 Gaduła (3,430 p.)
Tablice nie są wskaźnikami bo różnią się zapisem w kodzie, natomiast po skompilowaniu wychodzi to samo w przypadku nowoczesnych kompilatorów.
komentarz 29 grudnia 2016 przez Sinnley Stary wyjadacz (12,810 p.)
Masz jakiś wyjściowy kod assemblera? Nie wydaje mi się, żebyś miał racje.
komentarz 29 grudnia 2016 przez erx700 Gaduła (3,430 p.)
Przy gcc zamiana *a na a[1] daje ten sam md5sum oraz z twojego przykładu zamiana

 int (*ptr)[5] = &tab;

na

int *ptr1 = tab;

daje ten sam md5sum.
komentarz 29 grudnia 2016 przez Sinnley Stary wyjadacz (12,810 p.)
Ok, ale dodaj teraz do obu wskaźników 1. Wychodzi kompletnie inny adres.
komentarz 29 grudnia 2016 przez erx700 Gaduła (3,430 p.)
Bo tak jak pisałem różnią się zapisem, dlatego kompilator inaczej to traktuje.
komentarz 30 grudnia 2016 przez morele123 Gaduła (4,790 p.)
Jak macie tablicę w c++, to tak samo jak byście napisali typ_danych zmienna, zmienna2, zmienna 3 itd. I niczym się to nie różni, jeśli zapisujecie w jednej linii. W pamięci komputera zaś przechowywane jest to jeden obok drugiego i tyle. Tzn. masz adres np. 120, i robimy tablicę 5 wymiarową, to kolejne adresy to 120,124,128,132,136. A jak robimy np. typ_danych zmienna, typ_danych zmienna2, to zmienna może mieć adres 120, a zmienna2 560.
0 głosów
odpowiedź 29 grudnia 2016 przez czujek22 Dyskutant (7,670 p.)
Tak jest to wskaźnik na pierwszy element tablicy. Przynajmniej tak jest też objaśnione w "Szkole programowania" Stephena Praty
0 głosów
odpowiedź 29 grudnia 2016 przez niezalogowany

Tak, wskazuje na pierwszy element w tablicy. Możesz to sprawdzić próbując wypisać pierwszy element tablicy tak:

cout<<*ptr<<endl;

Dodatkowo możesz tego wskaźnika używać z indexem:

ptr[2] = 666;
cout<<ptr[2]<<endl;

Masz tutaj cały przykład jaki zrobiłem do sprawdzenia tego: http://ideone.com/pXWvyW

Polecam takie eksperymenty, gdyż sprawdzenie czegoś w kodzie jest chyba najlepszym sposobem sprawdzenia jak to działa.

komentarz 29 grudnia 2016 przez Sinnley Stary wyjadacz (12,810 p.)

Oczywiście, ale zauważ, że

int tab[5];
int (*ptr)[5] = &tab;
int *ptr1 = tab;

cout << ptr << " " << ptr1;



Liczbowo wychodzi to samo, ten sam adres, ale wskazniki wskazuja na co innego. 
komentarz 29 grudnia 2016 przez niezalogowany

To są rodzaje wskaźnika, ale oba wskazują na początek tablicy.

int tab[5]
int (*ptr)[5] = &tab;
int *ptr1 = tab;
void *ptr2 = (void*)tab;
void *ptr3 = (void*)&tab;
//Wszystkie te 4 wskaźniki wskazują na tą samą komórkę pamięci, ale są różnego typu.
//To typ wskaźnika pozwala programowi się zorientować z czym przychodzi mu pracować
//Tak to rozumiem

Najlepiej jest używać zapisu int * ptr = new int[5], moim zdaniem najprostszy w użyciu.

komentarz 29 grudnia 2016 przez Sinnley Stary wyjadacz (12,810 p.)

Nie,

int tab[5];
int (*ptr)[5] = &tab;
int ptr1 = tab;

Cout << (int)ptr1 << " " << (int)ptr1 + 1;

// Zakladajac ze int ma 4 bajty, adres rozni sie o 4.

Cout << (int)ptr << " " << (int)ptr + 1;

// Zakladajac ze int ma 4 bajty, adres rozni sie o 4*5 = 20.

Mimo, że początkowy adres jest ten sam, po dodaniu jedynki adres jest już inny.
Na początku jest taki sam dlatego, że jest to najlogiczniejsze, żeby ptr pokazał adres pierwszej komórki, jako adres całej tablicy, ptr1 za to po prostu pokazuje adres pierwszej komórki.

 

ptr = ptr1 // ta operacja zwraca błąd.

 

komentarz 29 grudnia 2016 przez niezalogowany
Ehh nie umiem zbytnio tłumaczyć...

Dodając do wskaźnika 1 przeskakujesz o cały element na który wskazuje, dla inta to będzie 4, dla tablicy 5 intów będzie to 20.

Wskaźnik na inta pokazuje na jego pierwszy bajt, wskaźnik na pierwszy element tablicy wskazuje na pierwszy bajt tego elementu, a wskaźnik na tablicę wskazuje na pierwszy bajt tej tablicy.

Wskaźnik ptr jest wskaźnikiem na tablicę pięciu intów, a wskaźnik ptr1 jest wskaźnikiem na pierwszy element tej tablicy, jednak każdy wskazuje na pierwszy bajt tej tablicy, dlatego liczbowo jest to ten sam adres.
komentarz 29 grudnia 2016 przez niezalogowany
Dobra chyba obmyśliłem prostsze wytłumaczenie:

Dodanie do wskaźnika 1 powoduje przesunięcie go o rozmiar obiektu na który wskazuje.

int ma 4 bajty, więc dodanie do wskaźnika int*ptr, który jest typu int*, 1 przesuwa go o 4 bajty
int[5] ma 20 bajtów (4*5), więc dodanie do wskaźnika int(*ptr)[5], który jest typu int(*)[5], 1 przesuwa go o 20 bajtów.
komentarz 29 grudnia 2016 przez Sinnley Stary wyjadacz (12,810 p.)
Ale ja to rozumiem, to co proboje powiedzieć to, że są to wciąż wskaźniki osobnych typów mimo, że ostatecznie wskazują na ten sam bajt pamięci.
komentarz 30 grudnia 2016 przez niezalogowany
Emm.. było tak napisać od razu :p
komentarz 30 grudnia 2016 przez Sinnley Stary wyjadacz (12,810 p.)

Tak się jeszcze odwołam do

Najlepiej jest używać zapisu int * ptr = new int[5], moim zdaniem najprostszy w użyciu.

Otóż niekoniecznie. Każdy z tych typów wskaźnika, które podałem ma osobne zastosowanie.

int tab[5];
int bTab[4];

int * ptr = tab; // ok, ptr wskazuje na poczatek tablicy i zwraca adres pierwsze elementu w tablicy
int  (*bptr)[5] = &tab; // ok, uzywamy & bo odwolujemy się do calego obiektu tablicy piecioelementowej.
                                    // wskaznik wskazuje na cala tablice, a jako adres podaje adres jej pierwszego elementu.

ptr = btab; // ok, ptr wskazuje teraz na pierwszy element czteroelementowej tablic btab.
bptr = &btab; // BŁĄD, btab ma typ "wskaznik na piecioelementowa tablice", a btab ma 4 elementy.
                        // zapisy nie są równoważne.

Tak więc wszystko zależy od potrzeb. Zależnie od tego co chcemy stworzyć będziemy używać różnych wskaźników.

komentarz 30 grudnia 2016 przez niezalogowany
No tak masz rację. W sumie to nie używam tych wskaźników, bo zamiast tablic stosuję kontenery STL
0 głosów
odpowiedź 30 grudnia 2016 przez morele123 Gaduła (4,790 p.)

Jak używasz operatora new to tworzysz nowy obiekt, ptr to wskaznik tak ? Przypisujesz do niego wskazanie na 5 komórek o długości int. Np. tworzysz klasę, a w niej masz dwie dane np. :

class klasa

int value;

klasa * ptr;

I masz jakiś wskaźnik nazwijmy go pointer i robisz coś takiego: pointer = new klasa. Wówczas twój pointer przechowuje wskaźnik na element, który właśnie stworzyłeś, czyli na klasę. Jeżeli zrobisz następnie coś takiego: pointer->value to dostaniesz się do tego właśnie inta w tej klasie. Jak zrobisz pointer->ptr to dostaniesz się do wskaźnika klasy (klasa * ptr).

komentarz 30 grudnia 2016 przez Sinnley Stary wyjadacz (12,810 p.)
No wiem, a jak to się ma do mojego pytania o wskaźnik na tablicę?
komentarz 30 grudnia 2016 przez morele123 Gaduła (4,790 p.)
No napisałem, przecież. Tablica np. a[10] to jest 10 zmiennych poadresowanych obok siebie, jeżeli używasz samego a to odnosisz się do tych właśnie 10 elementów, a jeżeli używasz *a to odnosisz się tylko do pierwszego elementu.
komentarz 30 grudnia 2016 przez Sinnley Stary wyjadacz (12,810 p.)
Nie, jeśli odnosisz się do A to dostaniesz przekonwertowany wskaznik na pierwszy element, w skórcie adres. *a - dostajesz wartosc w tym adresie.

Moje pytanie brzmiało czy int * ptr = new int[5]; jest wskaznikiem na tablicę, czy na pojedynczego inta.
komentarz 31 grudnia 2016 przez morele123 Gaduła (4,790 p.)
No nie bardzo, bo twoje A zawiera wszystkie elementy, ale żeby zaoszczędzić miejsce, to skoro są te dane obok siebie to zapamiętuje adres pierwszego elementu i bodajże ilość elementów. Ale nie wiem czy nie przypadkiem ostatni adres. Więc to nie prawda, że to tylko jeden element.

ptr jest wskaźnikiem, więc będzie wskazywać na int[0]. Poleceniem new int[5] tworzysz tablicę intów o rozmiarze 5. Tak jak napisałem wcześniej.
komentarz 1 stycznia 2017 przez Sinnley Stary wyjadacz (12,810 p.)
Tak Ci się tylko wydaje, czy masz jakieś podstawy, dokumentacja, coś podobnego.

Dodatkowo: "No nie bardzo, bo twoje A zawiera wszystkie elementy, ale żeby zaoszczędzić miejsce, to skoro są te dane obok siebie to zapamiętuje adres pierwszego elementu i bodajże ilość elementów."

Co sobie zapamiętuje ten adres, A?

Podobne pytania

0 głosów
2 odpowiedzi 1,167 wizyt
0 głosów
1 odpowiedź 1,071 wizyt
0 głosów
1 odpowiedź 164 wizyt
pytanie zadane 2 grudnia 2018 w C i C++ przez tomekrx Nowicjusz (160 p.)

92,573 zapytań

141,423 odpowiedzi

319,645 komentarzy

61,959 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...