Skomplikowany zapis deklaracji wskaźników

2018-12-04 18:01
0

Otóż mam taki problem, że zaczynam dopiero wskaźniki i nie rozumiem takiego oto kodu i prosiłbym o wytłumaczenie kilku zaznaczonych linijek:)

    int rozmiar;
    cout << "Podaj rozmiar tablicy: ";
    cin >> rozmiar;

    int *tablica;      // tutaj deklarujemy wskaznik wskazujacy typ int o nazwie tablica (jasne) //
    tablica = new int [rozmiar];  // a tutaj jest kosmos, nagle z jednego wskaźnika robi sie ich tablica, jak??:/ //

    for (int i=0; i<=rozmiar; i++)
    {
        cout << tablica << endl;  
        tablica++;       
    }
    delete [] tablica;

No i jeszcze pętla:
Przy cout'cie zawartosci wskaznika nie ma okreslonych komorek [] tablicy, np od tablica[0] lecimy do zad rozmiaru do np tablica[x], no i stąd nie wiem skąd zaczynamy.
I linia nizej z inkrementacją, i tu problem z linijki wyzej, nie ma [] wiec jak zwiekszamy komorke tablicy?? #mind fck //

edytowany 6x, ostatnio: furious programming, 2018-12-04 19:51

Pozostało 580 znaków

2018-12-04 18:06
kq
2

Tak działa arytmetyka wskaźników - mając adres zmiennej w pamięci równie dobrze może być to pierwszy element tablicy jak i po prostu jedna zmienna.

Tak zostało to rozwiązane w C i tak zostało zaimportowane do C++.

mając taki wskaźnik, wiedz o kilku rzeczach:

  • tablica+1 doda do wskaźnika długość jednego elementu (nie bajtu!), więc będzie wskazywać na następny element tablicy (o ile to jest rzeczywiście tablica)
  • *tablica to dereferencja
  • tablica[n] to to samo co *(tablica+n)

BTW: https://dsp.krzaq.cc/post/176[...]xx-kiedy-uzywac-new-i-delete/


Pozostało 580 znaków

2018-12-04 18:16
0

Czyli jesli dobrze rozumiem, mozemy "inkrementowac" zmienna o nazwie tablica?, bo ona jest takze adresem pierwszej komorki tablicy? i "zwiekszając" zmienna dostajemy sie danej komorki?
Edit: Ale nadal chyba nie wiem jak z jednej zmiennej ze wskaznikiem powstala ich cala tablica..

edytowany 1x, ostatnio: Spark_of_hope, 2018-12-04 18:18

Pozostało 580 znaków

2018-12-04 18:18
kq
0

Zwiększając ją (a właściwie wykonując na niej operacje arytmetyczne) poruszasz się po tablicy.

Nie wiem czy podpasuje Ci ta analogia, ale wskaźnik to taki nr. domu na ulicy. Dodasz 1 to masz następny, odejmiesz to masz poprzedni, a żeby zobaczyć co jest w środku musisz wejść za pomocą *.


Pozostało 580 znaków

2018-12-04 18:27
0

wskaźnik to taki nr. domu na ulicy.

Dodałbym chyba, ze do domow sa przyczepione skrzynki, a w ich srodku jest nr domu xd, Ale to moje wyobrażenie:d
A co do poprzedniej Twojej odpowiedzi to wlasnie co by bylo gdybym dodal do zmiennej ze wskaznikiem +1 a to nie bylaby tablica?

Pozostało 580 znaków

2018-12-04 18:29
kq
0

To miałbyś tzw. UB, czyli niezdefiniowane zachowanie. Nie da się rzetelnie powiedzieć co się wtedy stanie, bo język tego nie definiuje. Ty, jako programista, masz do tego po prostu nie dopuścić.

To samo dotyczy np. wyjścia więcej niż 1 element poza koniec tablicy, lub próba dereferencji obiektu poza końcami tablicy.

Co do skrzynek to nie rozumiem za bardzo. Rozwijając analogię:

// PSEUDOKOD
Dom* krakowskie_przedmieście = 48; // pałac prezydencki, krakowskie przedmieście 48
krakowskie_przedmieście + 10; // adres krakowskie przedmieście 58
*krakowskie_przedmieście; // dereferencja, w tej analogii wchodzisz do pałacu prezydenckiego
krakowskie_przedmieście[0]; // to samo
krakowskie_przedmieście[10]; // wchodzisz do budynku pod adresem krakowskie przedmieście 58

edytowany 1x, ostatnio: kq, 2018-12-04 18:32

Pozostało 580 znaków

2018-12-04 18:31
0

Pomyslalem ze moze moglibysmy zmienic adres wskaznika o 1 bit:d

1 bajt miał być - Spark_of_hope 2018-12-04 19:08

Pozostało 580 znaków

2018-12-04 18:45
0

Co do skrzynek to nie rozumiem za bardzo.

Jesli chcesz zrozumieć jak ja mysle:):
Istnieje dom.
Istnieje jego adres w skrzynce, ale nwm jak ja otworzyc.
Tworze wskaznik z nazwą domu zeby moc otworzyc skrzynke i dostac sie do jego adresu-nr domu:d

edytowany 1x, ostatnio: Spark_of_hope, 2018-12-04 18:45

Pozostało 580 znaków

2018-12-04 18:55
kq
0

Nie, dostajesz się do zawartości, nie do adresu.

Może zamiast domów numerowane skrytki np. jak są na dworcach.

Numer skrytki to jej adres. Co jest w środku to zawartość. Adres możesz zwiększać/zmniejszać i będzie on wskazywał na różne skrytki. Po dereferencji uzyskasz zawartość skrytki.


edytowany 1x, ostatnio: kq, 2018-12-04 18:56

Pozostało 580 znaków

2018-12-04 19:05
0

No tak, ale uzywając nazwy wskażnika, odczytujemy adres, a uzywając operatora wskaźnika dostajemy sie do środka. Te analogie są do bani, cięzko to porównac, moje zdanie. Widzisz ja myslalem wcześniej o tym pierwszym dostaniu sie do skrzynki, a Ty do zawartości zmiennej, DAmn, cięzko użyc jednej analogii. Anyway dzięki za poświęcony czas, wracam do nauki.

Pozostało 580 znaków

2018-12-05 07:58

Bracie @Spark_of_hope traktuj może wskaźnik jako taki skrót do jakiejś danej w pamięci. Skrót ów możesz sobie nastawiać na dowolny typ dla którego go zdefiniowałeś, czyli jak na int to możesz odnosić się do int-ów, albo tablic intów. Jeśli używasz owego skrótu bez * to zmieniasz wskazanie na co pokazuje wskaźnik - te wszystkie +1, -1 co ci kq demonstrował.
Jeżeli chcesz sięgnąć "do wnętrza" wskaźnika aby zrobić coś z daną, na którą on wskazuje to wtedy używasz *.
Ot i cała filozofia.

Taka jeszcze dygresja odnośnie dynamicznych tablic:

    int *tablica;      // tutaj deklarujemy wskaznik wskazujacy typ int o nazwie tablica (jasne) //
    tablica = new int [rozmiar];  // a tutaj jest kosmos, nagle z jednego wskaźnika robi sie ich tablica, jak??:/ //

Magia polega na tym, że int *tablica umie wskazywać na element typu int, natomiast new int[ileśtam] powoduje, że pamięci tworzy się taka struktura leżących zaraz obok siebie intów:
| int1 | int2 | int3 | .... | int ileśtam |
i teraz *tablica wskazuje na int1. Ponieważ za 1 intem jest drugi to jak do tablica dodasz 1 co w języku C/C++ oznacza "przesuń wskaźnik *tablica o 1 wielkość elementu dla którego zostałaś zdefiniowana" spowoduje to, że teraz w *tablica będzie adres inta2. I tak aż do inta ileśtam.

Cyrk zacznie się dziać jak po przesunięciu *tablicy na inta ileśtam znów dodasz jeden lub więcej, albo kiedy *tablica wskazuje na inta1 a ty odejmiesz od niej 1 lub więcej.

W takim wypadku nie wiadomo, co znajduje się przed oraz za dynamicznie stworzoną tablicą, i czy masz dostęp do tej pamięci. Stąd sytuacja ta jest oznaczana jako Undefined Behavior.

Jeszcze jedna uwaga - jak tworzysz sobie dynamicznie tablicę to lepiej nie zmieniać wskaźnika który wskazuje na jej początek, bo nietrudno potem "zapomnieć" w programie gdzie się ona znajduje. Dlatego *tablicę w przykładowym programie lepiej zapisać tak:

int *const tablica = new int [rozmiar];

to gwarantuje, że nie przestawisz sobie przypadkiem wskaźnika *tablica na coś innego niż początek dynamicznej tablicy.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]
edytowany 1x, ostatnio: MasterBLB, 2018-12-05 08:00
Dzięki za dopowiedź, zaczynam coraz więcej rozumieć:) Dobra rada ta z nieprzesuwaniem pierwszego wskaźnika. Szkoda że nie istnieje zabezpieczenie, które samo by nie pozwalało odczytać element już nieznajdujący się w tablicy: tablica = tablica - 1 czyli taki błąd wysypie program.. bo przy próbie odczytania przykladowo*tablica będziemy próbowali odczytać zawartość, której wcześniej nie zdefiniowalśmy. :) - Spark_of_hope 2018-12-06 12:57
W czystym C/C++ nie ma, wymaga się od programisty, że ma świadomość problemu i we własnym zakresie zadba, żeby takich byków nie robić. Ponieważ jednak ludzie są tylko ludźmi, to i byków trzaskali takie ilości, że się w końcu co bardziej ogarnięci programiści C++ skrzyknęli, i stworzyli STL-a który nieco te bolączki łagodzi, i czyni życie dużo prostszym. - MasterBLB 2018-12-06 14:05

Pozostało 580 znaków

Liczba odpowiedzi na stronę

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