"Dziwny" program z referencjami w C++

0

Witam. Muszę zrobić pewne ćwiczenie z c++ z referencjami. Program ma wyglądać tak, że robimy strukturę o nazwie batonik z trzema polami. Następnie tworzymy trzy nowe zmienne odpowiadające tym polom ze struktury, które musimy przekazać do funkcji i przez referencje zmodyfikować tą strukturę. Zadanie już zrobiłem, ale na początku źle zrozumiałem treść zadania i zamiast funkcji void zrobiłem funkcje zwracająca referencję na strukturę. Jednak pierwszy program też po części zadziałał, jednak pojawił się jakiś błąd z polem marka. Generalnie kod wygląda tak:

#include <iostream>
#include <string>

using namespace std;

struct batonik
{
    string marka = "abcd";
    float waga = 1.5;
    int kalorie = 3;

};

batonik & funkcja(string m, float w, int k);

int main()
{
    string a = "Snickers";
    float b = 12.5;
    int c = 250;

    batonik struktura;

    batonik & referencja = struktura;

    cout<<"Wartosc struktury batonik st: "<<endl;
    cout<<"Nazwa: "<<struktura.marka<<endl;
    cout<<"Waga: "<<struktura.waga<<endl;
    cout<<"Kalorie: "<<struktura.kalorie<<endl;

    referencja = funkcja(a, b, c);

    cout<<"\nWartosc struktury batonik st po funkcji: "<<endl;
    cout<<"Nazwa: "<<struktura.marka<<endl; //po funkcji zawartosc tej zmiennej jest zbugowana, pozostale sa ok
    cout<<"Waga: "<<struktura.waga<<endl;
    cout<<"Kalorie: "<<struktura.kalorie<<endl;

    return 0;
}

batonik & funkcja(string m, float w, int k)
{
    batonik fst; //tworze strukture typu batonik

    batonik & rf = fst; //tworze referencje typu batonik i przypisuje jej strukture batonik fst

    rf.marka = m; //zmieniam dane za pomoca referencji rf
    rf.waga = w;
    rf.kalorie = k;
   
    cout<<"\nfst.marka: "<<fst.marka<<endl; //dane zostaly zamienione przez referencje rf, bo wyswietlaja sie poprawnie
    cout<<"fst.waga: "<<fst.waga<<endl;
    cout<<"fst.kalorie: "<<fst.kalorie<<endl;

    return rf;
}

Program działa, jednak zmienna struktura.marka po wywołaniu funkcji jest zbugowana (w moim przypadku pojawia się nazwa Snic <). Pole waga i kalorie zostały dobrze zmienione. Wiem, że program z zadania miał tak nie wyglądać, bo funkcja miała być typu void, ale zastanawia mnie, co jest tutaj źle, że zmienna struktura.marka jest zbugowana.

I jeszcze jedno: jak zwracamy referencje, to wynik funkcji musimy przypisać też do referencji, zgadza się? Czyli powyższy kod:

batonik & referencja = struktura;
referencja = funkcja(a, b, c);

Jest ok?

3

I jeszcze jedno: jak zwracamy referencje, to wynik funkcji musimy przypisać też do referencji, zgadza się?

Nie.

Twój kod jest zły, bo zwracasz referencję do zmiennej lokalnej - a to UB.

0
kq napisał(a):

I jeszcze jedno: jak zwracamy referencje, to wynik funkcji musimy przypisać też do referencji, zgadza się?

Nie.

Twój kod jest zły, bo zwracasz referencję do zmiennej lokalnej - a to UB.

Zmodyfikowałem kod w taki sposob:

#include <iostream>
#include <string>

using namespace std;

struct batonik
{
    string marka = "qwertyabcd";
    float waga = 1.5;
    int kalorie = 3;

};

batonik & funkcja(string m, float w, int k, batonik & x);

int main()
{
    string marka = "Snickers";
    float waga = 12.5;
    int kalorie = 250;

    batonik st;

    batonik & referencja = st;

    cout<<"Wartosc struktury batonik st: "<<endl;
    cout<<"Nazwa: "<<st.marka<<endl;
    cout<<"Waga: "<<st.waga<<endl;
    cout<<"Kalorie: "<<st.kalorie<<endl;

    referencja = funkcja(marka, waga, kalorie, st);

    cout<<"5: "<<referencja.marka<<endl;

    cout<<"\nWartosc struktury batonik st teraz: "<<endl;
    cout<<"Nazwa: "<<st.marka<<endl;
    cout<<"Waga: "<<st.waga<<endl;
    cout<<"Kalorie: "<<st.kalorie<<endl;


    return 0;
}

batonik & funkcja(string m, float w, int k, batonik & x)
{
    batonik & rf = x;

    rf.marka = m;
    rf.waga = w;
    rf.kalorie = k;

    cout<<"1: "<<m<<endl;
    cout<<"2: "<<x.marka<<endl;
    cout<<"3: "<<rf.marka<<endl;

    return rf;
}

Dodałem czwarty parametr, czyli referencje typu batonik i to ja zwróciłem przez return. Teraz już działa. Tak może być?
I jeszcze jedno: skoro wtedy nie działało, to dlaczego akurat przypisało poprawnie nową wagę i liczbę kalorii batonika? Jakiś problem z danymi w pamięci?

0

UB to UB, może stać się wszystko. Jak nic tego nie nadpisało to dane zostały odczytane "poprawnie".

Teraz jest poprawnie. Ale dlatego nie podobało mi się, że uczą Cię, że referenca to zmienna. Referencja to nie zmienna, chyba że rozumiesz ją jako oryginalna zmienna, do której jest zbindowana.

0
kq napisał(a):

Teraz jest poprawnie. Ale dlatego nie podobało mi się, że uczą Cię, że referenca to zmienna. Referencja to nie zmienna, chyba że rozumiesz ją jako oryginalna zmienna, do której jest zbindowana.

Nie mogę używać określenia "zmienne referencyjna"? A jaka jest Twoja definicja referencji? Alias do innej zmiennej? Bardziej "elegancki" wskaźnik?

1

Rzecz w tym, że rozumienie referencji jako wskaźnika potrafi być szkodliwe, nawet jeśli rzeczywiście tak jest to zaimplementowane. Referencja lub alias może być, zmienna referencyjna implikuje, że jesteś w stanie odróżnić a od b w poniższym przykładzie (albo przypisać b do innej zmiennej):

int a = 42;
int& b = a;
0
kq napisał(a):

Rzecz w tym, że rozumienie referencji jako wskaźnika potrafi być szkodliwe, nawet jeśli rzeczywiście tak jest to zaimplementowane. Referencja lub alias może być, zmienna referencyjna implikuje, że jesteś w stanie odróżnić a od b w poniższym przykładzie (albo przypisać b do innej zmiennej):

int a = 42;
int c = 10;
int &b = a;

Bo należy je rozumieć jako stały wskaźnik.
A przestawić referencję się da, ale to już trzeba hacków asemblerowych:

lea eax, c;// ewentualnie rax na systemie 64bit
mov b, eax;// teraz w b jest adres c

Jak się pisze w C/C++ jak Swaróg przykazał to się uznaje, że referencje są nieprzestawialne aby ich rozumienia sobie nie gmatwać.

1

Nie da się, bo referencja może być kompletnie ominięta i wtedy nie ma żadnego przestawiania.

0

O i proszę:
CzaryMary.PNG
Wymagany kompilator MSVC, albo przeróbka składni asm na stosowaną w g++.

0

A teraz skompiluj z optymalizacją.

1

Proszę:
CzaryMary v2.PNG
Ale moment kq, dzień wcześniej tłumaczyliśmy komuś referencje w sposób wskaźnikowy - to nie był czasem autor tego wątku??
EDIT: tak, to on.

Ok, koniec offtopu.

Popełniłeś Bracie @kario97 nieduży błąd:

/*batonik&*/ void funkcja(string m, float w, int k, batonik &x)
{
    //batonik &rf = x; //<- to nie jest potrzebne
 
    //rf.marka = m;
    //rf.waga = w;
    //rf.kalorie = k;
    x.marka = m;
    x.waga = w;
    x.kalorie = k;
 
    cout<<"1: "<<x.kalorie<<endl;
    cout<<"2: "<<x.marka<<endl;
    cout<<"3: "<<x.waga<<endl;
 
    //return rf; < nie ma potrzeby zwracać
}

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