Funkcja operatorowa >>

Funkcja operatorowa >>
XS
  • Rejestracja:około 11 lat
  • Ostatnio:4 dni
  • Postów:135
0
Kopiuj
#include <iostream>
#include <string.h>

using namespace std;

class CRekord{
    char* m_pNazwa;
    const int m_nrID = licznik;
    static int licznik;
    short int m_pKod[20];

public:
    CRekord(char* naz);
    ~CRekord();
    CRekord(const CRekord& wzorzec);
    CRekord operator= (const CRekord& prawy){
        if(this != (&prawy)){
            this->~CRekord();
            m_pNazwa = prawy.m_pNazwa;
            for(int i=0; i<20 ; i++){
                m_pKod[i] = prawy.m_pKod[i];
            }
        }
    }
    void ustaw();
    friend istream& operator>>(istream &we, CRekord &prawa);
    void wypisz();
};

int CRekord::licznik = 0;

CRekord::CRekord(char* naz){
    licznik++;
    m_pNazwa = new char[50];
    strncpy(m_pNazwa,naz,50);
    for(int i=0; i<20 ; i++){
        m_pKod[i]=0;
    }
}

CRekord::~CRekord(){
    delete [] m_pNazwa;
}

CRekord::CRekord(const CRekord& wzorzec){
    licznik++;
    m_pNazwa = wzorzec.m_pNazwa;
    for(int i=0; i<20 ; i++){
        m_pKod[i] = wzorzec.m_pKod[i];
    }

}


void CRekord::wypisz(){
    cout<<m_pNazwa<<endl<<m_nrID<<endl<<licznik<<endl<<m_pKod[0]<<endl;
}

void CRekord::ustaw(){
    short int temp[20];
    cout<<"Podaj stary kod"<<endl;
        for (int i=0; i<20 ; i++) {
            cin>>temp[i];
            if(m_pKod[i]!=temp[i]) return;
        }

    cout<<"Podaj nowy kod"<<endl;
        for(int i=0; i<20 ; i++){
            cin>>m_pKod[i];
        }
}

istream& operator>>(istream &we, CRekord &prawa){
    if (&cin == &we){
        cout<<"Podaj nazwe"<<endl;
        char temp[50];
        cin>>temp;
        strncpy(prawa.m_pNazwa,temp,50);

        cout<<"Podaj kod"<<endl;
        for (int i=0; i<20 ; i++){
            cin>>prawa.m_pKod[i];
        }
    }
    return we;
}

int main(){
    CRekord a("napis");
    a.wypisz();

    CRekord b(a);
    b.wypisz();

    cin>>b;




    return 0;
}

Może mi ktoś wytłumaczyć te warunek?

Kopiuj
 friend istream& operator>>(istream& we, CRekord& wzor)
{
if (&cin == &we)
{

Co to jest &cin? Adres strumenia czy coś :D?

Zobacz pozostały 1 komentarz
KM
Tak czy siak, odpowiedź: Tak, &amp;cin to jest adres strumienia. To g**wno sprawdza, czy strumień, który podajesz jako argument (we), to jest tożsamościowo strumień cin, porównując ich adresy w pamięci.
spartanPAGE
@kmph deklaracja jest normalna, definicja natomiast to jakiś potwór.
KM
@spartanPAGE Mnie chodzi konkretnie o if (&amp;cin == &amp;we)
spartanPAGE
@kmph wiem; Ale prostując: istream to nie jest abstrakcyjny strumień. Dla przykładu obiekt cin jest jego instancją.
KM
@spartanPAGE Abstrakcyjny w sensie projektu, sorry wyrażenie nieścisłe. istream to jest jakiś strumień wejścia, z założenia funkcja, która przyjmuje obiekt klasy istream nie wie, co to konkretnie za strumień (a więc, jest bariera abstrakcji). cin to jest ten konkretny strumień. Wiem, że istream to nie jest, w ścisłym sensie, klasa abstrakcyjna.
twonek
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
1

cin to obiekt typu std::istream, więc tak jak każdy normalny obiekt ma jakiś adres. Sprawdzasz tutaj czy wczytasz z cin czy może jakiegoś innego strumiena.
http://en.cppreference.com/w/cpp/io/cin

edytowany 1x, ostatnio: twonek
kq
"do cin" ⟶ "z cin" imo :P
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
2
  1. Smrodek od niepoprawnie używanej inkrementacji: http://4programmers.net/Forum/1101404
  2. if(&cin==&we) cout<<"Podaj nazwe"<<endl; - reszta niech leci jak jest,
  3. Tu
Kopiuj
char temp[50];
    ...
    strncpy(prawa.m_pNazwa,temp,50);

Mazanie po pamięci, musisz zrobić jak w konstruktorze lub użyć strdup
4. Powinno być: CRekord::CRekord(const char *naz)
5.

Kopiuj
char *strdup(const char *str)
  {
   if(!str) return str;
   size_t size=strlen(str)+1;
   char *ret=new char[size];
   memcpy(ret,str,size);
   return ret;
  }

w konstruktorze też lepiej to użyj.
6. tu CRekord::CRekord(const CRekord& wzorzec) nazwę również musisz skopiować.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
KM
reszta niech leci jak jest niezupełnie, bo jeszcze cout&lt;&lt;&quot;Podaj kod&quot;&lt;&lt;endl; trzeba w ifa wsadzić
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:2 dni
  • Lokalizacja:Szczecin
5

@kmph ma rację, to jest chore. &cin to adres obiektu strumienia standardowego wejścia. To porównanie ma na celu zapewnienie, że wczytujesz wyłącznie ze standardowego wejścia, ignorując wszystko inne.

Ponadto:

  1. W kodzie masz UB (operator kopiowania i konstruktor kopiujący kopiują wskaźnik, a potem jest double delete)
  2. Poczytaj o regule zero: https://rmf.io/cxx11/rule-of-zero/
  3. Używaj standardowych kontenerów zamiast je ręcznie implementować. std::string nie gryzie. std::vector też nie.
  4. Nie powinieneś wypisywać nic w metodzie wczytującej ze strumienia.

Jeśli to nie jest Twój kod, a tylko się na nim wzorujesz - nie wzoruj się, jest zły.


KM
@kmph ma rację, to jest chore. Chociaż przyznam, że „kompromisowe” rozwiązanie @_13th_Dragon do mnie przemawia: if(&amp;cin==&amp;we) cout&lt;&lt;&quot;Podaj nazwe&quot;&lt;&lt;endl; - reszta niech leci jak jest czyli, bawienie się w „interaktywność” tylko jeśli to jest cin, ale normalne wczytywania z czegokolwiek inego. Oczywiście nadal pozostaje problem jeśli mamy przekierowanie standardowego wejścia, ale to nie do uniknięcia przy jakiejkolwiek interaktywności chyba
kq
Tak, jak pisałem tego posta to jeszcze tego nie było, a nie pomyślałem o tym. Ale ogółem uważam, że tego typu interaktywność to błąd. W ostateczności opt-in z konsoli :P
KM
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 4 lata
  • Postów:473
1
Kopiuj
if(this != (&prawy)){
            this->~CRekord();

To już chyba błąd sam w sobie. https://isocpp.org/wiki/faq/dtors Powtarzają tam setki razy, by nigdy nie wywoływać destruktora, chyba że się używa placement new

Zobacz pozostały 1 komentarz
Endrju
Tam jest błąd (UB). Po wywołaniu destruktora obiekt nie istnieje. W następnej linijce jest użycie składnika m_pNazwa, ale *this już nie istnieje. (3.8/1, 3.8/3)
KM
@kq Note that calling a destructor directly for an ordinary object, such as a local variable, invokes undefined behavior when the destructor is called again, at the end of scope. http://en.cppreference.com/w/cpp/language/destructor Pytanie: Czy jeżeli najpierw operator= wywoła destruktor, a potem ponownie zostanie wywołany destruktor tego samego obiektu (co się prędzej czy później stanie, chyba że sam obiekt jest dynamicznie alokowany), to jest UB?
Endrju
UB jest z innego powodu i dużo szybciej (linijkę niżej), przecież napisałem wyżej.
KM
@Endrju Sorry, nie zauważyłem, jak pisałem to jeszcze twojego komentarza nie było. Skądinąd chyba mam rację, że tu będzie jeszcze jedno UB.
kq
Teoretycznie jak najbardziej. Praktycznie - mniej (co nie zmienia faktu, że UB to UB i tego się po prostu nie robi). Teraz mi wstyd za ten komentarz, ale zwalmy to na zmęczenie.
KM
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 4 lata
  • Postów:473
0
Kopiuj
// Interaktywność pomijam. Jeśli będzie potrzebna, to niech się nią zajmie
// jakiś zewnętrzny wrapper albo funkcja main(). IMHO tak będzie najlepiej

#include <istream>
#include <ostream>
#include <string>
#include <vector>
#include <cstddef>
#include <utility>

class CRekord
{
  std::string nazwa;
  int ID;
  static std::size_t licznik;
  static constexpr std::vector<int>::size_type kod_rozmiar = 20;
  static constexpr short kod_domyslny = 0;
  std::vector<short> kod;

public:
  CRekord(std::string nazwa) :
    nazwa(nazwa), ID(licznik++),kod(kod_rozmiar, kod_domyslny) {}
  CRekord(const CRekord &cr) : nazwa(cr.nazwa), ID(licznik++), kod(cr.kod) {}
  CRekord(CRekord &&cr) noexcept :
    nazwa(std::move(cr.nazwa)), ID(std::move(cr.ID)), kod(std::move(cr.kod)) {}
  CRekord &operator = (const CRekord &cr)
    {nazwa = cr.nazwa; kod = cr.kod; return *this;}
  CRekord &operator = (CRekord &&cr) noexcept
  {
    nazwa = std::move(cr.nazwa);
    kod = std::move(cr.kod);
    ID = std::move(cr.ID);
    return *this;
  }
  friend std::istream &operator >> (std::istream &we, CRekord &cr)
  {
    std::string pom_nazwa; std::vector<short> pom_kod(kod_rozmiar);
    we >> pom_nazwa;
    for(std::vector<short>::size_type i = 0; i < kod_rozmiar; ++i)
      we >> pom_kod[i]; // Zadowolony z preinkrementacji, @_13th_Dragon? ;P
    if(we.good())
    {
      cr.nazwa = std::move(pom_nazwa);
      cr.kod = std::move(pom_kod);
    }
    return we;
  }
  friend std::ostream &operator << (std::ostream &wy, CRekord const &cr)
  {
    wy << cr.nazwa << std::endl << cr.ID << std::endl << cr.kod[0] << std::endl;
    return wy; // Pomijam wypisywanie licznika, bo to IMHO bez sensu
  }
  bool ustaw
    (std::vector<short> const &stary_kod, std::vector<short> const &nowy_kod)
  {
    if(kod == stary_kod)
    {
      kod = nowy_kod;
      return true;
    }
    else return false;
  } // Pobraniem starego_kodu i nowego_kodu niech się zajmie wrapper
};

std::size_t CRekord::licznik = 0;

Komentarze?

Zobacz pozostałe 3 komentarze
KM
@kq http://stackoverflow.com/a/18654089/4385532 może i masz rację z tymi move constructors
KM
@_13th_Dragon Wiem, ale swapowanie array ma czas liniowy, więc to by psuło złożoność move constructor i move assignment operator chyba, czy się mylę?
kq
Tak, ale tak samo było w oryginalnym kodzie, więc możliwe, że tak powinno być ;) Zamiana char*string to poprawa oczywistego błędu. Poprawa short int[50] na vector&lt;short int&gt; to prawdopodobnie dobry ruch, ale już tej gwarancji nie masz.
KM
Poprawa short int[50] na vector&lt;short int&gt; to *prawdopodobnie* dobry ruch, ale już tej gwarancji nie masz. Porównywanie i przypisywanie jest łatwiejsze, stąd ten pomysł.
KM
Tak, ale tak samo było w oryginalnym kodzie, więc możliwe, że tak powinno być ;) W oryginalnym kodzie w ogóle nie było move constructor. To był błąd, bo każda tymczasowa kopia powiększała licznik i uzyskiwała nowe ID. Tzn. teoretycznie możliwe, że to było zamierzone, ale wątpię bardzo.
insectoman
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 6 lat
1

Kolega xavi robi ten kod w ramach nauki na poprawkę z egzaminu z c++.

W załączniku macie polecenia do egzaminu. (z lat ubiegłych, chomiki rlz) Nie można stosować wektorów etc, a jedynie to o co prosi prowadzący w poleceniu.

PS. Udzielam się tu czysto informacyjnie, bo poznałem zadania, które ktoś wrzucił na naszą grupę na fb, a ja egzamin mam za sobą.

edytowany 1x, ostatnio: insectoman
KM
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 4 lata
  • Postów:473
2

EDIT!! Przepraszam, pomyliłem się, wprowadziłem do kodu poprawki.

EDIT2. if(&cin == &we) chyba jednak zbędne. W zadaniu jest o tym, że operator ma zostać skojarzony ze strumieniem wejścia istream, a więc niekoniecznie cin - to jest strumień standardowego wejścia, a to różnica.

Dobrze zatem. Też miałem nauczycieli z takimi wymogami, rozumiem.

Do przygotowania się do egzaminu:

Kopiuj
#include <iostream>
#include <istream>
#include <cstring>
#include <iomanip>

class CRekord
{
  // Skoro wykładowca żąda… Nie widzę zalet takiego rozwiązania nad std::string
  char* m_pNazwa;
  const int m_nrID;
  static int licznik;
  short int m_pKod[20];

public:
  // Nie mogę definiować w klasie żadnych metod, bo inaczej będą inline.
  // Wszystkie definicje muszą wylądować poza klasą.
  // Jak pisze @kq, przy takiej deklaracji nie możesz prosto tworzyć obiektów tej klasy za pomocą literału znakowego.
  CRekord (char* naz);
  ~CRekord();
  CRekord(const CRekord& prawy);
  // Operator przypiasania musi zwracać CRekord&, bo inaczej nie będzie można
  // przypisywać kaskadowo. Powinni byli gdzieś Ci powiedzieć, dlaczego tak.
  CRekord& operator = (const CRekord& prawy);
  // Może zwracanie bool będzie lepsze. True jeśli przypisanie się udało,
  // false w.p.p.
  bool ustaw_kod();
  friend std::istream& operator >> (std::istream& we, CRekord& prawy);
};

int CRekord::licznik = 0;

// jednocześnie przypisuję i inkrementuję licznik
// Mam nadzieję rozumiesz czym się różni licznik++ od ++licznik?
CRekord::CRekord(char* naz) : m_nrID(licznik++)
{
  // new char[51] bo miejsce na null terminator
  m_pNazwa = new char[51];
  std::strncpy(m_pNazwa, naz, 50);
  // Dodanie null terminatora; jeśli naz (razem z null terminatorem) jest 
  // dłuższa niż 50 znaków, to strncpy nie doda null terminatora automatycznie
  m_pNazwa[50] = '\0';
  // sizeof(m_pKod) działa, gdyż m_pKod jest tablicą alokowaną statycznie
  // Gdyby to był tylko wskaźnik do tablicy, (czyli np. tablica alokowana
  // dynamicznie bądź tablica przekazana jako argument funkcji), to już tak nie
  // można by było.
  // Aha, i taka inicjalizacja też zadziała tylko dla tablic liczbowych
  // i tylko dla zera.
  memset(m_pNazwa, 0, sizeof(m_pKod));
}

CRekord::~CRekord()
{
  delete[] m_pNazwa;
}

// Ten design jest nieodporny na tworzenie się kopii tymczasowych,
// ale trudno – skoro wykładowca żąda. Chodzi mi o to, że przy takim projekcie,
// w niektórych sytuacjach (np. gdy jakaś funkcja zwraca obiekt klasy CRekord
// albo gdy obiekty tej klasy są w std::vector i swapujesz vector) może się
// nieoczekiwanie inkrementować licznik i zmieniać wartość m_nrID. Poczytaj
// o różnicy między copy constructor a move costructor, jeśli chcesz wiedzieć
// więcej
CRekord::CRekord(const CRekord& prawy) : m_nrID(licznik++)
{
  // Teraz 51 żeby się na pewno null terminator skopiował
  // Można tak bo wiadomo że prawy.m_pNazwa ma null terminator i rozmiar
  // nie większy niż 51 znaków z nullem włącznie
  std::strncpy(m_pNazwa, prawy.m_pNazwa, 51);
  // Chyba lepiej niż for?
  // Uwaga do kopiowania tablic liczb całkowitych memcpy się nadaje, ale do
  // kopiowania tablic bardziej skomplikowanych obiektów
  // jak np. CRekord już niekoniecznie
  std::memcpy(m_pKod, prawy.m_pKod, sizeof(m_pKod));
}

// Tak się definiuje operator poza klasą
CRekord& CRekord::operator = (const CRekord& prawy)
{
  if(this != &prawy)
  {
    // Swoim porządkiem to używanie tych wszystkich memcpy memset i innych
    // to jest straszne świństwo. Naprawdę, może jednak fory są lepsze. Nie
    // widzę zalet takich tablic nad std::vector
    std::strncpy(m_pNazwa, prawy.m_pNazwa, 51);
    std::memcpy(m_pKod, prawy.m_pKod, 20*sizeof(short int));
  }
  return *this;
}

bool CRekord::ustaw_kod()
{
  short int stary_kod[20];
  for(int i = 0; i < 20; ++i)
    std::cin >> stary_kod[i];
  short int nowy_kod[20];
  for(int i = 0; i < 20; ++i)
    std::cin >> stary_kod[i];
  if(std::memcmp(m_pKod, stary_kod, sizeof(m_pKod)))
  {
    std::memcpy(m_pKod, nowy_kod, sizeof(m_pKod));
    return true;
  }
  else return false;
}

std::istream& operator >> (std::istream& we, CRekord& prawy)
{
  // setw chroni przed przepełnieniem bufora, jak zadanie każe
  // Uwaga! Jest duża szansa, że komitet standaryzacyjny C++ zarządzi, że
  // operator >> ma przestać działać z tablicami znaków!!
  // http://cplusplus.github.io/LWG/lwg-active.html#2499
  // Kolejny powód by nie używać tablic znaków
  we >> std::setw(51) >> prawy.m_pNazwa;
  for(int i = 0; i < 20; ++i)
      we >> prawy.m_pKod[i];
  return we;
}

Czekam na gromy od pozostałych forowiczów ;P

Ostrzegam, że nie przetestowałem żadnego z tych moich dwóch kodów.

edytowany 4x, ostatnio: kmph
Zobacz pozostałe 5 komentarzy
KM
@kq strncpy: Copies at most count characters of the byte string pointed to by src (including the terminating null character) ( http://en.cppreference.com/w/cpp/string/byte/strncpy ) A więc znowu, strncpy z 51 kopiuje maks. 50 znaków i nulla jako 51. o ile za każdym razem string jest zakończony nullem, a o ile pamiętam staram się zawsze upewnić, żeby tak właśnie było.
kq
No i ten pięćdziesiąty pierwszy null zostanie zapisany na 51. miejscu w 50-elementowej tablicy. Edit: widzę, że zmieniłeś na 51-elementową. No to teraz jest ok, tylko niezgodnie z wymaganiami profesorka ;)
KM
@kq m_pNazwa = new char[51]; w zadaniu było, że tablica przechowywać ma tekst 50 znaków, a więc rozumiałem, że muszę zarezerwować miejsce na 51 elementów bo jeszcze null
kq
Przeczytałem jeszcze raz zadanie i w sumie nie jestem pewien, ale mam wrażenie, że gdyby ściśle trzymać się założeń profesorka to trzeba by trzymać do 50 znaków, ewentualnie bez nulla kończącego, w 50-elementowej tablicy.
KM
Nie, błagam. Wtedy to już naprawdę nie wiem, jak sensownie zrobić wczytywanie. Chyba trzeba by najpierw wczytać 49 znaków, potem sprawdzić, czy na wejściu czeka jeszcze jakiś znak… Daruję to już sobie. Chyba, że jest jakiś prostszy sposób, którego nie widzę.
pingwindyktator
  • Rejestracja:ponad 12 lat
  • Ostatnio:28 dni
  • Lokalizacja:Kraków
  • Postów:1055
1

Btw, czym się różni cin od obiektu
std::istream kek(cin.rdbuf());?
No niczym chyba, oba obiekty korzystają z tego samego bufora i zachowują się tak samo. A ten kod nie pozwoli mi wczytać do kek. W ogóle jakieś herezje straszne w tym temacie. A ten kod jest jeszcze gorszy.


do not code, write prose
kq
Witaj na polskich uczelniach :D
pingwindyktator
Pan magister się odezwał :D
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)