C ++

Jak používat vektor C ++

Jak používat vektor C ++

Úvod

Pole je řada stejných typů objektů v po sobě následujících místech paměti. Pole nemůže zvětšit nebo zmenšit délku. Vektor je jako pole, ale jeho délku lze zvětšit nebo zmenšit. Vektor má tedy mnohem více operací než pole.

C ++ má mnoho knihoven, které všechny tvoří standardní knihovnu C ++. Jednou z těchto knihoven je knihovna kontejnerů. Kontejner je kolekce objektů a lze s ním provádět určité operace. C ++ kontejnery lze seskupit do dvou sad: sekvenční kontejnery a asociativní kontejnery. Sekvenční kontejnery jsou vektor, pole (ne stejné pole, o kterém jsme se již zmínili dříve), deque, forward_list a list. Jedná se o různé kolekce (datové struktury podobné maticím) a každá nabízí odlišné kompromisy.

Každý programátor by měl vědět, jak se rozhodnout, zda použít vektor, pole, deque, seznam vpřed nebo seznam. Když programátor potřebuje strukturu, která vyžaduje více operací než ty, které jsou spojeny s běžným polem, nemělo by se použít běžné pole.

Pokud úkol zahrnuje časté vkládání a mazání uprostřed sekvence, měl by se použít seznam nebo seznam vpřed. Pokud úkol zahrnuje časté vkládání a mazání na začátku nebo na konci sekvence, měl by být použit deque. Pokud tyto druhy operací nejsou vyžadovány, měl by se použít vektor.

Tento článek ukazuje, jak používat vektor C ++. K pochopení tohoto článku budete potřebovat určité znalosti o ukazatelích, referencích a polích C ++.

Třída a objekty

Třída je sada proměnných a funkcí, které pracují společně, kde proměnné nemají přiřazené hodnoty. Když jsou proměnným přiřazeny hodnoty, třída se stane objektem. Různé hodnoty dané stejné třídě vedou k různým objektům; to znamená, že různé objekty mohou být stejné třídy, ale mají různé hodnoty. Vytvoření objektu z třídy je také známé jako vytvoření instance objektu.

Termín vektor popisuje třídu. Objekt vytvořený z vektoru má název, který vybere programátor.

Funkce, která patří do třídy, je nutná k vytvoření instance objektu z třídy. V C ++ má tato funkce stejný název jako název třídy. Různé objekty vytvořené (instancované) ze třídy mají odlišná jména, která každému z nich dal programátor.

Vytvoření objektu z třídy znamená konstrukci objektu; to také znamená vytvořit instanci objektu.

Vektorová třída

Vektorová třída již byla definována a je v knihovně. Chcete-li použít třídu vektorů, musí programátor zahrnout záhlaví vektoru do souboru s následující směrnicí o předběžném zpracování:

#zahrnout

Jakmile je záhlaví zahrnuto, zpřístupní se všechny vektorové prvky (datové členy a členské funkce). Chcete-li použít objekt count k výstupu dat do terminálu (konzoly), musí být také zahrnuto záhlaví objektu. Chcete-li napsat program s vektorem, musí být zahrnuty minimálně následující záhlaví:

#zahrnout
#zahrnout

Vytvoření instance vektoru

int foo [10];

Nahoře je deklarace pole se jménem „foo“ a počtem prvků „10.„Toto je pole celých čísel. Deklarace vektoru je podobná. U vektoru je počet prvků volitelný, protože délka vektoru se může zvětšovat nebo zmenšovat.

V tomto bodě programu již byla v knihovně definována vektorová třída a byla zahrnuta hlavička. Vektor lze konkretizovat následujícím způsobem:

std :: vektor vtr (8);

Zde je vektor speciální funkce konstruktoru. Typ dat, která bude vektor obsahovat, je „int“ v hranatých závorkách. Termín „vtr“ je název zvolený programátorem pro vektor. A nakonec „8“ v závorkách je předběžný počet celých čísel, která vektor bude mít.

Termín „std“ znamená standardní jmenný prostor. Za tímto výrazem musí v této souvislosti následovat dvojtečka. Kdokoli může napsat vlastní knihovnu vektorových tříd a používat ji. C ++ však již má standardní knihovnu se standardními názvy, včetně „vector.„Chcete-li použít standardní název, musí standardnímu názvu předcházet std :: . Abyste se vyhnuli zadávání std :: pokaždé, když v programu zadáte standardní název, může programový soubor začínat následovně:

#zahrnout
#zahrnout
pomocí jmenného prostoru std;

Přetížení funkce

Když mají dva nebo více různých podpisů funkcí stejný název, říká se, že je přetížený. Při volání jedné funkce určuje počet a typ argumentů, která funkce se provede.

Konstrukce vektoru

Konstrukce vektoru znamená vytvoření instance (vytvoření) vektorového objektu. Funkce konstruktoru je přetížena následovně:

vektor název

Tím se vytvoří vektor délky nula a typ „T.„Následující příkaz vytvoří vektor nulové délky typu„ float “se jménem„ vtr: “

vektor vtr;

vektor jméno (n)

Tím se vytvoří vektor s n prvky typu „T.„Prohlášení pro tento vektor se čtyřmi floatovými prvky je následující:

vektor vtr (4);

vektor jméno (n, t)

Tím se vytvoří vektor n prvků inicializovaných na hodnotu t. Následující příkaz vytvoří vektor 5 prvků, kde každý prvek má hodnotu 3.4:

vektor vtr (5, 3.4);

Konstrukce s inicializací

Vektor lze zkonstruovat (vytvořit) a inicializovat současně jedním z následujících dvou způsobů:

vektor vtr = 1.1, 2.2, 3.3, 4.4;

Nebo

vektor vtr 1.1, 2.2, 3.3, 4.4;

Všimněte si, že těsně za názvem objektu nejsou žádné závorky. Závorky použité hned za názvem objektu by měly mít seznam inicializátorů, a to následovně:

vektor vtr (1.1, 2.2, 3.3, 4.4);

Vektor lze sestavit a inicializovat později pomocí seznamu inicializátorů. V tomto případě se závorky nepoužijí:

vektor vtr;
vtr = 1.1, 2.2, 3.3, 4.4;

vektor V2 (V1)

Toto je konstruktor kopírování. Vytvoří vektor V2 jako kopii vektoru V1. Následující kód to ilustruje:

vektor vtr1 (5, 3.4);
vektor vtr2 (vtr1);

Přiřazení vektoru během výstavby

Během konstrukce lze vytvořit prázdný vektor, zatímco k němu je přiřazen jiný, a to následovně:

vektor vtr1 1.1, 2.2, 3.3, 4.4;
vektor vtr2 = vtr1;

Druhé prohlášení je ekvivalentní:

vektor vtr2 = 1.1, 2.2, 3.3, 4.4;

const vektor

Const vektor je vektor, jehož prvky nelze změnit. Hodnoty v tomto vektoru jsou jen pro čtení. Po vytvoření se vektor zobrazí takto:

vektor konst vtr 1.1, 2.2, 3.3, 4.4;

V tomto typu vektoru nelze přidat ani odebrat žádný prvek. Navíc nelze měnit žádnou hodnotu.

Stavba s Iterátorem

Šablona poskytuje obecnou reprezentaci pro datový typ. Iterátor poskytuje obecnou reprezentaci skenování přes hodnoty kontejneru. Syntaxe pro vytvoření vektoru s iterátorem je následující:

šablona
vektor (nejprve InputIterator, poslední InputIterator, const Allocator & = Allocator ());

Tím se vytvoří vektor pro rozsah [první, poslední) pomocí zadaného alokátoru, který bude popsán dále v tomto článku.

Zničení vektoru

Chcete-li zničit vektor, jednoduše jej nechte vyjít z rozsahu a destrukce je zpracována automaticky.

Vektorová kapacita

size_type capacity () const noexcept

Celkový počet prvků, které může vektor obsahovat bez nutnosti přerozdělení, je vrácen funkcí členské kapacity. Segment kódu je následující:

vektor vtr (4);
int num = vtr.kapacita();
cout << num << '\n';

Výstup je 4.

rezerva (n)

Paměťový prostor není vždy volně dostupný. Extra prostor lze rezervovat předem. Zvažte následující segment kódu:

vektor vtr (4);
vtr.rezerva (6);
cout << vtr.capacity() << '\n';

Výstup je 6. Rezervovaný prostor navíc je tedy 6 - 4 = 2 prvky. Funkce vrátí neplatnost.

size () const noexcept

Tím se vrátí počet prvků ve vektoru. Následující kód ilustruje tuto funkci:

vektor vtr (4);
float sz = vtr.velikost();
cout << sz << '\n';

Výstup je 4.

shrink_to_fit ()

Poté, co přidáte další kapacitu vektoru pomocí funkce reserve (), lze vektor zmenšit tak, aby odpovídal původní velikosti. Následující kód to ilustruje:

vektor vtr (4);
vtr.rezerva (6);
vtr.shrink_to_fit ();
int sz = vtr.velikost();
cout << sz << '\n';

Výstup je 4 a ne 6. Funkce vrátí neplatnost.

resize (sz), resize (sz, c)

Tím se změní velikost vektoru. Pokud je nová velikost menší než stará velikost, pak se prvky ke konci vymažou. Pokud je nová velikost delší, přidá se ke konci nějaká výchozí hodnota. Chcete-li přidat konkrétní hodnotu, použijte funkci resize () se dvěma argumenty. Následující segment kódu ilustruje použití těchto dvou funkcí:

vektor vtr1 1.1, 2.2, 3.3, 4.4;
vtr1.změnit velikost (2);
cout << "New size of vtr1: " << vtr1.size() << '\n';
vektor vtr2 1.1, 2.2;
vtr2.změnit velikost (4, 8.8);
cout << "vtr2: "<< vtr2[0] <<" "<< vtr2[1] <<"
"<< vtr2[2] <<" "<< vtr2[3] << '\n';

Výstup je následující:

Nová velikost vtr1: 2
vtr2: 1.1 2.2 8.8 8.8

Funkce vrátí neplatnost.

empty () const noexcept

Tato funkce vrací 1 pro true, pokud ve vektoru nejsou žádné prvky, a 0 pro false, pokud je vektor prázdný. Pokud má vektor 4 umístění pro určitý typ dat, například float, bez jakékoli hodnoty float, pak tento vektor není prázdný. Následující kód to ilustruje:

vektor vtr;
cout << vtr.empty() << '\n';
vektor vt (4);
cout << vt.empty() << '\n';
vektor v (4,3.5);
cout << v.empty() << '\n';

Výstup je následující:

1
0
0

Přístup k vektorovým prvkům

Vektor lze subskriptovat (indexovat) jako pole. Počítání indexu začíná od nuly.

vectorName [i]

Operace „vectorName [i]“ vrací odkaz na prvek v ith index vektoru. Následující kód výstupy 3.3 pro výše uvedený vektor:

vektor vtr 1.1, 2.2, 3.3, 4.4;
float fl = vtr [2];
cout << fl << '\n';

vectorName [i] konst

Operace „vectorName [i] const“ je provedena místo „vectorName [i]“, když je vektor konstantní vektor. Tato operace se používá v následujícím kódu:

vektor konst vtr 1.1, 2.2, 3.3, 4.4;
float fl = vtr [2];
cout << fl << '\n';

Výraz vrací konstantní odkaz na ith prvek vektoru.

Přiřazení hodnoty dolním indexem

Hodnotu lze přiřadit nekonstantnímu vektoru následovně:

vektor vtr 1.1, 2.2, 3.3, 4.4;
vtr [2] = 8.8;
cout << vtr[2] << '\n';

Výstup je 8.8.

vectorName.v (i)

„VectorName.at (i) “je jako„ vectorName [i] “, ale„ vectorName.at (i) ”je spolehlivější. Následující kód ukazuje, jak by měl být tento vektor použit:

vektor vtr 1.1, 2.2, 3.3, 4.4;
float fl = vtr.v (2);
cout << fl << '\n';
at () je vektorová členská funkce.

vectorName.at (i) const

„VectorName.at (i) const “je jako„ vectorName [i] const “, ale„ vectorName.at (i) const “je spolehlivější. „VectorName.at (i) const “se provede místo„ vectorName.at (i) “, když je vektor konstantní vektor. Tento vektor se používá v následujícím kódu:

vektor konst vtr 1.1, 2.2, 3.3, 4.4;
float fl = vtr.v (2);
cout << fl << '\n';
at () const je vektorová členská funkce.

Přiřazení hodnoty pomocí funkce at ()

Hodnotu lze přiřadit nekonstantnímu vektoru pomocí funkce at (), a to následovně:

vektor vtr 1.1, 2.2, 3.3, 4.4;
vtr.v (2) = 8.8;
cout << vtr[2] << '\n';

Výstup je 8.8.

Problém s podskriptováním

Problém subskriptování (indexování) spočívá v tom, že pokud je index mimo rozsah, může být vrácena nula nebo může dojít k chybě za běhu.

přední()

Tím se vrátí odkaz na první prvek vektoru bez odebrání prvku. Výstup následujícího kódu je 1.1.

vektor vtr 1.1, 2.2, 3.3, 4.4;
float fl = vtr.přední();
cout << fl << '\n';

Prvek není odstraněn z vektoru.

přední () konst

Když před vektorovou konstrukcí předchází const, provede se výraz „front () const“ místo „front ().„Toto se používá v následujícím kódu:

vektor konst vtr 1.1, 2.2, 3.3, 4.4;
float fl = vtr.přední();
cout << fl << '\n';

Je vrácena konstantní reference. Prvek není odstraněn z vektoru.

zadní()

Tím se vrátí odkaz na poslední prvek vektoru bez odebrání prvku. Výstup následujícího kódu je 4.4.

vektor vtr 1.1, 2.2, 3.3, 4.4;
float fl = vtr.zadní();
cout << fl << '\n';

zpět () konst

Když před vektorovou konstrukcí předchází const, provede se výraz „back () const“ místo „back ().„Používá se v následujícím kódu:

vektor konst vtr 1.1, 2.2, 3.3, 4.4;
float fl = vtr.zadní();
cout << fl << '\n';

Je vrácena konstantní reference. Prvek není odstraněn z vektoru.

Přístup k vektorovým datům

data () noexcept; data () const noexcept;

Kterýkoli z těchto ukazatelů vrací ukazatel, takže [data (), data () + size ()) je platný rozsah.

Tomu se budeme podrobněji věnovat dále v článku.

Vracející se Iterátoři a vektor

Iterátor je jako ukazatel, ale má více funkcí než ukazatel.

begin () noexcept

Vrátí iterátor, který ukazuje na první prvek vektoru, jako v následujícím segmentu kódu:

vektor vtr 1.1, 2.2, 3.3, 4.4;
vektor:: iterator iter = vtr.začít();
cout << *iter << '\n';

Výstup je 1.1. Všimněte si, že byla deklarována deklarace, která přijímá iterátor. Iterátor je ve vráceném výrazu dereferencován, aby získal hodnotu stejným způsobem, jako je dereferencován ukazatel.

begin () const noexcept;

Vrátí iterátor, který ukazuje na první prvek vektoru. Když před vektorovou konstrukcí předchází const, provede se výraz „begin () const“ namísto „begin ().„Za této podmínky nelze odpovídající prvek ve vektoru upravit. Používá se v následujícím kódu:

vektor konst vtr 1.1, 2.2, 3.3, 4.4;
vektor:: const_iterator iter = vtr.začít();
cout << *iter << '\n';

Výstup je 1.1. Všimněte si, že pro přijetí vráceného iterátoru byl tentokrát použit pouze „const_iterator“ namísto „iterátoru“.

end () noexcept

Vrátí iterátor, který směřuje bezprostředně za poslední prvek vektoru. Zvažte následující segment kódu:

vektor vtr 1.1, 2.2, 3.3, 4.4;
vektor:: iterator iter = vtr.konec();
cout << *iter << '\n';

Výstup je 0, což nemá smysl, protože za posledním prvkem není žádný konkrétní prvek.

end () const noexcept

Vrátí iterátor, který směřuje bezprostředně za poslední prvek vektoru. Když před vektorovou konstrukcí předchází „const“, místo „end () se provede výraz„ end () const “.„Zvažte následující segment kódu:

vektor konst vtr 1.1, 2.2, 3.3, 4.4;
vektor:: const_iterator iter = vtr.konec();
cout << *iter << '\n';

Výstup je 0. Všimněte si, že pro přijetí vráceného iterátoru byl tentokrát použit pouze „const_iterator“ namísto „iterátoru“.

Reverzní iterace

Je možné mít iterátor, který iteruje od konce těsně před první prvek.

rbegin () noexcept

Vrátí iterátor, který ukazuje na poslední prvek vektoru, jako v následujícím segmentu kódu:

vektor vtr 1.1, 2.2, 3.3, 4.4;
vektor:: reverse_iterator rIter = vtr.rbegin ();
cout << *rIter << '\n';

Výstup je 4.4.

Všimněte si, že byla deklarována deklarace, která přijímá zpětný iterátor. Iterátor je ve vráceném výrazu dereferencován, aby získal hodnotu stejným způsobem, jako je dereferencován ukazatel.

rbegin () const noexcept;

Vrátí iterátor, který ukazuje na poslední prvek vektoru. Když před vektorovou konstrukcí předchází „const“, místo „rbegin () se provede výraz„ rbegin () const “.„Za této podmínky nelze odpovídající prvek ve vektoru upravit. Tato funkce se používá v následujícím kódu:

vektor konst vtr 1.1, 2.2, 3.3, 4.4;
vektor:: const_reverse_iterator rIter = vtr.rbegin ();
cout << *rIter << '\n';

Výstup je 4.4.

Všimněte si, že const_reverse_iterator byl tentokrát použit místo pouhého reverzního_iterátoru k přijetí vráceného iterátoru.

rend () noexcept

Vrátí iterátor, který ukazuje těsně před první prvek vektoru. Zvažte následující segment kódu:

vektor vtr 1.1, 2.2, 3.3, 4.4;
vektor:: reverse_iterator rIter = vtr.rend ();
cout << *rIter << '\n';

Výstup je 0, což nemá smysl, protože těsně před prvním prvkem není žádný konkrétní prvek.

rend () const noexcept

Vrátí iterátor, který ukazuje těsně před první prvek vektoru. Když před vektorovou konstrukcí předchází „const“, místo „rend () se provede výraz„ rend () const “.„Zvažte následující segment kódu:

vektor konst vtr 1.1, 2.2, 3.3, 4.4;
vektor:: const_reverse_iterator rIter = vtr.rend ();
cout << *rIter << '\n';

Výstup je 0.

Všimněte si, že const_reverse_iterator byl tentokrát použit místo pouhého reverzního_iterátoru k přijetí vráceného iterátoru.

Vektorové modifikátory

Modifikátor, který upravuje vektor, může převzít nebo vrátit iterátor.

A.emplace (p, args)

Vloží objekt typu T zkonstruovaný pomocí std :: forward(args)… před p.

Podrobnosti - viz dále

insert (iteratorPosition, value)

Vloží kopii hodnoty na pozici iterátoru vektoru. Vrátí iterátor (pozici) ve vektoru, kde byla umístěna kopie. Následující kód ukazuje, kam byla hodnota umístěna:

vektor vtr 10, 20, 30, 40;
vektor:: iterator iter = vtr.začít();
++iter;
++iter;
vtr.vložka (iter, 25);
cout << vtr[1] << " << vtr[2]<< '
'' << vtr[3] << '\n';

Výstup je: 20 25 30.

Všimněte si, že iterátor byl pokročilý (zvýšený) stejně jako ukazatel.

Lze také vložit seznam inicializátorů, jak ukazuje následující kód:

vektor vtr 10, 20, 30, 40;
vektor:: iterator iter = vtr.začít();
++iter;
++iter;
vtr.insert (iter, 25, 28);
cout << vtr[1] << " << vtr[2]<< '
'' << vtr[3]<< " << vtr[4] << '\n';

Výstup je: 20 25 28 30.

vymazat (poloha)

Odebere prvek na pozici, na kterou ukazuje iterátor, a poté vrátí pozici iterátoru. Následující kód to ilustruje:

vektor vtr 10, 20, 30, 40;
vektor:: iterator iter = vtr.začít();
++iter;
++iter;
vtr.vymazat (iter);
cout << vtr[0] << " << vtr[1] << '
'' << vtr[2]<< '\n';

Výstup je: 10 20 40

push_back (t), push_back (rv)

Slouží k přidání jednoho prvku na konec vektoru. Použijte push_back (t) následujícím způsobem:

vektor vtr 1.1, 2.2, 3.3, 4.4;
vtr.push_back (5.5);
float fl = vtr [4];
cout << fl << '\n';

Výstup je 5.5.

push_back (rv): - viz dále.

pop_back ()

Odebere poslední prvek bez jeho vrácení. Velikost vektoru se zmenší o 1. Následující kód to ilustruje:

vektor vtr 1.1, 2.2, 3.3, 4.4;
vtr.pop_back ();
float sz = vtr.velikost();
cout << sz << '\n';

Výstup je 3.

A.vyměnit (b)

Lze zaměnit dva vektory, jak je znázorněno v následujícím segmentu kódu:

vektor vtr1 1.1, 2.2, 3.3, 4.4;
vektor vtr2 10, 20;
vtr1.swap (vtr2);
cout << "vtr1: "<< vtr1[0] <<" "<< vtr1[1] <<"
"<< vtr1[2] <<" "<< vtr1[3] << '\n';
cout << "vtr2: "<< vtr2[0] <<" "<< vtr2[1] <<"
"<< vtr2[2] <<" "<< vtr2[3] << '\n';

Výstupem je:

vtr1: 10 20 0 0
vtr2: 1.1 2.2 3.3 4.4

Pamatujte, že délka vektoru se v případě potřeby zvětší. Také hodnoty, které neměly nahrazení, jsou nahrazeny nějakou výchozí hodnotou.

Průhledná()

Odebere všechny prvky z vektoru, jak ukazuje následující segment kódu:

vektor vtr 1.1, 2.2, 3.3, 4.4;
vtr.Průhledná();
cout << vtr.size() << '\n';

Výstup je 0.

Rovnost a relační operátoři pro vektory

Operátor ==

Vrátí 1 pro true, pokud mají dva vektory stejnou velikost a odpovídající prvky jsou stejné; v opačném případě vrátí hodnotu 0 pro false. Například:

vektor U 1, 2, 3;
vektor V 4, 5, 6;
bool bl = U == V;
cout << bl << '\n';

Výstup je 0.

The != Operátor

Vrátí 1 pro true, pokud dva vektory nemají stejnou velikost a / nebo odpovídající prvky nejsou stejné; v opačném případě vrátí 0 pro false. Například:

vektor U 1, 2, 3;
vektor V 4, 5, 6;
bool bl = U!= V;
cout << bl << '\n';

Výstup je 1.

The < Operator

Vrátí 1 pro true, pokud je první vektor počáteční podmnožinou druhého vektoru, přičemž prvky dvou stejných částí jsou stejné a ve stejném pořadí. Pokud mají oba vektory stejnou velikost a pohybují se zleva doprava a v prvním vektoru se setká s prvkem, který je menší než odpovídající prvek ve druhém vektoru, bude i nadále vrácen 1. V opačném případě se vrátí 0 pro false. Například:

vektor U 3, 1, 1;
vektor V 3, 2, 1;
bool bl = Ucout << bl << '\n';

Výstup je 1. < does not include the case when the size and order are the same.

Provozovatel

Vrací se !(U < V), where U is the first vector and V is the second vector, according to the above definitions.

The <= Operator

Vrací U <= V, where U is the first vector and V is the second vector, according to the above definitions.

Operátor> =

Vrací se !(U <= V), where U is the first vector and V is the second vector, according to the above definitions.

Závěr

Vektor je příkladem kontejneru sekvence. Vektor je „lepší“ forma běžného pole a je vytvořen z třídy. Vektory mají metody, které jsou klasifikovány pod: konstrukce a přiřazení, kapacita, přístup k prvkům, přístup k datům, iterátory, modifikátory a numerické přetížené operátory.

Existují další kontejnery sekvence, které se nazývají list, forward_list a array. Pokud úkol zahrnuje časté vkládání a mazání uprostřed sekvence, měl by se použít seznam nebo seznam vpřed. Pokud úkol zahrnuje časté vkládání a mazání na začátku nebo na konci sekvence, pak by měl být použit deque. Vektory by se tedy měly používat pouze v případě, že tyto druhy operací nejsou důležité.

Hry Porty komerčních her s otevřeným zdrojovým kódem
Porty komerčních her s otevřeným zdrojovým kódem
Zdarma, s otevřeným zdrojovým kódem a multiplatformní herní enginy lze hrát staré i některé z poměrně nedávných herních titulů. Tento článek uvede sez...
Hry Nejlepší hry z příkazového řádku pro Linux
Nejlepší hry z příkazového řádku pro Linux
Příkazový řádek není při používání Linuxu jen vaším největším spojencem - může být také zdrojem zábavy, protože jej můžete použít k hraní mnoha zábavn...
Hry Nejlepší aplikace pro mapování gamepadu pro Linux
Nejlepší aplikace pro mapování gamepadu pro Linux
Pokud rádi hrajete hry na Linuxu s gamepadem místo typického vstupního systému pro klávesnici a myš, máte k dispozici několik užitečných aplikací. Mno...