V tomto návodu se budeme zabývat optimalizací řetězců. Mimo jiné se dozvíte jak s řetězci pracovat. Jdeme na to.
Základy a výpočet velikosti řetězce
Všichni snad umíme vytvořit jednoduchý řetězec a nastavit mu hodnotu.
- Kód: Vybrať všetko
new str[5] = "ahoj";
Tento řetězec má ale 5 znaků, protože každému prázdnému poli v pawnu je základně přiřazena hodnota 0. Pawn to pojme jako:
- Kód: Vybrať všetko
new str[5] = "ahoj\0";
Pokud vytváříte řetězec bez přiřazení hodnoty, pawn provede toto.
- Kód: Vybrať všetko
new str[256];
for (new i;i<256;i++)
{
str[i] = 0;
}
Zde se dostáváme k jádru našeho problému. Vidíte že v případě 256ti znakového řetězce dochází k provedení cyklu for 256krát. Pokud použijeme řetězec s velikostí 128 znaků, dojde k ušetření 50% času při přiřazování hodnot. Čím více řetězců, tím více ušetříme času.
Dále se dostáváme k velikosti řetězce. Každý znak má 4 bajty.
- Kód: Vybrať všetko
new str[256];
256 * 4 = 1024
Rozdíl:
- Kód: Vybrať všetko
new str[128];
128 * 4 = 512
Pouze v tomto řetězci dojde k ušetření 512 bajtů paměti. Pokud toto uděláme například v 200 řetězcích, kde místo 256 dáme 128, dojde již k ušetření paměti o 102,4KB. To už je poměrně velká jednotka. Používáním větších řetězců může dojít k vážným problémům, kdy vám kompilátor vyhodí následující hlášky:
- Kód: Vybrať všetko
Header size: 200 bytes
Code size: 588 bytes
Data size: 512 bytes
Stack/heap size: 16384 bytes; estimated max. usage=10250 cells (41000 bytes)
Total requirements: 17684 bytes
- Kód: Vybrať všetko
Header size: 216 bytes
Code size: 776 bytes
Data size: 528 bytes
Stack/heap size: 16384 bytes; estimated max. usage: unknown, due to recursion
Total requirements: 17904 bytes
To znamená, že jste využili více paměti, než je možno. V důsledku toho může dojít k padání serveru, nefunkčnosti některých publiků a dalším vážným problémům. Proto je nutné zmenšovat řetězce.
Absolutně zarážející je tento příklad pawnerů:
- Kód: Vybrať všetko
dcmd_cmd(playerid, params[])
{
#pragma unused params
new str[256];
new name[256];
GetPlayerName(playerid, name, sizeof(name));
format (string, sizeof(string), "hráč %s se zaměstnal jako popelář", name);
SendClientMessageToAll(COLOR_CERVENA, string);
return 1;
}
Takže zde řetězce zabírají:
- Kód: Vybrať všetko
256 * 4 = 1024 * 2 = 2048 bajtů.
To je docela dost. Při naší optimalizaci:
- Kód: Vybrať všetko
128 * 4 = 512
24 * 4 = 96 + 512 = 608
Dojde k ušetření paměti o 1,44KB. To je opravdu hodně.
Důvody pro nepoužívání řetězců o velikosti 256 znaků
Nepotřebujete to vůbec
Maximální délka vstupu a výstupu na chat je 128 znaků. Pokud ale chcete ušetřit ještě více místa, můžete jednotlivé řetězce počítat.
- Kód: Vybrať všetko
new string[14];
format (string, sizeof(string), "delka stringu");
Jednoduše si spočítáte kolik má znaků (včetně mezer) a připočítáte jedna.
Další věcí jsou jména hráčů. Maximální velikost jména je 24 znaků, proč používat delší? Pro jméno je nejlepší dát vždy 24, protože nevíte jestli hráč má delší jméno. Pokud dáte třeba:
- Kód: Vybrať všetko
new name[15];
A hráč má 20 znakové jméno, dojde k nezobrazení některých znaků.
Zbytečné
Je zbytečné vytvářet velké řetězce, tak jako je zbytečné vytvářet více řetězců, jak ukáže následující příklad.
- Kód: Vybrať všetko
dcmd_ahoj(playerid, params[])
{
#pragma unused params
new string[256];
new string2[256];
format (string, sizeof(string), "ahoj zkousime string %d", promena(nejaka));
format (string, sizeof(string), "string je v poradku %d", promena(nejaka));
SendClientMessageToAll(COLOR_CERVENA, string);
SendClientMessageToAll(COLOR_CERVENA, string2);
return 1;
}
K čemu vytvářet 2 řetězce o takové velikosti, když to můžete udělat takto:
- Kód: Vybrať všetko
dcmd_ahoj(playerid, params[])
{
#pragma unused params
new string[128];
format (string, sizeof(string), "ahoj zkousime string %d", promena(nejaka));
SendClientMessageToAll(COLOR_CERVENA, string);
format (string, sizeof(string), "string je v poradku %d", promena(nejaka));
SendClientMessageToAll(COLOR_CERVENA, string);
return 1;
}
Zde dojde k ušetření:
- Kód: Vybrať všetko
256 * 4 = 1024 * 2 = 2048
- Kód: Vybrať všetko
128 * 4 = 512
1024 - 512 = 512
O 512 bajtů místa. Také dost, že?
Kdy je potřeba použít 256ti znakové řetězce nebo i vyšší
Čtení ze souborů
Při čtení ze souboru stylem řádek po řádku je někdy zapotřebí velký řetězec. Nelze odhadnout velikosti řetězce, ale vždycky je lepší více než méně.
SQL
SQL příkazy jsou velmi dlouhé. Někdy je i zapotřebí 1024 znaků.
Práce s řetězci
Dostali jsme se do druhé části našeho návodu, kterou je práce s řetězci. Popíšu vám tady základní funkce pro práci a úpravu řetězců.
Strcmp
Velmi známá funkce, která slouží pro porovnání dvou řetězců. Struktura:
- Kód: Vybrať všetko
strcmp(první string, druhý string, ignorace velikosti, délka(nepovinné))
Pokud je ignorace velikosti nastavena na hodnotu true je AhoJ to samé jako Ahoj. V případě false je to jiný řetězec.
Příklad:
- Kód: Vybrať všetko
if (strcmp(string, string2, true) == 0)
Funkce vrací hodnoty:
-1 - když je string před stringem2
1 - když je string po stringu2
0 - když jsou stejné
Strfind
Tato funkce hledá část řetězce v jiném. Struktura:
- Kód: Vybrať všetko
strfind(kde hledáme, co hledáme, ignorace velikosti, pozice);
Příklad:
- Kód: Vybrať všetko
if (strfind("Ahoj jak se mas?", "Ahoj", true) != -1);
-1 znamená že se řetězec Ahoj může nacházet kdekoli v řetězci Ahoj jak se mas a je tak prohledáván celý řetězec.
Strdel
Tato funkce vymaže část řetězce. Struktura:
- Kód: Vybrať všetko
strdel(string, začátek, konec);
Příklad:
- Kód: Vybrať všetko
new string[20] = "Ahoj jak se mas?";
strdel(string,0,5);
Takže zůstane pouze 'jak se mas?'
Strins
Tato funkce vloží část řetězce do jiného. Struktura:
- Kód: Vybrať všetko
strins(string, co vložit, pozice, délka(nepovinné));
Příklad:
- Kód: Vybrať všetko
strins("ja jsem ", "Iron", 9);
Výsledkem bude věta 'ja jsem Iron'
Strmid
Tato funkce vytáhne část řetězce. Struktura:
- Kód: Vybrať všetko
strins(kam ukládat, odkud vytahovat, začátek, konec, délka(nepovinné));
Příklad:
- Kód: Vybrať všetko
strmid(string, "ahoj jak se mas?", 0, 5);
Takže se vytáhne 'ahoj'.
Strlen
Také známá funkce, která zjišťuje délku řetězce. Struktura:
- Kód: Vybrať všetko
strlen(string);
Příklad:
- Kód: Vybrať všetko
new len = strlen("ahoj");
Proměnná len bude nabývat hodnotou 5-
Strpack
Užitečná funkce, která zjistí počet znaků řetězce a zmenší velikost. Struktura:
- Kód: Vybrať všetko
strpack(kam ukládá, originální řetězec, délka(nepovinné));
Příklad:
- Kód: Vybrať všetko
strpack(string, "ahoj");
String bude dlouhý 5 znaků.
Strval
Velmi známá funkce, která převede řetězec na číslo. Struktura:
- Kód: Vybrať všetko
strval(string);
Příklad:
- Kód: Vybrať všetko
new cislo = strval(string);
Strcat
Velice užitečná funkce, která spojí dva řetězce. Struktura:
- Kód: Vybrať všetko
strcat(základ, co dosadit, délka(nepovinné));
Příklad:
- Kód: Vybrať všetko
new string[40];
strcat(string, "Ahoj ");
strcat(string, "ja jsem iron");
Výsledek bude 'Ahoj ja jsem iron'.
Floatstr
Tato funkce převede řetězec na desetinné číslo. Struktura:
- Kód: Vybrať všetko
floatstr(string);
Příklad:
- Kód: Vybrať všetko
new string[5] = "14.58";
new Float:B = floatstr(string);
Hodnota B bude nabývat 14.58.
Další užitečné funkce pro práci s řetězci
Strtok
Tato funkce rozdělí řetězec v místě, kde najde určitý znak. Struktura:
- Kód: Vybrať všetko
stock strtok(const string[], &index,seperator=' ')
{
new length = strlen(string);
new offset = index;
new result[MAX_STRING];
while ((index < length) && (string[index] != seperator) && ((index - offset) < (sizeof(result) - 1)))
{
result[index - offset] = string[index];
index++;
}
result[index - offset] = EOS;
if ((index < length) && (string[index] == seperator))
{
index++;
}
return result;
}
- Kód: Vybrať všetko
strtok(co rozdělit, pozice(nepovinné), znak);
Příklad:
- Kód: Vybrať všetko
if (strcmp(cmdtext,"/call", true) == 0)
{
new tmp[128]; // hodnota pro strtok
new string[128];
idx; // index
tmp = strtok(cmdtext, idx); //rozdeleni retezce
format (string, sizeof(string), "hrac %s vola %s", PlayerName(playerid), tmp) // playerName jsem pouzil jako stock
SendClientMessageToAll(COLOR_CERVENA, string);
return 1;
}
Split
Pracuje podobně jako strtok, ale dělí celí řetězec. Struktura:
- Kód: Vybrať všetko
stock split(const strsrc[], strdest[][], delimiter)
{
new i, li;
new aNum;
new len;
while(i <= strlen(strsrc))
{
if(strsrc[i] == delimiter || i == strlen(strsrc))
{
len = strmid(strdest[aNum], strsrc, li, i, 128);
strdest[aNum][len] = 0;
li = i+1;
aNum++;
}
i++;
}
return 1;
}
- Kód: Vybrať všetko
split(string, string kam ukládat, znak);
Příklad:
- Kód: Vybrať všetko
new tmp[2][128];
split("ahoj vsichni",tmp, ' ');
print(tmp[0]);
Vypíše ahoj.
Beat
Úplně to stejné jako strtok. Pravděpodobně se s touto funkcí ani nesetkáte. Struktura:
- Kód: Vybrať všetko
stock beat(string[], arg, symbol, begin = 0) {
new output[32],outLen;
while (string[begin] && string[begin] == symbol) begin++;
while (string[begin]){
if (string[begin] == symbol) {
arg--;
while (string[++begin] == symbol) {}}
if (!arg){
new ch;
while ((ch = string[begin++]) && ch != symbol && outLen < (sizeof (output) - 1)) {
output[outLen++] = ch; }
output[outLen] = EOS;
return output; }
begin++; }
return output;
}
- Kód: Vybrať všetko
beat(string, argument, znak);
Chrfind
Opět to samé, nicméně doporučuji tuto funkci u DCMD příkazů pro vytvoření příkazu se 2 parametry. Struktura:
- Kód: Vybrať všetko
stock chrfind(n,h[],s=0)
{
new l=strlen(h);
while(s<l)
{
if(h[s]==n)
return s;s++;
}
return -1;
}
Příklad:
- Kód: Vybrať všetko
dcmd_kick(playerid, params[])
{
new vyhozeny = strval(params);
new id;
if (!params[0] || !(id = chrfind(' ', params) + 1) || !params[id]) return SendClientMessage(playerid, COLOR_SYSTEM, "/kick id duvod");
Kick(vyhozeny);
return 1;
}



)



