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

question-closed Wskaźniki w c++ - pytania ...

Object Storage Arubacloud
0 głosów
356 wizyt
pytanie zadane 29 czerwca 2017 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)
zamknięte 29 czerwca 2017 przez Jakub 0

Witam ,już drugi raz przerabiam kurs P.Mirosława zanim będę poznawał programowanie obiektowe . Wcześniej przyznam że uczyłem się tak byle było (dlatego powtarzam też ten kurs). Teraz bardziej wnikam w bardziej szczegóły ,jestem na etapie wskaźników i jest to dla mnie jak i dla wielu innych prawdziwa zmora frown. Mam do wskaźników kilka pytań i fragmentów kodu które nie rozumiem w tym również te z kursu . Dziękuje wam za wszelkie zainteresowanie i pomoc :

Zapis z użyciem gwiazdki i bez :

wiem że przy użyciu gwiazdki pracujemy na wartości zmiennej na którą wskazuje wskaźnik a bez niej na wskaźniku , czyli możemy go przesunąć o kilka bajtów do przodu i przestawić na inną szufladkę w tablicy ...

Jak więc wytłumaczyć poniższy fragmenty kodu z kursu gdzie gwiazdka jest użyta nawet do przesunięcia wskaźnika na inną wartość :

for(int i=0; i<n; i++)
    {
        *wskaznik=i;
        *wskaznik+=50;
        *wskaznik++;    //jakim prawem to działa skoro jest tu gwiazdka ??
    }

Sposoby wykonywania operacji na wskaźnikach :

używając dynamicznej alokacji :

int n=10;

int *w = new int[n];

możemy użyć tej tablicy do operacji w pętlach :

for(int i=0; i<n; i++)
{
        cout<<w;
        w++;
}

a pod spodem inny zapis :

for(int i=0; i<n; i++)
{
        cout<<w[i];
}

czy te zapisy się czymś różnią ? Np w drugim przykładzie następują błędy przy pokazywaniu adresu jakie powinna wyświetlać tablica a przy pierwszym chodzi wszystko ok . Z kolei do sortowania by pracować na orginalnych zmiennych użyjemy tej drugiej metody od czego to zależy ?

Wiem że te dylematy wynikają z mojej nie wiedzy ale proszę o wyrozumiałość :)

komentarz zamknięcia: już znam odpowiedź
1
komentarz 29 czerwca 2017 przez vector Dyskutant (9,200 p.)

czy te zapisy się czymś różnią ?

Tak mianowicie można obrazować działanie w[i] jako *(w+i) czyli w[i] zwraca wartość i-tego elementu w rezultacie w przykładzie pierwszym wypiszesz adresy wszystkich elementów tablicy a w drugim wartości wszystkich elementów tablicy.

komentarz 29 czerwca 2017 przez Jakub 0 Pasjonat (23,120 p.)
dzięki ,wreszcie już to jakoś zrozumiałem  . Czyli masz też na myśli że taki zapis :

*tab++;

rożni się od tego:

tab++;

że ten wyższy pokazuje kolejno wartości a drugi adresy zmiennych na których pracuje ? Wiem że już mogłeś mi na to pytanie udzielić odpowiedź ale już chce być przekonany że to zrozumiałem .
komentarz 29 czerwca 2017 przez Buby Pasjonat (19,590 p.)
Pierwszy oznacza dosłownie: zwróć wartość spod adresu i przesuń wskaźnik.

Drugi oznacza tylko: przesuń wskaźnik.

1 odpowiedź

+3 głosów
odpowiedź 29 czerwca 2017 przez Buby Pasjonat (19,590 p.)
edycja 29 czerwca 2017 przez Buby
 
Najlepsza

Hej smiley Już wszystko tłumaczę. Zapis *nazwa_wskaznika++ oznacza to samo co dwie kolejne operacje, czyli *nazwa_wskaznika; nazwa_wskaznika++; Postinkrementacja następuje przed operacją wyłuskania, lecz działa następująco - co prawda zwiększa wskaźnik, lecz odczyt wartości początkowej ma miejsce dla jej starej wersji. Przykład:

int i = 0;
std::cout << i++;  //wyswietla 0, ale po tej instrukcji i ma wartosc 1
std::cout << i; //wyswietla 1

Akurat w tej pętli, którą zaprezentowałeś można się pozbyć wyłuskania przy inkrementacji i nie powinno to zmienić wyniku programu. (własciwie nie wiem, dlaczego ta gwiazdka się tam znalazła - być może, żeby pokazać, że w ten sposób nie zmodyfikuje się wartości, która znajduje się pod danym adresem, tylko zmodyfikuje się sam wskaźnik).

Przykład, który to obrazuje:

#include <iostream>

int main() {
    int a[2] = {0, 7};
    
    int* wskaznik_1 = a;
    std::cout << "PRZYKLAD_1" << std::endl;
    std::cout << "Wyswietl wartosc na ktora wskazuje wskaznik_1 i przesun go o 1 adres.\n" \
    << "Postinkrementacja wykonuje sie po odczytaniu wartosci." << std::endl;

    std::cout << "Pierwszy element: " << *wskaznik_1++ << std::endl;
    std::cout << "Kolejny element: " << *wskaznik_1 << std::endl;

    std::cout << "\n\nTo samo, rozbite na dwie operacje" << std::endl;

    int* wskaznik_2 = a;
    std::cout << "PRZYKLAD_2" << std::endl;
    std::cout << "Wyswietl wartosc na ktora wskazuje wskaznik_2 i przesun go o 1 adres.\n";

    std::cout << "Pierwszy element: " << *wskaznik_2 << std::endl;
    wskaznik_2++;
    std::cout << "Kolejny element: " << *wskaznik_2 << std::endl;

    return 0;
}

Gdy skompilujesz ten program, to wyniki obu przykladów będą identyczne.

 

A teraz odnośnie drugiego pytania - Twój drugi przykład wyświetlania, nie wyświetla adresów, tylko wartości, a skoro nie zainicjalizowałeś elementów tablicy, to wyświetlasz śmieci z pamięci. Twoje wyświetlanie powinno wyglądać tak:

for(int i=0; i<n; i++)
{
        cout<<&w[i];
}

Zapis w[i] jest równoznaczny z *(w + i), zwraca on wartość, stąd nie wyswietlał adresów, tylko śmieci z pamięci. Jest to uproszczenie, ponieważ tablica w C++ to jakiś blok w pamięci. Przy zapisie:

int tablica[5] = {1, 2, 3, 4, 5};

int* wskaznik = tablica;

Wskaźnik będzie zawierał adres pierwszego elementu tablicy, tj. &tablica[0].

Więc stąd zapis tablica[3] jest równoznaczny z *(tablica + 3).

 

Kiedy przekazujesz do funkcji zmienną "tablicową", to tak na prawdę przekazujesz adres w pamięci na jej pierwszy element, dlatego późniejszy zapis z użyciem nawiasów kwadratowych działa, bo przesuwasz się w pamięci na kolejne, oryginalne dane.

 

W razie niejasności pytaj - postaram się uprościć albo podać jakiś sample code.

Pozdrawiam! smiley

komentarz 29 czerwca 2017 przez Jakub 0 Pasjonat (23,120 p.)

dzięki za cierpliwość i dokładne wytłumaczenie laugh . Przyznam że jeszcze trochę mi zajmie dokładne przyswojenie sobie wskaźników ale powoli jakoś to będzie. Nigdy nie lubiałem zwłaszcza wskaźników i rekurencji

3
komentarz 29 czerwca 2017 przez unknown Nałogowiec (39,560 p.)

Inkrementacja następuje po operacji wyłuskania. 

Na odwrót. Operator inkrementacji ma pierwszeństwo.  

komentarz 29 czerwca 2017 przez Jakub 0 Pasjonat (23,120 p.)
czyli to oznacza że po takim kodzie :

int *wsk = a; //na zerowy element (a to tablica)

cout<<*a++; //inkrementujemy i wyłuskujemy

zostanie wyświetlona nie zerowa lecz pierwsza szufladka w tablicy skoro najpierw jest wykonywana inkrementacja  ??
1
komentarz 29 czerwca 2017 przez Buby Pasjonat (19,590 p.)
Kolega wyżej ma rację z kolejnością operacji, ale mój przykład kodu był poprawny.

Program wykona się tak jak to opisałem, z tym, że postinkrementacja zwraca kopie. Możesz to sobie wyobrazić w ten sposób [mniej więcej].

Załóżmy, że operator++, wywołuje funkcję. Wtedy ta funkcja miałaby taki wygląd:

1. Zapisz do zmiennej tymczasowej wartość na której wywołujesz operator.

2. Zwiększ wartość na której wywołujesz operator.

3. Zwróć wartość tymczasową z punktu 1.

Wtedy odczytujesz wartość, która została zapisana jako tymczasowa, ale faktyczny wskaźnik ma już nową wartość.

 

Kolejność wypisywania pokazana w przykłądach jest dobra - po prostu ja opisałem to w sposób, który dla osoby początkującej jest łatwiejszy do zrozumienia, lecz niekoniecznie jest to prawidłowy tok rozumowania [faktycznie, w dalszej nauce mogłoby to nieść problemy i post edytuję]
komentarz 30 czerwca 2017 przez Jakub 0 Pasjonat (23,120 p.)
Dzięki , trochę to skomplikowane ale puki co rozumiem

Podobne pytania

0 głosów
1 odpowiedź 162 wizyt
pytanie zadane 25 stycznia 2022 w C i C++ przez Author[] Gaduła (3,130 p.)
0 głosów
1 odpowiedź 657 wizyt
pytanie zadane 30 kwietnia 2020 w C i C++ przez Eriss69 Gaduła (4,470 p.)
0 głosów
1 odpowiedź 847 wizyt

92,551 zapytań

141,393 odpowiedzi

319,523 komentarzy

61,936 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!

...