Diskuze: Edit části textového souboru[c++]
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.


Ahoj, tak v prvé řadě, pokud otevřeš soubor v módu "w" jako write, soubor se vždy přepíše, to znamená, že by jsi nebyl schopný uchovávat týmu více, a vždy by jsi je přepsal tím jedním týmem, otevírej tedy soubor v módu "a" jako append, dále tam máš strukturu, kterou nevyužíváš, buď si deklaruj nějaké pole
struct sazky data[100]; //Uznej dle uvážení
, kde budeš hodnoty ze souboru například načítat, to je ten jednodušší způsob, já bych ale doporučoval naučit se dynamické alokování paměti, nebo tento problém řešit spojovým seznamem, ty sám si alokuješ velikost takovou, kolik potřebuješ a nemusíš řešit pak problémy, že v souboru máš 101 údajů a ty máš pole o 100 položkách. K té editaci a mazání, nepředpokládám, že by jsi tam měl údajů miliony, tak pro tebe nejjednodušší způsob bude načíst si všechny data ze souboru krásně do pole, dejme tomu, a poté jednoduše zjistíš, například podle čísla řádku, nebo jména klubu, který řádek potřebuješ editovat, vyzveš uživatele k zadání nových údajů a tento řádek přepíšeš, poté otevřeš soubor v módu "w" a vše tam znovu zapíšeš už po úpravě, mazání opět není nic složitého, můžeš to řešit stejně jak při editaci, najdeš řádek, který potřebuješ smazat a poté jednoduše z té dané pozice můžeš udělat něco jako:
for(i = radek; i < pocet - 1; i++) //Jsem na řádku, který chci odstranit
{
polozka[i] = polozka[i + 1]; //Přepisuji od řádku až do konce následujícím prvkem
}
--pocet; //Jelikož jsem položku odebral, tak snížím počet
Poté opět zapíšeš do souboru Doufám že jsem tě aspoň trošku nakopl, ale opravdu doporučuji se
naučit pracovat s dynamickou alokací paměti, tam to jde dělat mnohem
čistěji než vše mít staticky
Podívej se jak fungují struktury a tu uživatelskou nabídku udělej
univerzálnější, zkus nad tím ještě popřemýšlet
Kdyby jsi něco nevěděl tak se
klidně ptej
.
DarkCoder:28.11.2019 22:25
Tak jak to máš tak takto jednoduché to rozhodně nebude. Zadání je natolik rozsáhlé a komplexní, že jen základní kostra programu Ti zabere několik stovek řádků. Na to se připrav. Navíc procházení mezi položkami má konkrétní strukturu. Nemůžeš vše zadávat v jednom kroku, nic na sebe nenavazuje. Podívej se znova na nějaké stránky sázkové kanceláře a prohlédni si veškeré vazby.
Už úvodní stránka má nějakou podobu. Nelze začínat volbou když nevíš na so reaguješ. Na první stránce bude seznam sportů a pod ním nabídka volby. Uvědom si, že počet voleb bude dynamický v závislosti na počtu sportů. Pokud jich bude více, přibyde volba posun na další stránku. V závislosti na aktuální pozici v seznamu může přibýt posun na předchozí stránku. Kde bude volba ukončení aplikace je na tobě. Volby které budou dole bude Pridání, Editace, Mazání. Je třeba si uvědomit, že to je jen volba k typu sportu, tedy k úvodnímu seznamu.
Z volby sportu přecházíš na název ligy, z názvu ligy na zápas, ze zápasu na kurzy v zápasech mezi dvěma či vícero účastníky. Odtud na informace o týmu, soupisky, předchozí zápasy, statistiky, apod.
Pro jednoduchost použij pouze soubory, práce s adresáři si vyžaduje už pokročilejší znalost programování. Pro volbu můžeš použít to co se Ti zobrazuje na obrazovce nebo ID daného úkonu. Na základě výsledku volby přecházíš na další zobrazení a možnosti volby. Uvědom si, co ovlivňují zadané volby. Pokud například smažeš sport Fotbal, smažou se Ti všechny podkategorie pod ním. Když Edituješ položku, projeví se změna na všech dalších místech, apod.
ID je dobrá volba pro pohyb v aplikaci. Můžeš tak vyhledat daný úkon. Během programu si udržuješ informaci o maximálním ID. Když přidáváš novou položku, přiřazuješ mu unikátní ID.
Když budeš vědět spojitost mezi položkami a budeš mít nějaký návrh, můžeš začít tvořit. Při práci se soubory vnímej to, v jakém módu soubor otevíráš. Mnoho dobrých rad ohledně programátorského konceptu už bylo řečeno. Pokud se vydáš cestou čistého ID pro výběr volby, scanf() je postačující. V opačném případě používej fgets() a analyzuj a upravuj vstup. Bez dobré znalosti souborů a konceptu dynamické alokace se pro efektivně vypadající aplikaci neobejdeš.
Jirka Kadlec:29.11.2019 17:10
@DarkCoder Díky moc za rady, projekt má být jednoduchý, jsem na fakultě elektrotechniky a ostatní projekty typu jednoduchých old school her jsou na +- 50-100 řádků, takže jsem vážně nečekal, že to bude až tak složité... @Eric Hawlasek Díky moc, moc si vážím, že se snažíte pomoct, zatím mi na facebooku a ostatních fórech řekli akorát že se na to potřebuju naučit nějaké složité věci a že mi to bude trvat hodně dlouho.... Takže pokud to chápu dobře, mám si udělat jedno pole ve kterém budou všechny data jako název sportu, ligy, týmu atd... Vždycky jednu tu kompletní sadu dat budu ukládat na jeden řádek, takže bude na každém řádku jeden záznam. Ty jednotlivé věci v tom záznamu jako sport tým liga atd si mám oddělit třeba čárkou a pak když budu chtít změnit třeba nějaký tým, tak si najdu všechny řádky s tím týmem "pak je vymažu" a napíšu tam nové stejné řádky akorát s jiným názvem týmu? Jak mám vzít ten zbytek údajů v řádku který má zůstat stejný a vložit do něj tým, který je v tom řádku dejme tomu uprostěd... Smazat budu chtít potom celý řádek, to ano, ale jak to mám teda editovat, když měním jenom jednu věc v řádku? Potřebuju co nejjednodušší a nejméně časově náročné řešení, má to být projekt, na který mám dohromady 3 týdny (teď už jen 2) a měl by mít opravdu pár desítek řádků.. Probíráme jenom základy C++ konzolovek, je to předmět na pár kreditů který mám mimo obor... Ještě jednou díky moc..
Jirka Kadlec:29.11.2019 20:23
Resp. nevíte prosím jak přesně bych mohl najít v tom souboru všechny záznamy (řádky) ve kterých je slovo, které předtím uživatel zadá a pak je všechny vymazat? Našel jsem na to nějaké funkce, ale žádnou jsem nerozjel... Díky moc, pěkný večer.
DarkCoder:29.11.2019 21:31
Hledání slova v záznamu se dá jinak prezentovat jako hledání subřetězce v řetězci. K tomu v C slouží funkce strstr(), která se součástí knihovny string.h
Prototyp funkce je:
char *strstr(const char *mainstring, const char *substring)
kde:
- mainstring představuje konstantní ukazatel na začátek řetězce u kterého chceme přítomnost subřetězce otestovat
- substring představuje konstantní ukazatel na začátek řetězce jehož přítomnost chceme v hlavním řetězci otestovat
V případě úspěchu vrací funkce strstr() ukazatel na první výskyt subřetězce v řetězci. V opačném případě vrací NULL.
Následující příklad ukazuje použití funkce strstr().
#include <stdio.h>
#include <string.h>
int main(void) {
const char str[] = "Mam rad retezce";
const char substr[] = "retez";
if (strstr(str, substr)) printf("subretezec nalezen\n");
else printf("subretezec nenalezen\n");
return(0);
}
Pozn:
V některých programech může být použití této funkce nebezpečné a je to
i tvůj případ. Pokud budeš mít veškerá data uložena v jednom souboru,
popř. ne úplně rozdělena zvlášť, může mít nevhodná volba subřetězce
vliv i na záznamy, které měnit nechceš. Následné mazání záznamů
spojené s subřetězcem může mít fatální důsledky na správnou funkčnost
tvé aplikace.
Erik Hawlasek:30.11.2019 0:02
Ahoj, DarkCoder už tuto problematiku velmi krásně vysvětlil, no, otázka teda je, co to znamená, že to má být jednoduché, pokud to má být vše provázané mezi sebou, jak vysvětloval DarkCoder, doporučuji si prvně nakreslit jakési tabulky, které mezi sebou propojíš aby jsi viděl, do čeho se vlastně chystáš jít. Podobně to tedy realizuješ i v souboru. Struktura je zjednodušeně řečeno schránka schopná uchovávat data, je jen na tobě, jak s ní naložíš, dejme tomu že struktura Sport, by mohla obsahovat například:
struct Sport
{
int id_sportu;
char nazevSportu[100];
// další data, která potřebuješ
};
Řádek můžeš ukládat do souboru například takto:
1|Fotbal //Další data
Máš více možností, ve funki fscanf pro čtení ze souboru jde použít
krásný regulární výraz, kde si řetězec rozkouskuješ a celý ho do
struktury uložíš, poté už budeš mít nějakou podmínku, kde se budeš
ptát, jestli je id týmu shodné s tím, o který si žádáš (může to být
i název týmu, vše je na tobě Pokud zjistíš, že je shoda, znamená to, že jsi našel i onen
řádek v souboru, který máš načtený ve struktuře, s těmito daty už si
můžeš dělat operace které se ti zlíbí, pokud by jsi tyto hodnoty načetl
do toho pole, ale opravdu doporučuji používat dynamickou alokaci paměti
tak jsi schopný daný řádek
upravit a pak to znova do souboru zapsat... V knihovně <string.h> je
funkce strtok, pomocí které můžeš opět řádek rozdělit pomocí
oddělovačů
ale rychlejší
je to opravdu tím regulárním výrazem přes fscanf(), zmínil jsi základy
C++, tam bych se už určitě začal dívat na objektové programování
tvůj kód totiž prvky C++
nevyužívá vůbec. Takto zapsaný kód vypadá jako čisté Cčko
. Pokud by jsi chtěl použít
funkci strtok, načti celý řádek funkcí fgets() a ten pak zpracuj, tuto
funkci už taky zmínil DarkCoder. Jedná se tedy pouze o načtení dat ze
souboru, vyhledání daného prvku, například pro editaci a jen úprava jeho
jména a následné zapsání zpět do souboru, jo pokud to má být
provázané, nebude to tak jednoduché a budeš muset například na základě
získaných dat z jednoho souboru vyhledat data, která na to navazují, jak
může taková návaznost vypadat bylo již řečeno od DarkCodera, pro ukázku
ještě tedy přidám příklad s fscanf:
int i = 0;
FILE *file = fopen("sporty.txt", "r");
while(fscanf(file, "%d|%[^\n]", &sport[i].id_sportu, sport[i].nazevSportu) != EOF)
{
if(id == sport[i].id_sportu)
{
//našel jsem ho, vyzvu uživatele například k úpravě názvu sportu...
}
++i;
}
//zapíšeš po úpravě do souboru
fclose(file);
Kód jsem netestoval, takže tam může být nějaká chybka, ale jde o to
že nějak takto podobně to může vypadat, snad ti to tedy nějak pomohlo .
Zobrazeno 7 zpráv z 7.