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

Struktura i wskaznik

0 głosów
550 wizyt
pytanie zadane 9 kwietnia 2018 w C i C++ przez lambdag Obywatel (1,310 p.)

Witam, chciałbym się upewnić czy dobrze myślę: mam taki pseudo kod:

struct node{
       int x;
       node *next;
}
void add(node *head){

}
int main()
{
    node *head = 0;
    add(head);
    return 0;
}

W takim sensie do funkcji add przesyłam nie orginalna strukturę tylko jej kopię?? Musiałbym dodać druga gwiazdkę lub referencje żeby to miało sens? Bo mógłbym zmienić funkcję żeby zwracała strukturę to wtedy miałoby to sens ale tak to nie? Dobrze to rozumiem..?

 

2 odpowiedzi

+1 głos
odpowiedź 9 kwietnia 2018 przez RafalS VIP (122,780 p.)
wybrane 9 kwietnia 2018 przez lambdag
 
Najlepsza

Nie. Działa to w ten sposób, że mając wskaźnik do struktury masz w pamięci dwa bloczki.
Wyobraź sobie to w ten sposób. Tworzysz sobie strukture typu node w normalny sposób: node n;. W tym momencie zostaje wydzielony blok w pamięci powiedzmy, że blok numer 69, w którym przechowywana jest ta struktura, wartość w tym bloku to int i node*, ich wartosci są losowe przed inicjalizacją. Teraz tworzysz wskaźnik do node:  node* wsk;. Rezerwujesz kolejny blok w pamięci na wskaźnik do node, powiedzmy, że pod adresem 80, wartość tego bloku jest randomowa, w momencie inicjalizacji sa tam jakieś smieci. I teraz chcesz, żeby ta zmienna (blok w pamięci) wskazywała Ci na twoją wcześniej utworzoną strukture (pamiętała adres w pamięci gdzie trzymana jest ta struktura). Robisz więc wsk = &n;. I wtedy wartość wsk wynosi 69. Gwiazdkując (dereferencując) ten wskaźnik trafiasz do twojej strukturki n. Jeśli zrozumiałeś ten wywód to będziesz już w stanie sam odpowiedzieć na pytanie co jest przekazywane do funkcji. Musisz jeszcze pamiętać, że argumenty funkcji są przekazywane przez wartość:

void fun(int x) { x = 100;}
int main(){
int a = 0;
fun(a); // a wciaz wynosi 0 bo funkcja pracuje na kopii zmiennej a
}

Wygląda to tak:

Bloki pamięci to kwadraty, w środku jest wartość, u góry nazwa zmiennej.

Nie wiem czy to widzisz, ale zmodyfikowałeś wartość innej zmiennej niż a, wartość innego bloku pamięci.

Na pewno widziałeś też taki kod:

void fun(int* x) {*x=100;}
int main(){
int a = 0;
int* wskaznik_na_a = &a;
fun(wskaznik_na_a); // wartosc a zmienia się
}

Tutaj też argument przekazywany jest przez wartość, ale tym razem wartość wskaźnika, a nie inta. Wrzucasz sobie inta do bloku pamięci o numerze 65 i przesyłasz wskaźnik do tego bloku. Dostajesz więc taką sytuacje:

Tym razem możesz modyfikować wartość a, bo masz dostęp do bloku pamięci, w którym jest nasza zmienna a.

A co jeśli będzie trzeba zmienić wartość samego wskaźnika, a nie wartość bloku na który ten wskaźnik pokazuje, jeśli zrobisz tak jak w pierwszym przypadku:

void fun(int* wsk){ wsk = 0;}

To dostaniesz coś takiego

Po wyjściu z funkcji zmienna kopia wsk znika, nie zmieniłeś więc wartości wskaźnika wsk. Idąc podobną logiką jak wcześniej, wystarczy, że dodasz gwiazdke i bedzie cacy:
 

void fun(int** wsk){ *wsk = 0;}

Teraz po wyjściu z funkcji wartość samego wskaźnika zmieni się, bo modyfikujesz blok pamięci w którym trzymana jest jego wartość.

 

 

Po krótkim wstępie wracając do Twojego przykładu: po pierwsze to nie jest pseudokod tylko C / C++ :P.
Całe to zamieszanie można rozwiązać korzystając z referencji, które są dostępne w C++, w C nie. Referencje to tak jakby druga nazwa na tą samą zmienną (ten sam blok w pamięci), wtedy możesz modyfikować jej wartość normalnie:

void fun(int& x){x=100;}

i wartość zmiennej przesłanej do funkcji zmieni się po wywołaniu funkcji.

A jeśli chodzi o wskaźniki, to jeśli nie rozumiesz tego co próbowałem wyjaśnić to musisz pamiętać jedynie tyle, że jeśli chcesz zmodyfikować argument to musi to wyglądać w ten sposób:
chcesz zmodyfikować inta to musisz przeslać int* wsk i zmodyfikować *wsk. Chcesz zmienić sam wskaźnik to musisz przesłać int** i podobnie zmodyfikować *wsk itd z dowolną ilością gwiazdek.

Mam nadzieję, że cokolwiek rozjaśniłem.

komentarz 9 kwietnia 2018 przez lambdag Obywatel (1,310 p.)
Dobrze wyjaśniłeś wlasnie o to mi chodziło chyba źle wyslowilem w pytaniu :D
+1 głos
odpowiedź 9 kwietnia 2018 przez Bondrusiek Maniak (61,440 p.)

Witam,

używając wskaźnika jako argument funkcji można przesłać oryginalną strukturę. Przykład w C++

#include <iostream>

using namespace std;

struct node{
       int x;
       node *next;
};

void add(node *head){
    cout << "x " << head->x << endl;
    head->x += 1;
}

int main()
{
    node *head;
    head = new node();
    head->x = 1;
    add(head);
    add(head);
    delete head;
    return 0;
}

 

Podobne pytania

0 głosów
2 odpowiedzi 1,264 wizyt
pytanie zadane 10 sierpnia 2018 w SQL, bazy danych przez mi-20 Stary wyjadacz (13,250 p.)
0 głosów
1 odpowiedź 910 wizyt
pytanie zadane 11 czerwca 2018 w SQL, bazy danych przez emeryt68 Nowicjusz (130 p.)
0 głosów
1 odpowiedź 344 wizyt

93,772 zapytań

142,730 odpowiedzi

323,382 komentarzy

63,368 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

Twierdza Linux. Bezpieczeństwo dla dociekliwych

Aby uzyskać rabat -10%, użyjcie kodu pasja-linux, wpisując go w specjalne pole w koszyku.

...