dowolny wskaźnik

dowolny wskaźnik
YA
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 12 lat
  • Postów:36
0

Dzień dobry.

Mój problem dotyczy wskaźników.
Np:

Kopiuj
wchar_t* zm1;
wchar_t** zm2;
wchar_t*** zm3;
//...
wchar_t/*n[*]*/ zm_n;

Przepraszam za ten zapis ale myślę, że wiecie o co mi chodzi (ostatnia linia). Jak stworzyć wskaźnik o dowolnej ilości "zagnieżdżeń" wiedząc jednak ile tych "zagnieżdżeń" ma być (parametr podany w konstruktorze np. jakiejś klasy).
Gdyby makra miały jakiś mechanizm pętli byłoby możliwe sklejenie takiego wyrażenia. Szukałem w sieci jakiegoś rozw. ale bezskutecznie.

ZJ
  • Rejestracja:około 14 lat
  • Ostatnio:prawie 12 lat
1

Chciałem już napisać, że się nie da, ale na szczęście (niestety dla ludzi, którzy pracują nad utrzymaniem kodu) w C++ można zastosować lepsze makra, czyli szablony.

Kopiuj
 
template <class T,int n>
struct MultiStarPointer 
{
	typedef typename MultiStarPointer<T,n-1>::pointer *  pointer;
};
 
template <class T>
struct MultiStarPointer<T,0> 
{
	typedef T pointer;
};

int main(){
  MultiStarPointer<char,1>::pointer p;
	char * v;
	p=v;
	MultiStarPointer<int,3>::pointer pi3;
	int*** pi3test;
	pi3=pi3test;
}

Ogólnie to po co tobie takie rozwiązanie. Jeżeli potrzebujesz tworzyć dużo różnych wskaźników ("wielo gwiaździstych"), to bym się zastanowił nad strukturą kodu oraz czy nie można tego problemu rozwiązać w inny sposób.

rafal__
"bym się zastanowił nad strukturą kodu oraz czy nie można tego problemu rozwiązać w inny sposób. " - np. drzewo
ZJ
W drzewie każdy wierzchołek przechowuje wskaźnik do wierzchołków dzieci, więc potrzebujesz tylko jedną "gwiazdkę" (ewentualnie dwie dla bardziej ogólnego drzewa, tj z tablicą dzieci).
YA
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 12 lat
  • Postów:36
0

Dziękuję za odp. Nie wiedziałem, że tak się nawet da.
Natomiast czy przyjąłem dobre założenia, tego nie wiem. Chciałem zrobić najpospolitszą rzecz czyli tablicę n-wymiarową i zamknąć to w jakiejś klasie.
Ktoś zapyta o sens robienia takiego czegoś, przecież są gotowe rozw. jak np. boost multi arrays. To wszystko prawda, jednak chciałem stworzyć sobie coś takiego sam, dostosować do konkretnych potrzeb i przy okazji czegoś się nauczyć. Jeśli ktoś ma jakieś sugestie co do sposobu alokacji pamięci (lepszy sposób), niech pisze śmiało.

KA
  • Rejestracja:prawie 21 lat
  • Ostatnio:około 4 lata
  • Postów:1652
1

Można to rozwiązać na wiele sposób. Na ogół rozwiązania uniwersalne są gorsze.

  1. Czy liczba wymiarów w tej tablicy może ulegać zmienia? Tzn czy tablica @da może nagle stać się 3D?
  2. Czy liczba wymiarów tablicy jest ustalana w czasie kompilacji czy w czasie działania programu?
  3. Czy tablice mogą się rozszerzać? Jeżeli nie, to czy całkowite wymiary tablicy są ustalane w czasie kompilacji czy w czasie działania programu?
  4. Czy tablice będą w większości przypadków puste? Tzn np same zera dla tablic z liczbami (generalnie konstruktor domyślny). // dość istotne, zwłaszcza gdy tablice mogą być duże
  5. W nawiązaniu do poprzednio: Złożoność czasowa czy pamięciowa? Co optymalizować?

A najlepiej napisz do czego to ma być stosowane ;)

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:30 minut
3

Rozwiązanie zaproponowane przez Zjarka ma sporą wadę - dostanie się do elementu w tablicy n-wymiarowej wymaga zdereferencjowania n wskaźników.

Tablice wielowymiarowe o każdym wymiarze stałym (tzn np bez sytuacji, w której rzędy tablicy mają różną długość) można łatwo emulować za pomocą tablicy jednowymiarowej i schematu Hornera. Np:

Kopiuj
int a[A][B][C];
a[x][y][z] = v;
// ten kod jest równoważny z poprzednim
int b[A * B * C];
b[(x * B + y) * C + z] = v;

"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
msm
Fajne rozwiązanie - można to teraz zapakować w ładną klasę i cieszyć się obiektowością :)
YA
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 12 lat
  • Postów:36
0

Dziękuję za pomoc.
Liczba wymiarów tablicy jest stała, ich długość raczej też (nad tym jeszcze pomyślę ale raczej stała) i mogą to być wartości określone zarówno w czasie działania programu jak i kompilacji. Tablice nie będą puste (hm zdawało mi się, że w rzeczywistości tablica nigdy nie jest pusta). Mogą służyć do tymczasowego przechowania jakiś danych np inf. o modelu 3d, po spełnieniu swojej funkcji ulegną zniszczeniu lub do trzymania jakiś informacji dłuższy czas. Złożoność ... nie wiem czy dobrze rozumiem ale ważniejsza będzie tu raczej lepsza wydajność niż użycie pamięci. Wybaczcie mi braki w wiedzy.
Sprawdzę też pomysł Wibowita, ale czy tutaj można, po przeciążeniu operatora [], zastosować potem wyłuskanie jakiejś wartości np. przez zapis: tab3d[x][y][z]?

ZJ
Da się to zrobić, ale w tym przypadku o wiele prostsza jest notacja nawiasowa (x,y,z), na pewno prostsza do wydajnego napisania. Jeżeli zależy ci na wydajności i operacji na takich tablicach to użyj jakieś biblioteki opartej na macierzowych bibliotekach Fortrana, np. Armadillo.
YA
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 12 lat
  • Postów:36
0

Emulowanie tablicy fajny pomysł, jest tylko mały problem związany z narzutem w postaci dodatkowych obliczeń podczas pobierania jakiegoś elementu. Nic mądrego nie wymyślę i zastanawiałem się czy po prostu nie zrobić tego w podobny sposób jak np. w przypadku std::vector, czyli do już istniejącego obiektu dodać kolejny itd., czyli wystarczyłaby tylko tablica 1-wymiarowa i druga n-wymiarowa, która używałaby tej pierwszej:

Kopiuj
//zgodnie z tym założeniem np. tablica
int arr[x][y][z];
//tablica o wymiarze x ze wskaźnikami do x tablic 
//x tablic o wymiarach y ze wskaźnikami do już właściwych tablic
//x * y tych właściwych tablic o wymiarach z
//np.
template <typename TYPE> class Simple_array 
{ 
    //... 
};
typedef Simple_array <Simple_array*> _Simple_array_;

template <typename TYPE> class Array
{
    //...
    Array( unsigned dimensions_count, unsigned dimensions[] )
    {
	//przydział pamięci
    }
    //...
};
edytowany 1x, ostatnio: yet_another_bug
ZJ
  • Rejestracja:około 14 lat
  • Ostatnio:prawie 12 lat
0

Narzut związany z obliczeniami jest dość mały, stawiałbym na to, że mniejszy niż wynikający z dereferencji wskaźników (na pewno tak było jak robiłem trójwymiarową tablicę bitów, ale o narzuconym rozmiarze (128), więc mnożenie było zredukowane do przesunięcia bitowego). Dodatkowo przy tablicy wskaźników masz gorsze cache'owanie, co też może się przełożyć na wydajność.

//Edit
Dodatkowo iterowanie po jednym wymiarze (jakimkolwiek) ogranicza się do dodawania stałej do indeksu, dzięki czemu narzut arytmetyczny praktycznie nie ma znaczenia.

edytowany 1x, ostatnio: Zjarek
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:30 minut
0

Schemat Hornera podałem w sumie jako ciekawostkę. Skoro A, B i C to stałe, to ich iloczyny też są stałymi, a więc można je raz przeliczyć na wstępie i nie używać schematu Hornera. Dlatego:

Kopiuj
int b[A * B * C];
// zamiast
b[(x * B + y) * C + z] = v;
// można użyć
b[x * B * C + y * C + z] = v;

Kompilator powinien sobie obliczyć te iloczyny w czasie kompilacji, ewentualnie jeżeli wymiary są obliczane przed tworzeniem instancji klasy, to można to wymnożyć w konstruktorze. Zostaje więc kod:

Kopiuj
b[x * BC + y * C + z] = v;

Ilość mnożeń i dodawań pozostała taka sama jak w schemacie Hornera, ale tutaj można wykonywać mnożenia równolegle. Obecnie (tzn od czasów Pentiumów) procesory są wielopotokowe i mogą robić kilka niezależnych operacji naraz, a więc na przykład w tym przypadku.

Różnice w szybkości iteracji pomiędzy implementacją z emulacją za pomocą mnożenia, a implementacją z wielokrotną dereferencją zależy od wielkości najniższych wymiarów. Jeśli są one niskie to narzut w implementacji z wielokrotną dereferencją jest duży.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
YA
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 12 lat
  • Postów:36
0

Ok, jeszcze raz dziękuję wam za wszystkie uwagi.

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)