Zwracanie referencji w C/Struktury

Zwracanie referencji w C/Struktury
LU
  • Rejestracja:około 9 lat
  • Ostatnio:około 9 lat
  • Postów:11
0

Hej!
Mam mały problem z zadaniem. Ma być funkcja która przyjmuje jako argumenty referencje do typu struktury. Funkcja ma sprawdzać pewne rzeczy i- zwracać referencję do pierwszego obiektu albo NULL. Pytanie i problem jest takie- jak zwrócić NULL'a? No i jak będzie wygladała deklaracja i definicja?

Struktura& foo(Struktura& obj1, Struktura& obj2)
czy
Struktura foo(Struktura& obj1, Struktura& obj2)?
Mnie się wydaje, że ta druga opcja, bo skoro przyjmujemy referencję to możemy normalnie zwrócić obj1 w returnie jeżeli zajdą te odpowiedni warunki.
Ale w przeciwnym wypadku co? Jakim cudem można zwrócić NULL'a skoro trzeba mieć w returnie l-wartość, a null jest p-wartoscia?

grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
4

W C nie ma czegoś takiego jak referencje.

Jeżeli taka jest treść zadania to pewnie wykładowca cierpi na częsty dosyć syndrom mieszania C z C++.

edytowany 2x, ostatnio: grzesiek51114
LU
  • Rejestracja:około 9 lat
  • Ostatnio:około 9 lat
  • Postów:11
0

Wiem, ale zadanie to zadanie... oficjalnie to jest C, ale to ma być "przechodzenie w C++". Więc uznajmy, że takie zadanie jest. Nie rozumiem tylko jakim cudem zwrócić NULL'a?

L0
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 2 lata
3

coś ci się chyba pomieszało i miało być na wskaźnikach. możesz spokojnie zwrócić wskaźnik o wartości NULL.

grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0
Kopiuj
struct test* foo(const struct test* obj1, const struct test* obj2);

...i śmiało możesz zwrócić NULL.

LU
  • Rejestracja:około 9 lat
  • Ostatnio:około 9 lat
  • Postów:11
0

Stwórz funkcję foo. Jako argumenty przyjmuje ona przez referencje
dwie zmienne typu STRUKTURA, a następnie sprawdza ... Jeżeli tak, funkcja zwraca referencję do większego obiektu. Jeśli nie, zwraca NULL.

Nie pomieszało mi się... gdyby to było na wskaźnikach to bym nie zadawał pytania. To jest zadanie, uciąłem to co niepotrzebne.

L0
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 2 lata
1

tylko wskaźniki mogą przyjmować null, więc zadanie jest błędne

grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
4

Nie możesz tak zrobić!

Nie da się zwrócić nullptr jako test& jeżeli test to 'struct test'.
Tak kod zwróci błąd kompilatora:

Kopiuj
test& foo(test& obj1, test& obj2){
    if(obj1.value > obj2.value) return obj1;
    else if(obj1.value < obj2.value) return obj2;
    return nullptr;
}

Ale taki już nie:

Kopiuj
#include<iostream>
using namespace std;

struct test{
    int value;
    test(int val):value(val){}
};

const test* foo(const test& obj1, const test& obj2){
    if(obj1.value > obj2.value) return &obj1;
    else if(obj1.value < obj2.value) return &obj2;
    return nullptr;
}

void print(const test* obj){
    if(obj) cout << obj->value << endl;
}

int main(){
    test obj1(10);
    test obj2(10);

    print(foo(obj1,obj2));
    return 0;
}
edytowany 4x, ostatnio: grzesiek51114
Zobacz pozostałe 5 komentarzy
grzesiek51114
grzesiek51114
@lukasson, @_13th_Dragon: purysty się znalazły. aż poprawiłem :P
_13th_Dragon
Drobna uwaga to nie powód aby od purystów wyzywać ;P
grzesiek51114
grzesiek51114
@_13th_Dragon wiesz... to raczej komplement nazwać kogoś purystą :)
_13th_Dragon
@grzesiek51114, podejdź do Pudziana nazwij go misiaczkiem po czym spróbuj zdążyć wytłumaczyć że to był komplement ;P
grzesiek51114
grzesiek51114
@_13th_Dragon challenge accepted :P
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:dzień
3

Kiedy ćwiczenia z C prowadzi javoviec to wszystkie wskaźniki nazywa referencja - może to jest klucz.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
Zobacz pozostałe 9 komentarzy
grzesiek51114
grzesiek51114
@_13th_Dragon typ referencyjny :)
_13th_Dragon
@grzesiek51114 - pedant ;P
grzesiek51114
grzesiek51114
@_13th_Dragon purysta :P
Azarien
w C# są: 1. wskaźniki, np. int*, 2. typy referencyjne, np. class Foo, 3. parametry funkcji przekazywane przez referencję, np. void foo(ref Foo param).
grzesiek51114
grzesiek51114
@Azarien ależ nikt temu nie zaprzeczał przecież. Później i tak wszyscy robili sobie żarty ;-)
LU
  • Rejestracja:około 9 lat
  • Ostatnio:około 9 lat
  • Postów:11
2

Istnieje też szansa, że koleś po prostu podpuszcza i specjalnie każe zrobić coś czego się nie da. Więc olewając sprawę zwracania nulla definicja powinna być test& foo(test&, test&)?

LU
  • Rejestracja:około 9 lat
  • Ostatnio:około 9 lat
  • Postów:11
0

Dzięki wielkie, można zamknąć! :)

grzesiek51114
grzesiek51114
Sam zamknij. Zaakceptuj wybraną odpowiedź po prostu.
LU
Chciałem być kulturalny, dostaniesz "ptaszka" :p
grzesiek51114
grzesiek51114
Dziękuję :)
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
1

@lukasson daj w ogóle znać o co temu ćwiczeniowcowi chodzilo jak już zaliczysz. Tak z ciekawości.

PS: Jeżeli w ogóle się tutaj jeszcze u nas pojawisz :-)

_13th_Dragon
Popieram, też jestem ciekaw.
LU
Pojawię się, jak się dowiem o co chodziło to oczywiście się odezwę ;)
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:dzień
  • Lokalizacja:Szczecin
0

Użycie null-referencji to UB w C++, więc kompilator może - i faktycznie tak robi - zadecydować, że się to nigdy nie zdarzy i pominąć takie sprawdzenie.

http://goo.gl/b5zvnv


JP
Na pewno jest to UB? Referencje "by design" nie są NULL więc jak? Chyba ze chodzi o zamą dereferencje NULL pointera.
kq
No właśnie. Standard mówi: § 8.5.3 [dcl.init.ref] / 1 A variable declared to be a T&amp; or T&amp;&amp;, that is, “reference to type T” (8.3.2), shall be initialized by an object, or function, of type T or by an object that can be converted into a T.
kq
I jeszcze jak by to było niedostatecznie czytelne: § 8.3.2 [dcl.ref] / 5 A reference shall be initialized to refer to a valid object or function.
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0

W zadaniu jest błąd, chodziło o wskaźnik, a nie referencję.
Referencję nullową można zwrócić, ale nikt tak nie robi.

Referencja to taki wskaźnik, który jak wspomniano wyżej generuje UB dla kodu który kompilator potrafi dogłębnie przetestować.
Jeśli nie potrafi, to spokojnie może przechowywać nullptr.
Taki "urok" C++.

Jak zrobić i sprawdzić bezpiecznie referencję z wartością nullptr (anty-przykład):
http://www.foundbit.com/en/resources/languages/cpp/expert/articles/cpp-avoid-null.html

edytowany 1x, ostatnio: vpiotr
pingwindyktator
ten artykuł podlinkowany to jest jakiś wtf
kq
Dziwny ten podlinkowany artykuł. Niekompilujący się kod (zwracanie interfejsu przez kopię), przestarzały kod, który nie powinien się kompilować (string literal ⟶ char*), błędne stwierdzenia (użycie null referencji to zawsze UB), uznanie braku dowodów jako dowodów braku (słaba kalka językowa, wiem), niewygodny kod (pusty boost::optional można zwrócić z boost::none lub po prostu {}).
0

???

Kopiuj
/*
 Stwórz funkcję foo.
 Jako argumenty przyjmuje ona przez referencje
 dwie zmienne typu STRUKTURA,
 a następnie sprawdza ...
 Jeżeli tak, funkcja zwraca referencję do większego obiektu.
 Jeśli nie, zwraca NULL.
*/
#include <iostream>
using namespace std;

typedef struct{
	int a;
} STRUKTURA;

STRUKTURA& foo(STRUKTURA& obj1, STRUKTURA& obj2){
	if(obj1.a == obj2.a)
		return *((STRUKTURA*)NULL);
	
	return obj1.a > obj2.a ? obj1 : obj2;
}

int main(){
	STRUKTURA s1, s2;
	
	cout << "addr s1 :" << &s1 << endl;
	cout << "addr s2 :" << &s2 << endl;
	
	s1.a = 1;
	s2.a = 2;
	cout << "test 1, 2: " << &foo(s1, s2) << endl;
	
	
	s1.a = 2;
	s2.a = 1;
	cout << "test 2, 1: " << &foo(s1, s2) << endl;
	
	s1.a = 3;
	s2.a = 3;
	cout << "test 3, 3: " << &foo(s1, s2) << endl;
	
	return 0;
}
Zobacz pozostałe 3 komentarze
_13th_Dragon
Jak na razie nie znam żadnego kompilatora na żadnej platformie który by spowodował że powyższy kod zostanie wykonany niezgodnie z oczekiwaniem ćwiczeniowca, Nie zmienia to jednak faktu że jest to co najmniej ryzykowne zagranie oraz nie należy tego studentom pokazywać, no chyba że z zastrzeżeniem/przekazem: - MOŻE JEDNAK LEPIEJ TAK NIE ROBIĆ.
kq
Kliknij mój link ;)
_13th_Dragon
Ostrzeżenie na takie rzeczy być powinno. Aczkolwiek niestety nie każdy umie czytać ;P
kq
Ostrzeżenie jest. Ale porównanie z nullem kompilator uznaje za fałszywe, nawet jeśli złamiesz reguły i jakoś tego nulla tam wpakujesz.
_13th_Dragon
Owszem clang jest "sprytny" ale programista i tak sprytniejszy: http://melpon.org/wandbox/permlink/FY5n3db6J8aFTSB7 - podkreślam, mimo to wszystko podtrzymuję: - MOŻE JEDNAK LEPIEJ TAK NIE ROBIĆ
0

Tak włączona, optymalizacja psuje motyw ;)

LU
  • Rejestracja:około 9 lat
  • Ostatnio:około 9 lat
  • Postów:11
0

Ta, trochę inne jest rozumienie referencji. Po prostu... parametr przekazany przez referencję to nie deklaracja i definicja ze znakiem &, tylko wywołanie funkcji przez znak &. Czyli tak naprawdę - przekazanie przez referencję to przekazanie przez wskaźnik, a przekazanie przez wartość to normalne odpalenie funkcji... No tak.

Zobacz pozostałe 2 komentarze
_13th_Dragon
Nadal jest to normalne odpalenie funkcji, i nie rozumiem o jaką interpretację ci chodzi.
LU
Z tego polecenia które podałem napisałbyś: STRUKTURA& foo(STRUKTURA& obj1, STRUKTURA& obj2). Zwracanie nulla byłoby idiotyczne. Bo tak jest zadanie napisane i tak większość ludzi to interpretuje. Ale dla kogoś "referencja" to nie jest ampersand przy definicji|deklaracji tylko przy wywolaniu funkcji. Więc deklaracja wyglądałaby tak: STRUKTURA* foo(STRUKTURA* obj1, STRUKTURA* obj2); bo przekazując parametry do funkcji i ją wywołując napiszesz: foo(&param1, &param2); - i dla tej osoby "przekazanie" przez referencję odbywa się w momencie odpalenia funkcji, wywołania.
LU
Więc return robisz po prostu obj1 albo obj2
vpiotr
@lukasson w tym wywolaniu nie ma referencji tylko wyłuskanie adresu. https://msdn.microsoft.com/en-us/library/64sa8b1e.aspx
LU
@vpiotrr ale ja to wiem... ludzie byli ciekawi jak w końcu miało być zrobione to zadanie. Nie moja wina że tak to przez kogoś było rozumiane...

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.