Hva slags funksjon kan jeg bruke for å vite hvor mange elementer som er i en matrisetegn?
sizeof () gir antall «mellomrom» tilgjengelig så det ikke fungerer for meg.
Kommentarer
Svar
Du vil ha strlen
.
char foo [100] = "bar"; Serial.println (strlen (foo)); // --> prints 3
Kommentarer
- Hvis svaret fungerte for deg, vennligst klikk " godta " -knappen (det ser ut som et kryss). På den måten vil andre mennesker vite at løsningen fungerte.
- Jeg måtte vente et par minutter på å gjøre det
- Merk at dette bare fungerer hvis dataene i inneholder en ascii-streng, og er ordentlig null-avsluttet. Videre, hvis du har en lang streng i
char[]
, og du overskriver den med en kortere streng uten å legge til nullavslutningen, får du størrelsen på den eldre strengen. - Ganske riktig. Svaret mitt var på spørsmålet som ble presentert. De tingene du nevner, bør tas i betraktning for null-avsluttede C-strenger.
Svar
Jeg kjenner deg har svaret ditt fra @NickGammon, men jeg vil bare legge til litt mer inngående informasjon om hvordan alt dette fungerer.
sizeof()
er ikke en funksjon i ordets normale forstand. Det er en operatør som gir deg antallet byte minne som er tildelt hva du overfører til det. Hvis du sender det til en matrise, returnerer det antall byte som matrisen har tilgjengelig. Hvis du sender den en peker til en matrise, returnerer den størrelsen på pekeren, ikke størrelsen på matrisen. Hvis du sender den til et heltallsvariabel, returnerer det antallet byte som brukes av den heltallvariabelen (2 på en 8-bit system som AVR, 4 på et 32-biters system som Due).
Så noen eksempler:
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
Nå strlen()
. Hvordan skiller det seg akkurat fra sizeof()
? Enkelt sagt, teller antall tegn i en tegnoppstilling til den når tegnet \0
som er» NULL «-termineringstegnet til en C-streng. La oss ta eksemplene før, men bruk strlen i stedet:
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.
Du merker at det alltid returnerer antall tegn i strengen opp til, men inkluderer ikke, det etterfølgende \0
-tegnet.
I sin enkleste form kan strlen()
-funksjonen se slik ut:
int strlen(const char *data) { int c = 0; const char *p = data; while (*p) { c++; p++; } return c; }
I utgangspunktet starter det med det første tegnet i strengen (*p = data
), undersøker om det «sa \0
eller ikke (while (*p)
), øker antall tegn (c++
) og går videre til neste tegn i strengen (p++
).
Hvis du vil gjenta gjennom strengen i programmet ditt, kan du ringe strlen()
først for å få antall tegn i strengen, og bruk deretter verdien i en løkke. Det er litt bortkastet, siden strlen()
først itererer gjennom strengen, så du ender med å itere gjennom den to ganger. Det er langt mer effektivt å lære hvordan du best kan gå gjennom hvert tegn i strengen til du finner det avsluttende tegnet, for eksempel hvordan strlen()
-funksjonen bruker pekeren for å gå gjennom minnet. Du kan også se hvor viktig det er at du sørger for at \0
-tegnet eksisterer på slutten av strengen, ellers hvordan fungerer det som strlen()
vet når du skal stoppe? De kan ikke vite hvor lang strengen er (sizeof()
vil returnere størrelsen på pekeren den sendes, ikke størrelsen på matrisen), så de må ha en slags manuell markør, og konvensjonen i C er å bruke \0
.
Merk at Arduino «s print()
fungerer faktisk gjør det veldig ineffektivt. Hvis du gjør noe sånt som:
char message[] = "Hello"; Serial.println(message);
Det vil faktisk gjøre ganske mye arbeid, det trenger det ikke virkelig . trinn for trinn:
- samtaler println (melding)
- som ringer skriv (melding)
- som får strenglengden med strlen (melding)
- og kaller skriv (melding, lengde)
- som deretter sløyfer fra 0 til lengde-1 og sender hvert tegn i meldingen for å skrive () etter tur.
- skriver til slutt ut
\r\n
for den nye linjen.
Så det ender faktisk nestet rundt 4 funksjoner dypt, og gjentar hele strengen to ganger. A klassisk eksempel på hvordan man kaster bort behandlingstid.Ved å iterere gjennom strengen en gang på jakt etter \0
-tegnet i write(message)
-funksjonen (trinn 2), vil den fungere minst dobbelt så raskt. Gode gamle Arduino …
Kommentarer
- Re “I sin enkleste form kan strlen () -funksjonen se slik ut”, i en kortere ( kanskje enklere?) form kunne det se ut som:
int strlen(const char *data) { const char *p = data; while (*p++); return p-data-1; }
- @ jwpat7 Jeg sa " enkleste ", ikke " korteste og mest kompakte ". Den formen, selv om den er mindre og mer effektiv, er mye mye vanskeligere for OP (som åpenbart er ikke en programmerer) å forstå.
- Enig 🙂 Også lettere å gjøre feil i Og hvis
\0
er den siste tilgjengelige byten i et segment, vil*p++
feil. Menint strlen(const char *data) { const char *p = data; while (*p) ++p; return p-data; }
unngår det problemet. - Egentlig
*p++
vant ' t feil selv om\0
er den siste tilgjengelige byten i et segment;*p
-delen får tilgang til den siste byten; ++ -delen vil settep
til en ugyldig adresse; men da den ugyldige adressen ikke ' ikke blir referert til, oppstår det ingen feil på en typisk maskin. - Det er en makro for kompileringstid … Det ' er ikke en makro , det ' er en operatør (som " + " og " – " er operatører). De er lavere enn makroer som er ting som gjøres før prosessortiden. Se sizeof operator . Også Operatører i C ++
Svar
use sizeof char nnn[10]; for(int i=0; i< sizeof(nnn)/sizeof(char); i++){ }
Kommentarer
- Leste du spørsmålet riktig?
- OP-en sa
sizeof
" fungerer ikke ' for meg " og så foreslår du at du bruker sizeof. - kan ikke svare på spørsmålet når du bruker det samme ukjente
char foo [100] = "bar";
– er det det du mener? Du vil ha svaret: 3?