Idiomatikus trim funkciót próbálok C-be írni. Hogyan néz ki ez? Inkább össze kellene állítanom az új karakterláncot, és vissza kell adnom?
void trim(const char *input, char *result) { int i, j = 0; for (i = 0; input[i] != "\0"; i++) { if (!isspace(input[i])) { result[j++] = input[i]; } } }
Megjegyzések
- Ott ‘ a kód hibáinak száma, ‘ kiszolgáltatott a puffertúlcsordulási támadásoknak, és nem ‘ t csináld, amit egy tipikus ” trim ” függvény csinál. A vágás eltávolítja a vezető és a záró szóközt. Ez kicsúsztatja őket.
- Köszönöm. Tudna részletesen bemutatni egy puffertúlcsordulási támadás kezelését?
- Soha nem szabad vakon másolnia az adatokat valamilyen pufferbe, ha nem tudja, hogy ‘ mennyi hely van kiosztva. rá, hogy ‘ csak problémát kér. Egyszerű tennivaló lenne egy olyan paraméter hozzáadása, amely befogadja a puffer méretét. Így ‘ a hívó félnek elmondani, hogy valójában mekkora. Ezután ‘ rajtad múlik, hogy soha ne próbálj meg olvasni / írni a megadott hosszon túl. Természetesen ‘ nem bolond bizonyíték, a hívó fél hamis hosszúságot adhat meg, de ez nem a tiéd, hanem a végük problémája lenne.
Válasz
Mint @JeffMercado rámutatott, ez eltávolítja a szóközöket a vezető és a záró szóközök levágása helyett. Feltéve, hogy meg akarja tartani a jelenlegi funkcionalitást, hívjuk “div div = = 7c4491d7a8”>
-nek.
Itt nagyon finom hiba van:
... isspace(input[i]) ...
isspace
egy előjel nélküli karakter vagy EOF
. A rendszerint aláírt char
átadása meghatározatlan viselkedést eredményez. Ehelyett mondja ki:
... isspace((unsigned char) input[i]) ...
Egy másik hiba: nem ad ki NUL terminátort, vagyis a hívónak nincs módja tudni, hogy a karakterlánc milyen hosszú ( hacsak nem nullázta le a puffert a függvény meghívása előtt).
Ezen hibák kijavításával kapunk:
void remove_spaces(const char *input, char *result) { int i, j = 0; for (i = 0; input[i] != "\0"; i++) { if (!isspace((unsigned char) input[i])) { result[j++] = input[i]; } } result[j] = "\0"; }
@JeffMercado is ezt a függvényt mondta érzékeny a puffertúlcsordulásra. Bizonyos értelemben ez nem igaz, feltéve, hogy a hívó tudja, hogy legalább strlen(input) + 1
puffert rendeljen hozzá. De a hívó fél lusta lehet, és csak azt mondja, hogy char result[100]
. Kimeneti pufferméret-paraméter hozzáadása valószínűleg megvéd az ilyen hibáktól:
void remove_spaces(const char *input, char *output, size_t output_size);
Nézze meg, megvalósíthatja-e ezt Néhány szem előtt tartandó dolog:
-
A kimeneti puffer méretének ellenőrzésénél ne felejtsd el a NUL terminátort.
-
Ne legyen olyan, mint strncpy , és hagyja ki a NUL terminátort, amikor meg kell csonkolnia a karakterláncot, mivel ez finom hibákhoz vezethet.
-
Ha a
int
elemet használja ai
és aj
éssize_t
output_size
esetén kapjon fordítói figyelmeztetéseket az aláírt és az aláíratlan összehasonlításáról. Ha nem, akkor kapcsolja be a fordító figyelmeztetéseit. Ha a GCC-t a parancssorból használja, akkor szokjon gépelnigcc -Wall -W
.
Megjegyzések
-
strncpy()
nem string függvény, még bár egyesek feltételezik. Tehát a karakterlánc eredménye egyébként is történés lenne. Ami az analógiát legjobb esetben is vázlatosá teszi.
Válasz
Tudjuk, hogy egy mutatót előre és hátra mozgathatunk , és azt is tudjuk, hogy balról levághatunk egy húrt. Ha növekszünk a mutatóval, és csökkentjük a mutatót a jobb oldalról történő vágáshoz, akkor két while
hurok elegendő. Észre fogja venni, hogy a jobb séta száma kisebb, mint a bal séta száma.
Jobbra szabott kód:
#include <stdio.h> #include <ctype.h> void trim_both(char *, char *); int main (void) { char title[100] = " My long string "; char title_t[100] = ""; (void) printf("String before left trim is:[%s]\n", title); trim_both(title, title_t); (void) printf("String after left trim is:[%s]\n", title_t); } // trim spaces from left void trim_both(char *title_p, char *title_tp) { int flag = 0; // from left while(*title_p) { if(!isspace((unsigned char) *title_p) && flag == 0) { *title_tp++ = *title_p; flag = 1; } title_p++; if(flag == 1) { *title_tp++ = *title_p; } } // from right while(1) { title_tp--; if(!isspace((unsigned char) *title_tp) && flag == 0) { break; } flag = 0; *title_tp = "\0"; } }
Válasz
Legegyszerűbb mód (csak a szóközök eltávolítása):
Trim.Start:
- A karakterek összehasonlítása a karakterlánc elején
" "
(szóköz vagy más karakterek, például\n
vagy\t
) és növekményes temp (i
) változó. - Mutató mozgatása a
i
(str+=i
). Most a karakterlánc olyan karakterből indul, amely nem szóköz (vagy bármely más fehér karakter).
Trim.End:
- Tegye ugyanazt, amit a Trim.Start esetében, de a karakterlánc végétől kezdve.
- Állítsa be az utolsó karaktert (utolsó szóköz)
\0
.
Az a fontos, hogy a függvény a mutatót mutatóra (húrra) vigye.Figyelje a függvényhívást: StringTrim(&p2);
char * StringTrim(char * *pointerToString) { u8 start=0, length=0; // Trim.Start: length = strlen(*pointerToString); while ((*pointerToString)[start]==" ") start++; (*pointerToString) += start; if (start < length) // Required for empty (ex. " ") input { // Trim.End: u8 end = strlen(*pointerToString)-1; // Get string length again (after Trim.Start) while ((*pointerToString)[end]==" ") end--; (*pointerToString)[end+1] = 0; } return *pointerToString; }
Használat:
char str1[] = " test1 "; char * p1 = str1; Debug("1. before trim: [%s]", p1); StringTrim(&p1); Debug("1. after trim [%s]", p1); char str2[] = " test2"; char * p2 = str2; Debug("2. before trim: [%s]", p2); StringTrim(&p2); Debug("2. after trim [%s]", p2); char str3[] = "test3 "; char * p3 = str3; Debug("3. before trim: [%s]", p3); StringTrim(&p3); Debug("3. after trim [%s]", p3); char str4[] = " "; char * p4 = str4; Debug("4. before trim: [%s]", p4); StringTrim(&p4); Debug("4. after trim [%s]", p4); char str5[] = ""; char * p5 = str5; Debug("5. before trim: [%s]", p5); StringTrim(&p5); Debug("5. after trim [%s]", p5);
Eredmény :
1. before trim: [ test1 ] 1. after trim [test1] 2. before trim: [ test2] 2. after trim [test2] 3. before trim: [test3 ] 3. after trim [test3] 4. before trim: [ ] 4. after trim [] 5. before trim: [] 5. after trim []