Jaký druh funkce mohu použít, abych zjistil, kolik prvků je v poli char?
sizeof () udává počet „mezer“, které jsou k dispozici, takže pro mě nefunguje.
Komentáře
Odpovědět
Chcete strlen
.
char foo [100] = "bar"; Serial.println (strlen (foo)); // --> prints 3
Komentáře
- Pokud odpověď pro vás fungovala, klikněte prosím na tlačítko " přijmout " (vypadá to jako zaškrtnutí). Ostatní lidé tak budou vědět, že řešení fungovalo.
- Musel jsem na to počkat několik minut
- Všimněte si, že to bude fungovat pouze , pokud budou data ve vašem obsahuje řetězec ASCII a je správně zakončen nulou. Kromě toho, pokud máte v
char[]
dlouhý řetězec a přepíšete jej kratším řetězcem bez přidání nulového zakončení, získáte velikost staršího řetězce. - Správně. Moje odpověď byla pro otázku, jak byla předložena. To, co zmiňujete, by mělo být vzato v úvahu pro řetězce C s nulovým zakončením.
Odpověď
Znám vás mít odpověď od @NickGammon, ale rád bych přidal trochu podrobnější informace o tom, jak to všechno funguje.
sizeof()
není funkce v normálním smyslu slova. Jedná se o operátor, který vám poskytne počet bajtů paměti přidělený kterémukoli, co mu předáte. Pokud mu předáte pole, vrátí počet bajtů, které má pole k dispozici. Pokud jej předáte ukazatel na pole, vrátí velikost tohoto ukazatele, nikoli velikost pole. Pokud mu předáte celočíselnou proměnnou, vrátí počet bajtů použitých touto celočíselnou proměnnou (2 na 8bitové systém jako AVR, 4 na 32bitovém systému, jako je Due).
Takže několik příkladů:
char array[50] = "hello"; // sizeof(array) = 50. char *array_p = array; // sizeof(array_p) = 2 or 4 depending on architecture. char single = "a"; // sizeof(single) = 1. char string[] = "hello"; // sizeof(string) = 6 (5 letters plus \0) - it allocates the memory at compile time to fit the string
Nyní strlen()
. Jak přesně se to liší od sizeof()
? Jednoduše řečeno, spočítá počet znaků v poli znaků, dokud nedosáhne znaku \0
, který je“ NULL „zakončovacím znakem řetězce C. Pojďme si vzít příklady dříve, ale místo toho použít strlen:
char array[50] = "hello"; // strlen(array) = 5. char *array_p = array; // strlen(array_p) = 5. char single = "a"; // strlen(single) = ERROR! strlen() doesn"t operate on single characters. char string[] = "hello"; // strlen(string) = 5.
Všimnete si, že vždy vrací počet znaků v řetězci až po, ale bez, koncový \0
znak.
Ve své nejjednodušší podobě může funkce strlen()
vypadat takto:
int strlen(const char *data) { int c = 0; const char *p = data; while (*p) { c++; p++; } return c; }
V zásadě začíná u prvního znaku v řetězci (*p = data
), zkoumá, zda „sa \0
nebo ne (while (*p)
), zvýší počet znaků (c++
) a přejde na další znak v řetězci (p++
).
Pokud chcete iterovat řetězcem v programu, můžete zavolat strlen()
nejprve získejte počet znaků v řetězci, potom použijte tuto hodnotu ve smyčce. To je trochu zbytečné, protože strlen()
nejprve iteruje řetězcem, takže iterací projdete dvakrát. Je mnohem efektivnější naučit se, jak nejlépe procházet jednotlivé znaky v řetězci, dokud nenajdete koncový znak, například jak funkce strlen()
používá ukazatel pro pohyb v paměti. Můžete také vidět, jak důležité je zajistit, aby na konci řetězce existoval znak \0
, jinak bude fungovat jako strlen()
víte, kdy přestat? Nemohou „vědět, jak dlouhý je řetězec (sizeof()
vrátí velikost předávaného ukazatele, nikoli velikost pole), takže musí mít nějaký druh ruční značka a konvence v jazyce C je používat \0
.
Všimněte si, že Arduino „s print()
skutečně funguje udělejte to velmi neefektivně. Pokud děláte něco jako:
char message[] = "Hello"; Serial.println(message);
Ve skutečnosti to udělá spoustu práce, kterou opravdu nepotřebujete. krok za krokem:
- volá println (zpráva)
- která volá write (zpráva)
- která získá délku řetězce strlen (zpráva)
- a zavolá write (zpráva, délka)
- která poté vytvoří smyčku od 0 do délky-1 a posílá postupně každý znak zprávy na write ().
- konečně vytiskne
\r\n
pro nový řádek.
Takže ve skutečnosti končí vnořený kolem hloubky 4 funkcí a dvakrát iteruje celý řetězec. A klasický příklad toho, jak ztrácet čas zpracováním.Když iterujete řetězcem, jakmile jednou hledáte \0
znak ve write(message)
funkci (krok 2), bude fungovat minimálně dvakrát rychleji. Staré dobré Arduino …
Komentáře
- Re „Ve své nejjednodušší podobě může funkce strlen () vypadat takto“, v kratším ( možná jednodušší?) forma by mohla vypadat takto:
int strlen(const char *data) { const char *p = data; while (*p++); return p-data-1; }
- @ jwpat7 řekl jsem " nejjednodušší ", ne " nejkratší a nejkompaktnější ". Této formě, i když je menší a efektivnější, je pro OP (která zjevně není programátorem) mnohem těžší pochopit.
- Souhlas 🙂 Také snazší dělat chyby v . A pokud je
\0
poslední přístupný bajt v segmentu,*p++
bude chybný. Aleint strlen(const char *data) { const char *p = data; while (*p) ++p; return p-data; }
se tomuto problému vyhne. - Ve skutečnosti
*p++
zvítězil ' t chyba, i když\0
je poslední přístupný bajt v segmentu; část*p
získá přístup k poslednímu bajtu; část ++ nastavíp
na neplatnou adresu; ale protože tato neplatná adresa není ' odkazována, na typickém stroji nedojde k žádné chybě. - Jedná se o makro v době kompilace … Není to ' makro , ' je to operátor (jako " + " a " – " jsou operátoři). Jsou na nižší úrovni než makra, což se děje v době před zpracováním. Viz sizeof operator . Také operátoři v C ++
odpověď
use sizeof char nnn[10]; for(int i=0; i< sizeof(nnn)/sizeof(char); i++){ }
Komentáře
- Četli jste otázku správně?
- OP řekl
sizeof
" nefunguje ' pro mě " a pak navrhujete použít sizeof. - can; t odpovědět na otázku při použití stejné neznámé
char foo [100] = "bar";
– myslíte tím přesně to? Chcete odpověď: 3?