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
_13th_Dragon
cout &lt;&lt; foo(obj1,obj1)-&gt;value &lt;&lt; endl; - i co się stanie ;P
grzesiek51114
grzesiek51114
@_13th_Dragon i albo się wywali albo zadziała :) w zależności od tego czy autor wątku dostosuje się do mojego komentarza w kodzie :P
_13th_Dragon
Miejmy nadzieje że ktoś czyta komentarze, w kodzie lub do postu ;P
grzesiek51114
grzesiek51114
@_13th_Dragon wiesz... to taki glicz w razie gdyby zrobił kopiuj-wklej na laborkach :) Takie zabezpieczenie antypirackie :P
LU
Wywali się jak się odwołamy do pola wskaźnika który jest nullem. Zadziała gdy usuniemy "->value".
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:3 miesiące
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:około 6 godzin
  • 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...
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)