Anonymní profil Jokertwo – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Anonymní profil Jokertwo – Programujte.comAnonymní profil Jokertwo – Programujte.com

 

Příspěvky odeslané z IP adresy 94.142.234.–

Jokertwo
Java › Vícestránková aplikace
14. 8. 2018   #381237

#1 MiraP
Ahoj, mohl by jsi použít layout manager CardLayout, který přesně tohle umí. V jednom JFramu/JPanelu přepínat obsah.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
 
public class CardLayoutExample {
 
  public static void main(String[] arguments) {
 
    // main window
    JFrame.setDefaultLookAndFeelDecorated(true);
    JFrame window = new JFrame("CardLayout Example");
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.setSize(300,300); 
    window.setLayout(new BorderLayout());
 
 
    final CardLayout cardLayout = new CardLayout(); 
    final JPanel cardPanel = new JPanel(cardLayout);
 
    // create two dummy panels (the "cards") to show
    JPanel card1 = new JPanel();
    card1.setBackground(Color.red);
 
    JPanel card2 = new JPanel();
    card2.setBackground(Color.blue);
 
    cardPanel.add(card1,"RedCard");
    cardPanel.add(card2,"BlueCard");
 
 
    // create two buttons 
    JPanel buttonPanel = new JPanel();
    JButton b1 = new JButton("Red");
    JButton b2 = new JButton("Blue");
    buttonPanel.add(b1);
    buttonPanel.add(b2);
 
    // create action listeners for buttons
    b1.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        cardLayout.show(cardPanel, "RedCard");
      }
    });
 
    b2.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        cardLayout.show(cardPanel, "BlueCard");
      }
    });
 
    // add card & button panels to the main window
    window.add(cardPanel,BorderLayout.CENTER);
    window.add(buttonPanel,BorderLayout.SOUTH);
    window.setVisible(true);
  }
}
C / C++ › Vyprázdnění bufferu klávesnice
28. 6. 2017   #216824

#3 kozomelec
Z terminálu se čte po řádkách, takže getchar() se odblokuje teprve poté, co zmáčknete Enter, a vrátí první znak z řádky. Následující volání getchar() se nezablokují, ale rovnou vrací postupně znaky řádky, tak dlouho, dokud nedojdete k Enteru. Pak se getchar() opět zablokuje a čeká dokud znovu Enter nezmáčknete.

C / C++ › NULL
26. 6. 2017   #216810

#19 Radek Chalupa
Nemůžete si nadefinovat sám NULL. Tohle makro je ve standardních knihovnách, a pokud ho nadefinujete jinak, získáte od překladače spoustu chyb, že definice makra je rozdílná. A obecně nepomůže ani undef, protože stačí, aby se systémová definice v pořadí vkládaných hlaviček dostala za vaši definici.

Navíc, pokud byste chtěl, aby se NULL chovalo "očekávaně", pak byste makro musel nadefinovat nějak takto: 

#define NULL ((void*) 0)

Pak by se skutečně vybrala očekávaná funkce s ukazatelem. Některé překladače používají tuhle definici; pokud si dobře vzpomínám svého času BorlandC na MS-DOSu.

C / C++ › NULL
23. 6. 2017   #216792

#15 KIIV
NULL se nedoporučuje používat kvůli přenositelnosti a jednoznačnosti následujícího kódu: 

void f(void* p_);
void f(int i_);
void f(long l_);

f(NULL);

Vzhledem k tomu že NULL je pro různé překladače a různé konfigurace jednoho překladače definovaný různě, se na každém zavolá jiná funkce. Máte naprostou pravdu, že NULL vyjadřuje záměry programátora, ale zároveň dokáže způsobit nečekané chyby - v tomto konkrétním případě na většině překladačů zavolá právě úplně jinou funkci, než byl autorův záměr. Autoři standardu si toho byli vědomi, proto od C++11 zavedli nullptr.

C / C++ › NULL
22. 6. 2017   #216787

#13 BDS
Ono, aby to nebylo jednoduché, u před-C++11 se navíc doporučuje používat 0 namísto NULL i u ukazatelů :-D

C / C++ › Generovaní náhodných čísel v C
6. 6. 2017   #216586

Navíc, pokud to má dobře fungovat i jinde než na Linuxu, tak dělení modulo hodnoty navrácené z rand() není dobrý nápad - spodní bity generovaných čísel nebývají dostatečně náhodné. Doporučený postup je něco takového: 

rand() / (RAND_MAX / N + 1)

Podrobnosti např. zde: http://c-faq.com/lib/randrange.html

C / C++ › Počet písmen ve slovech v te…
22. 5. 2017   #216164

#13 Tonda
Procenta jsou podíl počet znaků / celkový počet znaků vynásobený 100. Tzn. musíš si nejdříve sečíst všechny hodnoty, které v polích máš, a pak u každého znaku podíl spočítat. Dělení nezapomeň dělat ve float (double), jinak se ti každá hodnota zaokrouhlí na 0.

C / C++ › Geometrický průměr v C++
15. 5. 2017   #216041

#1 Jasal
V čem je problém? Jestliže v jedné funkci umíš matici po řádkách vypsat, tak by neměl být žádný problém v jiné funkci spočítat po řádkách geometrický průměr, ne? Takže skoro mám podezření, že kód asi není tvůj, že?

C / C++ › Úprava jednoduché hry v céčku
3. 5. 2017   #215828

No, měl bych ještě jeden námět na zlepšení. Proměnnou chaos bys mohl iniciálně nastavit na 1, a pak s ní násobit změnu pozice (zmenar a zmenas v kódu gna). A při vstupu na pole s @ proměnnou chaos vynásobit -1, čímž se bude elegantně překlápět mezi normálním a opačným ovládáním.

C / C++ › Program na prevod čísla z 16…
18. 4. 2017   #215661

Jak převést číslo ze vstupního stringu jsem obecněji (pro libovolný počet číslic, nejen 2) psal tady nedávno: http://programujte.com/forum/vlakno/31428-prevod-retezce-na-cislo-bez-pouziti-funkci-ktere-to-udelaji/#p212744 

Oproti algoritmu v linku vy potřebujete načítat cifry šestnáctkové soustavy. Kód pro tento účel může vypadat takto: 

int cifra;
if(znak >= '0' && znak <= '9') {
  cifra = znak - '0';
}
else if(znak >= 'A' && znak <= 'F') {
  cifra = 10 + znak - 'A';
}
else {
  /* -- chybny vstup!!!!!!! */
}

Je to vlastně to, co píše hluchéucho v předchozím komentáři. Daný kód bude ovšem fungovat pouze tam, kde kódování znaků A až F jde číselně hezky za sebou (např. ASCII). Osobně jsem se za svou praxi nesetkal s reálně používaným kódováním, které by tuhle podmínku nesplňovalo. Což samozřejmě neznamená, že neexistuje.

C / C++ › Scanf ve funkci
11. 4. 2017   #215549

#3 KIIV
Moc pěkné, tenhle trik jsem neznal. Scanf jsem sice už asi 10 let nepoužil, ale stejně je to hezký tip.

C / C++ › Vývojová prostředí c++ - jak…
11. 4. 2017   #215548

#3 Ovrscout
Nevím, kdy jste naposledy Eclipse zkoušel, ale vaše výhrady už dávno nejsou platné. Eclipse CDT se dá stáhnout jako kompletní balíček, a pokud už máte nainstalované gcc a jvm, tak funguje rovnou prakticky bez jakékoliv konfigurace. Jsem Linuxář, takže osobně za Windows moc mluvit nemůžu, ale i kolegové na Windows s Eclipse žádné problémy nemají.

C / C++ › Úkol do školy C++
6. 4. 2017   #215497

#3 KIIV
A když už jsme u těch školních čuňáren, co se učí, tak všechny proměnné jsou zbytečně globální, a navíc neinicializované :-) Vím, že v globálu to není třeba, ale stejně je dobrý zvyk to dělat.

C / C++ › zadanie mi nefunguje, neviem…
5. 4. 2017   #215473

#4 KIIV
Ano, musím podpořit názor. Tento zápis je pouze mlžení kódu, obzvláště pokud jsou ve výrazu operátory se side efekty (+=, --, ++). Vyhodnocení výrazu je sice v tomto případě dobře definované, ale asi neznám programátora, který by si byl absolutně jistý. If je jednoznačně lepší volba.

Jenom bych dodal, že navrhovaný přepis do ifu není zcela přesný, protože původní vyraz v případě, že centralny_sklad->jedlo bude nula, neprovede dekrementaci inventar_stav->unava[i] (předpokládám, že dekrementace se ztratila pouze omylem). Nejsem si ale úplně jistý, jestli tohle náhodou nebyla chyba v původním vyrazu :-)

C / C++ › Návrhové vzory - Specializac…
30. 3. 2017   #215394

#7 Doomista
Dědičnost povětšinou není ten nejlepší nástroj pro znovupoužívání kódu, k tomu je většinou vhodnější, jak píše KIIV, kompozice. Dědičnost by měla být používaná spíše pro specializaci rozhraní (proto taky UML má vztah generalizace/specializace, nikoliv dědičnost). Zkusme si tedy vzít váš návrh: 

class Souradnice {
  int x, y;
  void move(const Souradnice& s_);
};

class Bod {
  Souradnice p;
  virtual void prekresliSe();
  virtaul void move(const Souradnice& s_) {
    p.move(s_);
    prekresliSe();
  }
};

class Obdelnik : public Bod {
  Souradnice v;  /* -- rozmery obdelniku */
};

Všechno bude fungovat, tak jak chcete, svět bude růžový. Pak ale budete chtít svůj editor rozšířit o možnost kreslit křivky. Bezierovy kubiky se reprezentují pomocí 4 bodů. Tzn. nový objekt bude vypadat nějak takto: 

class Krivka : public Bod {
  Souradnice p2, p3, p4;
  virtual void move(const Souradnice& s_) {
    Bod::move(s_);
    p2.move(s_);
    p3.move(s_);
    p4.move(s_);
    prekresliSe();
  }
};

Na první pohled jsou tu problémy. S jedním bodem pracujete jinak, než s ostatními, což programátorovi přidělá pár nových vrásek. Navíc se vám dvakrát zavolá prekresliSe. A ještě jste se dostal k mnou zmiňovanému fragile base class problému, pokud metodě Bod::move nějak výrazně změníte chování (např. přidáte nějaký další side effect).

Můžete namítnout, že zbylé body je možné vyjádřit relativně vůči tomu prvnímu. Ano, to je pravda. Ale také to znamená, že při každé práci s křivkou si body nejdříve budete muset dopočítat. Takže jste si sice ušetřil práci s posunem, ale přidělal jste si práci všude, kde potřebujete s křivkou pracovat.

Problém je, že tímto návrhem jste si do architektury zavedl omezení, že každý grafický objekt musí být vyjádřitelný jedním absolutním bodem. Asi sám cítíte, že obejít toto omezení u křivky už docela skřípe. A stejný pocit bude mít každý programátor, který bude váš kód rozšiřovat.

To je tak ve zkratce to, co jsem měl na mysli.

C / C++ › Návrhové vzory - Specializac…
30. 3. 2017   #215387

#5 Doomista
Jj, máte pravdu, MVC se ve webu hodně uchytilo. Nicméně, jedná se o vzor, který byl vymyšlený kolem roku 1978 ve Smalltalku pro implementaci jejich GUI toolkitu. A co tak pozoruji posledních 10 let, tak prakticky všechny GUI toolkity k němu pomalu konvergují.

Proboha, tohle je asi ten nejhorší příklad, jaký se v učebnicích OOP vyskytuje. Podle mého názoru už zničil myšlení tak 3 až 4 generací programátorů. Ani Obdélník, ani Kruh nejsou speciálním případem bodu! Matematicky se jedná o množinu bodů. V programátorské praxi bude obdélník pravděpodobně reprezentovaný dvěma body a kruh jedním bodem a poloměrem. Ale ani jedno není bod!

Ta "správná" hierarchie pro tento příklad (předpokládám implementaci jednoduchého grafického editoru) je rozhraní GrafickýObjekt (což by v C++ byla ta pure virtual třída) a pro něj implementovat (v C++ podědit) třídy Bod (kreslil by se jako puntík), Obdelnik a Kruh, případně další.

C / C++ › Návrhové vzory - Specializac…
29. 3. 2017   #215374

Oddělení logiky od vykreslování určitě udělejte. Zkuste se například kouknout na klasický návrhový vzor MVC (Model View Controller), který přesně takhle pracuje. Má logický model a asynchronně k němu jsou k němu připojené dvojice View/Controller, které se starají o zobrazení, regují na změny v modelu a reagují na uživatelské události. Pokud půjdete podobnou cestou, pravděpodobně nebudete potřebovat továrnu, protože typy budou jasně dané zvoleným View.

Ve vašem návrhu nevím, jak byste chtěl zobrazení do Qt a CLI schovat pod jedno rozhraní, protože pro zobrazení budete potřebovat rozdílné prostředí. Aby to šlo, musel byste vytvořit společné rozhraní pro vykreslování do Qt a CLI.

Jedna architektonická. Pokud dědíte z třídy, která má implementaci, v 90 % případů to značí, že máte chybu v návrhu. Postup obvykle je definice rozhraní (v C++ třída, která má pouze pure virtual metody), a pak jejich implementace. Ještě horší situace je, když dědíte z třídy s implementací a ještě přetěžujete už naimplementovanou metodu. Pak si zaděláváte na vážné problémy, ocančované obvykle jako fragile base class.

C / C++ › Definovanie char Meno atribu…
28. 2. 2017   #215106

Musím se přidat. Maďarská notace je blbina. Prodlužuje názvy proměnných a obaluje je zbytečným balastem, čímž kód spíš znepřehledňuje než zpřehledňuje. Navíc duplikuje informaci, kterou nese typ proměnné, což se projeví jako příšerný opruz, když refaktorujete a typ změníte. Dokážu si představit, že to mělo nějaký význam, když se programy psaly ve vi, ale dnešní editory dokáží typovou informaci o proměnné dodat okamžitě, takže není žádný důvod ji vpisovat ještě do názvu. Ve firmě jsme se maďarské notace s velkým nadšením zbavili.

C / C++ › Linux - poslání události
22. 2. 2017   #214984

#29 jurin2jurin
Podle výpisu z ps spouštíte aplikace pod uživatelem root, tedy s právy problém nebude.

Abych to shrnul. Podle vás nefunguje ani roura, ani signály, ani TCP sockety. Pravděpodobnost, že nějaký Linux neumí ani jedno, je prakticky nulová. Takže bych hledal chybu na vaší straně.

Utilita kill vám říká, že PID neexistuje, takže tvrzení, že proces A určitě běží, se zdá být s největší pravděpodobností chybné. Netuším jakou z popisovaných variant momentálně zkoušíte. Ale vaše první ukázka kódu měla vadu, že proces A skončil ihned poté, co se aplikace B spustila (ihned po prvním úspěšném otevření roury, funkce exit ukončuje celý proces, ne jen vlákno). Jste si jistý, že tam něco takového nemáte?

Osobně bych vám doporučoval si komunikaci mezi procesy nejdříve odladit na "normálním" Linuxu, a pak ji zkoušet přenést na kostku.

Víc už vám tady asi nikdo neporadí, pokud nezveřejníte celý kód. Momentálně se motáme pořád dokola a už ani nevím, kterou variantu vlastně momentálně zkoušíte.

C / C++ › Linux - poslání události
21. 2. 2017   #214972

#27 jurin2jurin
Můžu si oči vyočit, ale nikde nevidím, že by oba procesy běžely najednou. Napadají mě dvě možnosti:

  1. navzdory vaším tvrzením současně neběží,
  2. každý běží v jiném terminálu a ps nebylo spuštěné tak, aby vypisovalo všechno. Já osobně pro tento účel používám ps axu, ale na Linuxu je obecně více preferované ps -ef.

Anebo jako workaround by šlo situaci otočit. Podle vašeho popisu se aplikace A chová jako server, takže dává lepší smysl, aby si pojmenovanou rouru vytvořila ona a B si ji pouze otevřelo.

C / C++ › Přeos globálních proměnných…
15. 2. 2017   #214902

#14 hlucheucho
Proměnná definovaná mimo funkci s modifikátorem static nesplňuje vaši definici "že je k ní přístup z celého programu bez ohledu na to, zda je celý program v jednom souboru či více souborech," tudíž podle ní není globální. Její extent je samozřejmě globální (jako u každé statické proměnné), ale její scope nikoliv - ten je omezený pouze na daný soubor. A modifikátor static se k nim obvykle právě z tohoto důvodu píše.

Proměnná nebo funkce s modifikátorem static má nastavený internal linkage,tzn. dané symboly nelze linkovat odjinud než ze stejného modulu. Default bez modifikátoru je external linkage, tedy vzniká globálně viditelný symbol. Se static tak můžete mít v různých modulech stejně pojmenované proměnné nebo funkce bez kolizí. Bez static by kolize vznikly.

Tímto debatu končím, protože už mne nebaví se hádat s někým, kdo ani napodruhé nebyl schopen si otevřít Google a ověřit si, jestli náhodou nemluvím o něčem, co dosud neznal. Přitom stačí jednoduše kouknout třeba na wiki: https://en.wikipedia.org/wiki/Static_variable

C / C++ › Přeos globálních proměnných…
8. 2. 2017   #214825

#11 KIIV
Samozřejmě, nijak nepopírám, že se jedná o heuristické pravidlo. Ale to pravidlo je pravdivé v 99 % případů a ten zbytek jsou dost speciální věci. A přístup embedářů "u nás je to přece jinak, pro nás taková pravidla nemají smysl" je chyba.

Konkrétně z vašich příkladů. errno je letitá ostuda standardní knihovny, za kterou se její autoři stydí, a která na vícevláknových systémech musí být řešená nějakým zpraseným mechanismem v překladači. Rozhodně se nejedná o příklad dobře použité globální proměnné.

stdout a spol. jsou v principu singletony. Singletony jsou obecně zlo. Což poznáte přesně v okamžiku, kdy se pokusíte napsat první automatický test kódu, který k singletonu přistupuje. Např. pokud budete chtít otestovat, zda váš kód generuje správný výstup, zjistíte, že jste v koncích. A bude před vámi dlouhá a protivná práce, kdy si do daných funkcí přidáte argument FILE* a stdout budete přepisovat na něj.

Osobně bych si představoval, že stdout bude součástí kontextu, který program dostává jako argument funkce main. Tak to není, takže asi není lepší způsob, než ho mít jako globální proměnnou. Ale používat ho globálně problém je a programátor by se tomu vyhýbat měl.

Když už jste zmínil premature optimization, tak globální přístup k proměnné je právě krystalická ukázka. Ano, může se časem ukázat, že předávání proměnných program zpomaluje, a pak se uchýlit ke globálnímu přístupu. Ale skutečně pouze v případě, že to má smysl.

Nevím, jestli chápu vaše tvrzení "když se program napíše úplně blbě..." Úplně blbě napsaný program je právě obvykle důsledek předčasných optimalizací a je to přesně ten důvod, proč je nedělat a jsou považované za "root of all evil". Pokud to ovšem někdo používá jako výmluvu pro nedělání optimalizací, které nekazí návrh (od detailů jako používat reference místo kopie objektů až po výběr algoritmů s vhodnou složitostí), pak je to pochopitelně špatně.

C / C++ › Přeos globálních proměnných…
8. 2. 2017   #214823

#10 hlucheucho
Problém globálních proměnných není v tom, že jsou v globálním datovém segmentu (koneckonců i stack a halda jsou obvykle v tom samém segmentu, takže principiálně je každá proměnná globální), ale v jejich přístupnosti kdekoliv jinde. To je to, co je špatně. A to je to, o čem se bavím.

Pokud před proměnnou mimo funkci napíšete static, říkáte tím, že se jedná o proměnnou, jejíž viditelnost je omezena pouze na modul, ve kterém je deklarovaná. Tudíž můžete mít v každém modulu stejně pojmenované proměnné, aniž by došlo ke kolizi při linkování. To je ideální řešení, pokud potřebujete vytvořit proměnnou v globálním segmentu a zároveň nevytvořit globální proměnnou. Ideální řešení pro handler přerušení nebo signálů.

Váš příklad s globálním přístupem ke konfiguraci v EEPROM se zhroutí jak domeček z karet v okamžiku, kdy váš zaměstnavatel přijde s požadavkem, že pokud váš program dokáže nějakou věc dělat jednou, tak přece bude strašně jednoduché, aby ji dělal i dvakrát a vy budete nucen vytvořit v EEPROM druhou instanci konfigurace. Řešení je takové, jak jsem psal minule - vytvořit konfigurace v globálním segmentu a do zbytku programu distribuovat ukazatel na ně. Vaše podmínky jsou splněné - překladač si určil adresu sám a zbylý kód je zcela nezávislý na konkrétní hodnotě.

C / C++ › Přeos globálních proměnných…
27. 1. 2017   #214681

#5 Hansa
No, z popisu nejsem příliš moudrý :-)

Pokud vás k používání globálních proměnných nutí vygenerovaný kód, tak pochopitelně s tím nic neuděláte. Pak stále platí, že máte chybu v návrhu, akorát jste ji neudělal vy, ale autoři generátoru :-)

Za předpokladu, že generovaný kód není špatně, nevidím na vašem popisu nic, co by nutilo používat globální proměnné. Z mého pohledu bych viděl zásadní chybu ve vašem tvrzení "void ADC_Init(void), která mino jiné dělal i to co void MX_TIM1_Init(void)". Pokud vám generátor vygeneruje inicializaci timeru, tak byste ji měl použít a ne ji duplikovat někde jinde.

Jako objektáři mi váš problém moc složitý nepřijde. Odkaz na timer se nějakým způsobem injektuje do ADC, ten si ho uschová a následně s ním pracuje. Nevěřím, že jeden uložený ukazatel je takový paměťový problém, aby to ve vašem případě nešlo udělat. Osobně mám zkušenost s Xilinxovým Spartanem, a tam to problém nebyl. Ale pochopitelně se můžu mýlit a být překvapený :-)

C / C++ › Přeos globálních proměnných…
27. 1. 2017   #214680

#7 hlucheucho
Tady jsme si asi měli nejdříve nadefinovat, o čem se bavíme. Globální proměnnou jsem měl na mysli skutečně proměnnou, ke které si různé části kódu svévolně přistupují. To je to, co nikdy nepoužívat. Vaše příklady ale do tohoto ranku nepatří.

V přerušení potřebujete předat data mezi handlerem a vnějším kódem (podobnou situaci musíme řešit i my na "velkém" systému v handlerech signálů). Tam vám stačí proměnnou pomocí static omezit pouze na modul, ve kterém je handler a funkce, které s daty pracují. Zbytek programu o takové proměnné absolutně nemusí (nesmí) vědět.

V případě konfigurace dokonce vůbec globální proměnnou nechcete, pouze chcete řídit, kde v paměti bude umístěná. Osobně, pokud bych něco takového dělal, bych si konfigurační proměnné umístil do struktury, tu bych zinstancioval tam, kde ji chci mít, a pak všem funkcím, které s konfigurací pracují, předával ukazatel na ni.

C / C++ › Přeos globálních proměnných…
27. 1. 2017   #214675

#3 hlucheucho
Hmm, máte nějaký konkrétní praktický příklad? Připadá mi, že používat C na platformě, kde je problém si předat jeden argument do funkce, nějak ztrácí význam.

C / C++ › Přeos globálních proměnných…
27. 1. 2017   #214673

Jestli dobře rozumím problému, tak v souboru casovac.c potřebujete deklaraci: 

extern int timer;

Tu byste, samozřejmě, měl mít v hlavičce, ne ji ručně dopisovat do každého modulu.

Nicméně, základní pravidlo pro používání globálních proměnných je "nikdy je nepoužívat". Nevím, co řešíte, ale jsem si téměř jistý, že máte špatně návrh.

C / C++ › C++ cvičebnice
27. 1. 2017   #214671

Mno, jestli se opravdu nudíte, tak by se mi určila hodila pomocná ruka na jednom mém (netvrdím, že perspektivním) drobném hobby projektu: https://github.com/Staon/otest2 Určitě bych tam našel drobnou práci pro začátečníky :-)

C / C++ › Čtení velkého souboru
27. 12. 2016   #214253

#12 KIIV
Máte na mysli původní kód, nebo ten můj? Pokud to druhé, tak tam asi mám nějakou chybu, ale nevím jakou, protože tim bez problému překóduji 900MB avi.

C / C++ › lineárně zřetězený seznam v C
23. 12. 2016   #214210

#17 Jerry
Naprosto s vámi souhlasím, že zadání psal nějaký mamlas :-)

Aha, prošel jsem si váš kód pořádně a to co popisujete, není strom, ale obousměrně zřetězený spojový (lineární) seznam. Nevím, kde jste vzal název sekvenční binární stromBinární strom je hierarchická struktura, kde každý uzel má až dva potomky. A protože je vždy hierarchický, slovo sekvenční k tomu už nedává moc smysl.

Je pravda, že z hlediska teorie grafů je možné seznam považovat za speciálním případ stromu. Ale v zadání neřeší grafy, tak bych mu s tím hlavu nezatěžoval a používal standardní terminologii v oboru.

Ve výsledku je jedno, jestli seznam implementujete alokováním na haldě, nebo nad polem záznamů (jak jste správně poznamenal). Podstatné je, že v zadání mají jednosměrně zřetězený seznam, zatímco vy mu jako radu dáváte obousměrně zřetězený. Předpokládám, že jejich učitel zaprvé nechtěl, aby se ztratili v příliš mnoha propojkách (představit si jak přepojit uzel v obousměrném seznamu není úplně jednoduché), zadruhé asi chtěl, aby si sami na vlastní kůži vyzkoušeli, jak jednosměrně zřetězený seznam zkomplikuje operace delete a insert.

C / C++ › Čtení velkého souboru
23. 12. 2016   #214209

#6 richard.zavodny
Přesně tak, jak KIIV píše - došla vám paměť. Soubor máte zkopírovaný v paměti dvakrát - jednou načtený a jednou enkódovaný - a ještě tam budete mít nějaký overhead způsobený nafukováním stringů při načítání.

Skutečně musíte načítat po menších částech. Stačí bloky o násobku 3, protože base64 překódovává 3 B na 4 B.

Protože ale bufferování do paměti řeší už C++ streamy, je poměrně zbytečné jejich funkci duplikovat. Takže, podle mne, ještě elegantnější řešení je napsat kódování base64 jako automat (má tři stavy: 1. B, 2. B, 3. B, a pak přechází zpět do stavu 1. B a přitom zapíše překódované 4 B do výstupu) a v cyklu číst byte po byte ze vstupního streamu a předávat je do automatu, který to zase průběžně zapisuje do výstupní streamu. Takhle to dělám u nás v práci. Mám to naimplementované jako C++ stream, takže použití je pak úplně triviální.

C / C++ › Dvourozměrné pole nebo pole…
22. 12. 2016   #214182

#1 mardon
Nepíšete, jakého výsledku chcete dosáhnout. Možnosti, jak se s daným problémem poprat, máte v principu dvě:

  • zvolit si maximální limity, např. maximální délka sekvence, maximální počet řádek a maximální délka řádky ve znacích apod., a při načítání dat je kontrolovat. Pak můžete použít statické struktury (např. to dvojrozměrné pole). Díky tomu se jedná o nejjednodušší řešení, které pro školní projekty většinou stačí (pokud zadání nevyžaduje něco jiného).
  • Anebo skutečně musíte vytvořit nějaké dynamické struktury (což je řešení, které je obvykle potřeba v praxi). I zde máte další možnosti: můžete si to držet ve spojových seznamech, "nafukovacích" polích, případně v dalších strukturách. Pokud potřebujete jít touto cestou, důrazně bych doporučil použít C++ a kontejnery v STL. Pokud je C nutnost, nikoliv jen vaše neochota pracovat s C++, pak vám život vůbec nezávidím a vyhraďte si dost času na studium, jak napsat nafukovací pole (doporučení hluchehoucho na větších datech nefunguje, protože má kvadratickou časovou složitost). Anebo použijte spojové seznamy, které se i v C dají udělat celkem snadno.

C / C++ › C - Nacitanie neznameho poct…
22. 12. 2016   #214179

#1 majkx
Formátovaný vstup ze standardních C i C++ streamů se chová tak, že požírá všechny bílé znaky a snaží se zpracovat "ne-bílá" data mezi nimi. Nepíšete, jestli váš formát je jedna řádka, nebo jestli máte opakovaně načítat řádky. Pokud to první, v C++ se to dá napsat velmi jednoduše: 

std::vector<int> data_;
std::copy(
    std::istream_iterator<int>(std::cin),
    std::istream_iterator<int>(),
    std::back_inserter(data_));

Pokud to druhé, můžete to načítat po řádkách (opakovat následující): 

/* -- read one line */
std::stringstream line_;
std::cin.get(*line_.rdbuf());
std::cin.get();  /* -- eat the newline */

/* -- parse the line */
std::vector<int> data_;
std::copy(
    std::istream_iterator<int>(line_),
    std::istream_iterator<int>(),
    std::back_inserter(data_));

Update: přehlédl jsem, že vysloveně nechcete std::string. Já sice používám streamy, ale std::string je pod tím schovaný (std::stringstream).

C / C++ › lineárně zřetězený seznam v C
22. 12. 2016   #214177

#4 Honza
Přečetl jsem si zadání a je to podle mne pouze jednoduchý jednosměrný spojový seznam, akorát je implementovaný nad polem - místo ukazatelů se používají indexy. A tím jak je to nad polem, tak je (pro pokročilé) ještě potřeba nějaké správy uvolněných položek (což se opět dá udělat jednodušše spojovým seznamem). Rozhodně podle zadání není potřeba žádný binární strom (zadání se jmenuje lineární zřetězený seznam).

C / C++ › Dijkstrův algoritmus
19. 12. 2016   #214115

#3 peter
Bohužel to tak nefunguje. Když se omezím pouze na šachovnici (což je méně obecné, než vyžaduje zadání), tak je potřeba si uvědomit, že nejkratší cesta nemusí nutně být také nejkratší na počet posunů na šachovnici (hran v grafu). Ve skutečnosti, pokud správně ohodnotíte hrany, vám nejkratší cesta může oběhnout několikrát šachovnici dokola nebo se různě kroutit apod. Takže pokud vámi popsaným algoritmem dosáhnete bodu B, v žádném případě nemáte jistotu, že jste našel nejkratší cestu.

C / C++ › Dijkstrův algoritmus
19. 12. 2016   #214111

#1 Michal
Takhle zběžným pohledem (pouze Dijkstra, menu a načítání vstupních dat jsem neřešil) mi připadá, že by to mělo, až na pár dost podstatných vad, fungovat. Není to sice zrovna nejefektivnější implementace Dijsktry, ale měla by být funkční. Ty podstatné vady jsou:

  • zvětšete si výrazně hodnotu pro nekonečno,
  • pole vybrano inicializujte v cyklu stejně jako pole vzdalenostprev,
  • v C se pole indexují od 0. Pokud máte for(i = 1; i < N; ++i), pak jste zapomněl projít první prvek a proiterujete pouze N - 1 prvků. Tahle chyba se vám vyskytuje všude včetně načítání vstupních dat.

Vzhledem k tomu, že v zadání máte "10 a více", tak výpis uzel + 65 nemůže fungovat. Místo charového pole si pro cestu udělejte intové pole a pomocí printf("%d") ji pak pozpátku vypište.

C / C++ › Pointer na pole struktur
19. 12. 2016   #214110

#1 Marcel
Pokud v C chcete do funkce předat pole, předává se jako ukazatel na první položku. A překladač vám pole, které dáte do argumentu volané funkce, na takový ukazatel automaticky převede. Tudíž v případě argumentu funkce není rozdíl mezi polem a ukazatelem (jde pouze o argument funkce, neznamená to, že není rozdíl mezi polem a ukazatelem).

Váš kód mi přijde téměř správný, pouze vám nesedí typ na řádce s mallocem a není důvod použít referenci při volání.

typedef struct point {
  double x;
  double y;
} POINT;

void test(POINT* p, int i) {
  p[i].x=nieco;
}

int main(int argc_, char* argv_[]) {
  int i = 0;
  scanf("%d",&n);
  POINT* p = (POINT*)malloc(n * sizeof(POINT));
  test(p, i);
  return 0;
}

Váš závěr, že je potřeba předávat ukazatel na ukazatel je mylný - z výše uvedené logiky byste musel mít pole ukazatelů na POINT, nikoliv pole POINTů.

C / C++ › SFML - Vstupní bod procedury…
26. 9. 2016   #212801

Nejsem Windowsář, ale tohle by vypadalo, že používáte jiný (jinou verzi) překladač, než se kterým byla sestavena knihovna. Každý překladač si dekoruje C++ symboly jinak a linker je pak nemůže najít. Udělal jste opravdu všechno, co je v odstavci Installing SFML?

C / C++ › převod řetězce na číslo bez…
21. 9. 2016   #212777

#7 hlucheucho
Ty algoritmy bohužel nejsou dobře. Pokud si znaménko k číslu přinásobíte před cyklem, tak se vám číslice pro záporná čísla budou odečítat, ne přičítat: 

-123: (-1 * 10 + 2) * 10 + 3 = -77

Znaménko musíte aplikovat vždy až na konec, přesně tak, jak to děláte u čísel s destinnými místy. Anebo byste ho musel přinásobit ke každé číslici.

C / C++ › převod řetězce na číslo bez…
21. 9. 2016   #212776

#5 MiCizek
Váš pocit není úplně správný. Když například kouknete do glibc na funkci strtol, tak zjistíte, že je dělaná v principu stejně, jako to, co jsem napsal tady já. Akorát ten kód vypadá strašně a něco z něho vyčíst je umění, protože řeší znaménka, různé základy, wide chars, oddělovače tisíců a má tam strašnou spoustu podmíněných překladů. Ale je to čisté C, o žádný assembler se tam nepokoušeli.

C / C++ › Alternativa pro referenci na…
16. 9. 2016   #212741

#17 Doomista
Tohle řešení funguje pouze pro kopírovatelné objekty a objekty které mají default konstruktor. Referenci nelze přiřadit, pouze inicializovat. Takže aby to fungovalo, musíte si nejdříve vytvořit prázdnou instanci navraceného objektu a v get metodě do ní přiřadit.

Tohle je strašně velké omezení, aby se to dalo považovat za obecně platné řešení. Automaticky jste tak totiž vyřadil objekty, které se kopírovat neumí. Což jsou například všechny polymorfní typy, které dělat kopírovatelné je cesta do pekla. Navíc u polymorfních typů dopředu nevíte, jakou konkrétní implementaci vám to vrátí, takže ani nejste schopný udělat dopředu prázdnou instanci.

std::pair asi fungovat bude, dokud si vystačíte s jeho kopírovacím konstruktorem. Jakmile budete potřebovat přiřazení, dostanete se do problému, protože reference nejde přiřazovat.

Suma sumárum, pořád se domnívám, že nejlepší obecné řešení, pokud nenalezený objekt není chyba, je vrátit ukazatel (normální nebo smart, pokud by se předávalo vlastnictví). Pokud je chyba, vracet referenci a vyhazovat výjimku.

C / C++ › Alternativa pro referenci na…
16. 9. 2016   #212737

#14 Kit
Tady jste vůbec nepochopil, o čem píšu. Výjimky samozřejmě propadávají vertikálně přes callstack. To je jejich normální vlastnost. Já ale ukazuji, že NullObject s metodami implementovanými výjimkami, způsobuje horizontální zpoždění. Výjimka vypadne z místa, které je vzdálené od místa, kde skutečně chyba nastala. V tomto příkladu chyba nastala tehdy, když nebyl nalezený záznam pro uživatele. Ale projeví se až bůhví kde při prvním přístupu k objektu. Vy pak sice ve výjimce vidíte, že chyba nastala při volání NullObject::něco(), ale už nemáte jak dohledat, proč se vůbec stalo, že jste dostal instanci NullObject.

Výjimky mají být vždy chybový stav. Jejich použití k něčemu jinému je obvykle špatně. To že se z chyby program umí na nějaké úrovni zotavit na tom nic nemění.

C / C++ › Alternativa pro referenci na…
16. 9. 2016   #212736

#13 Kit

  1. to je přesně to, o čem celou dobu mluvím. NullObject se hodí pouze někdy. Jsem rád, že jsme se shodli.
  2. Tím, že něco pojmenujete návrhovým vzorem, nijak neodstraníte problémy, které jsem popsal. Zkoušel jste si někdy implementovat singleton s double checked locking? Není to jednoduché, snadno tam uděláte chybu, a prakticky se to nedá ladit. Navíc singleton není v tomhle případě úplně to nejlepší filozoficky. Jeho hlavním cílem je zaručit maximálně jednu instanci, ale proč by NullObject obecně nemohl mít instancí víc?
  3. Nevšiml jsem si, že bych kdekoliv psal o getterech a setterech. Máte pravdu, že bohaté rozhraní může způsobovat těsné závislosti, ale vy jste mluvil o zapouzdření. Navíc ani settery a gettery zapouzdření neruší. (Čímž neříkám, že jsou dobře. Narušují něco, čemu já sám pro sebe říkám logické zapouzdření, normálně se mluví o anemických objektech.)

C / C++ › Alternativa pro referenci na…
15. 9. 2016   #212726

#8 Doomista
Ano, to je přesně to, co jsem měl na mysli výrokem "výjimky nepomohou." Pokud klientský kód výjimku neočekává, může to dělat pěkné brikule včetně pádu procesu.

Ale ani situace, kdy ji očekává není dobře. Vyhozená výjimka znamená chybový stav, takže se nabízí otázka, proč nevyhodit výjimku už při hledání objektu, jestliže nenalezení objektu je chybový stav. Takhle efektivně hlášení programu o chybovém stavu odsunete daleko od místa, kde k chybě skutečně došlo. A zkuste si odladit program, kde se vám chyby budou projevovat tisíce instrukcí od místa jejich vzniku 

C / C++ › Alternativa pro referenci na…
15. 9. 2016   #212725

#7 Kit

  1. Právě že obecně neušetří. Pokud budu mít nějakou vyhledávací strukturu (řekněme telefonní seznam), tak je zcela korektní a není chybovým stavem, že daný klíč v seznamu není. Daný člověk jednoduše nemá telefon. Klientský kód se v tomto případě bude skutečně chovat rozdílně pro situaci "našel" a pro situaci "nenašel" (někdy zobrazí dialog, někdy člověka přeskočí a nepošle mu spam SMS, atd.). Jak vytvoření něčeho jako NullPersonRecord v tomto případě ušetří práci? Klientský kód stejně musí výsledek nějakým způsobem porovnat a rozskočit se. Možnost, že by alternativní kód byl přímo v NullPersonRecord je čuňárna. Zaprvé porušíte single resonsibility, protože taková funkce do záznamu o uživateli logicky nepatří. Zadruhé půjde o velmi nepraktické a nerozšiřitelné řešení, protože budete muset přenést nesouvisející kód ze všech míst, která pracují s telefonním seznamem, na jedno místo.
  2. Pokud se nedá pořádně určit, co by měl null object dělat, tak rozhodně to rychleji mít nebudete. Navíc jeho implementace není jediné zdržení. V C++ totiž musíte nějak zajistit vytvoření instance null object tak, aby existovala i po opuštění funkce a mohl jste ji bezpečně vrátit. Pokud to uděláte jako globální proměnnou/konstantu, tak musíte zaručit, že ji nikdo nebude chtít nikdy použít před vstupem do main, protože pořadí dynamické inicializace modulů není definované. Pokud použijete nějakou formu lazy inicializace, tak se situace zase komplikuje kvůli synchronizaci vláken. (Připouštím, že C++11 hodně pomáhá, když už má inicializaci statických proměnných ve funkci synchronizovanou. Ale podpora C++11 ještě pořád není na všech překladačích, takže když se na to spolehnete, nebudete mít přenositelný kód.)
  3. Jak konkrétně bohaté rozhraní narušuje zapouzdření?

Nechápejte mě špatně, já proti NullObject nic nemám. Jsou situace, kdy se perfektně hodí a dokáže úžasným způsobem zjednodušit a zpřehlednit kód. Ale v žádném případě to není obecně platná odpověď na otázku "co vracet, pokud objekt neexistuje."

 

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý