czyszczenie tablicy znaków c

104

Pomyślałem, że ustawienie pierwszego elementu na wartość null wyczyści całą zawartość tablicy char.

char my_custom_data[40] = "Hello!";
my_custom_data[0] = '\0';

Jednak to ustawia tylko pierwszy element na null.

lub

my_custom_data[0] = 0; 

Zamiast używać memset, pomyślałem, że powyższe 2 przykłady powinny wyczyścić wszystkie dane.

ant2009
źródło
1
Jared, dlaczego ustawiłeś tag c ++? mówił o "C" i nie dodał żadnych znaczników związanych z C ++.
Johannes Schaub - litb
1
Dotyczy to równie dobrze tablic znaków w C ++, mimo że nie określił tego.
Adam Hawes
4
Usunąłem tag C ++, aby uniknąć tego, co już widzieliśmy w przypadku osób oferujących rozwiązania specyficzne dla C ++
Alnitak

Odpowiedzi:

113

To zależy od tego, jak chcesz wyświetlić tablicę. Jeśli patrzysz na tablicę jako serię znaków, jedynym sposobem na wyczyszczenie danych jest dotknięcie każdego wpisu. memsetjest prawdopodobnie najskuteczniejszym sposobem osiągnięcia tego celu.

Z drugiej strony, jeśli zdecydujesz się wyświetlić ten ciąg znaków C / C ++ zakończony znakiem null, ustawienie pierwszego bajtu na 0 skutecznie wyczyści ciąg.

JaredPar
źródło
4
Kluczowym słowem w odpowiedzi jest „skutecznie”. Tylko pierwszy element ma wartość początkową równą 0, a reszta nadal ma niezdefiniowane wartości, ale jeśli traktujesz tablicę jako ciąg zakończony wartością null, a pierwszy element ma wartość null, wówczas ciąg jest uważany za pusty.
Arnold Spence
rzeczywiście, to jest odpowiedź ludzie.
Johannes Schaub - litb
@caparcode, dokładnie. Dlatego bardzo ważne jest, aby zrozumieć, w jaki sposób używana jest tablica.
JaredPar
Tak, to właśnie powinienem był powiedzieć w moim pierwszym poście. Znak jest zakończonym łańcuchem. więc albo te zrobią tę sztuczkę. char [0] = '\ 0'; lub char [0] = 0. Nie jestem pewien, ale słyszałem, że użycie „\ 0” jest lepsze przy używaniu ciągów zakończonych znakiem null.
ant2009
@robUK, tak, masz rację. Technicznie „\ 0” jest równe 0 (w ascii), ale powinieneś użyć „\ 0”, ponieważ jasno określa twój zamiar
Mark Testa
70

Tablica w C jest po prostu miejscem w pamięci, więc rzeczywiście, twoje my_custom_data[0] = '\0';przypisanie po prostu ustawia pierwszy element na zero i pozostawia pozostałe elementy nienaruszone.

Jeśli chcesz wyczyścić wszystkie elementy tablicy, musisz odwiedzić każdy element. Do tego memsetsłuży:

memset(&arr[0], 0, sizeof(arr));

Jest to na ogół najszybszy sposób rozwiązania tego problemu. Jeśli możesz użyć C ++, rozważ zamiast tego std :: fill:

char *begin = &arr;
char *end = begin + sizeof(arr);
std::fill(begin, end, 0);
John Feminella
źródło
1
Uważam, że druga wersja powinna wyglądać następująco: std :: fill (arr, arr + sizeof (arr) / sizeof (arr [0]), 0);
David Rodríguez - dribeas
Wyjaśnienie: nie używaj sizeof z fill, ponieważ później będziesz mieć problemy z tablicami int, long, double lub co masz.
Zan Lynx,
Wolę: std :: fill (& arr [0], & arr [arr_len], 0);
Zan Lynx,
Zan Lynx, to niezdefiniowane zachowanie. nie możesz zrobić & arr [arr_len]. ale musisz zrobić std :: fill (arr, arr + sizeof arr, 0); lub jeśli masz gdzieś długość std :: fill (arr, arr + arr_len, 0); zakładając tablicę znaków
Johannes Schaub - litb
Jest ważny tylko w C. chociaż pytanie wyraźnie dotyczyło C (inny facet dodał tag C ++, nie mam pojęcia dlaczego), std :: fill pokazuje powinowactwo do C ++ :)
Johannes Schaub - litb
25

Dlaczego myślisz, że ustawienie pojedynczego elementu wyczyści całą tablicę? Zwłaszcza w języku C niewiele dzieje się bez bezpośredniego zaprogramowania przez programistę. Jeśli ustawisz pierwszy element na zero (lub dowolną wartość), to zrobiłeś dokładnie to i nic więcej.

Podczas inicjalizacji możesz ustawić tablicę na zero:

char mcd[40] = {0}; /* sets the whole array */

Poza tym nie znam żadnej innej techniki niż memset lub coś podobnego.

abelenky
źródło
Myślę, że to zależy od używanego kompilatora
cocoafan
1
@cocoafan: Nie, to nie jest zależne od kompilatora. Jest częścią specyfikacji języka. Każdy kompilator, który zachowuje się inaczej, nie jest zgodny z językiem C.
abelenky
Nie wiedziałem, dziękuję. Nie mogłem znaleźć żadnego źródła, w którym mógłbym przeczytać ten specjalny przypadek. Byłoby miło mieć to jako zakładkę.
cocoafan
1
Nazywa się to częściową inicjalizacją. Nie mam specyfikacji C99, ale tutaj są dwa źródła: bit.ly/enBC2m "Nie ma potrzeby inicjowania wszystkich elementów tablicy. Jeśli tablica jest częściowo zainicjowana, elementy, które nie zostały zainicjalizowane, otrzymują wartość 0 z odpowiedni typ. ” bit.ly/f9asHH "Jeśli jest mniej inicjatorów niż elementów w tablicy, pozostałe elementy są automatycznie inicjalizowane na 0"
abelenky
Nie dotyczy to tablicy, która została już zadeklarowana i przypisane wartości, prawda?
skinnedKnuckles
10

Posługiwać się:

memset(my_custom_data, 0, sizeof(my_custom_data));

Lub:

memset(my_custom_data, 0, strlen(my_custom_data));
Jake1164
źródło
1
Druga opcja ( memset(my_custom_data, 0, strlen(my_custom_data));) wyczyści tylko do pierwszego „\ 0”, który może znajdować się poza końcem tablicy. To może, ale nie musi, być w porządku.
brewmanz
9

Wypróbuj następujący kod:

void clean(char *var) {
    int i = 0;
    while(var[i] != '\0') {
        var[i] = '\0';
        i++;
    }
}
Cristian Altamirano
źródło
2
FYI - wsuń kod 4 spacjami lub zaznacz go i naciśnij przycisk „kod”, który wygląda jak dwie linie binarne.
meagar
Doskonałe rozwiązanie, jeśli nie chcesz dołączać string.h dla memset ().
Akash Agarwal
7

Dlaczego nie użyć memset() ? Tak to się robi.

Ustawienie pierwszego elementu pozostawia resztę pamięci nietkniętą, ale funkcje str będą traktować dane jako puste.

John Fricker
źródło
1
Nie używaj memset zamiast czytelności: stackoverflow.com/questions/453432/ ...
Johann Gerell
1
i jaka jest twoja odpowiedź?
mkb
6

Pls znaleźć poniżej, gdzie wyjaśniłem dane w tablicy po przypadku 1 i przypadku 2.

char sc_ArrData[ 100 ];
strcpy(sc_ArrData,"Hai" );

Przypadek 1:

sc_ArrData[0] = '\0';

Wynik:

-   "sc_ArrData"
[0] 0 ''
[1] 97 'a'
[2] 105 'i'
[3] 0 ''

Przypadek 2:

memset(&sc_ArrData[0], 0, sizeof(sc_ArrData));

Wynik:

-   "sc_ArrData"
[0] 0 ''
[1] 0 ''
[2] 0 ''
[3] 0 ''

Chociaż ustawienie pierwszego argumentu na NULL załatwi sprawę, zalecane jest użycie memset

Akaanthan Ccoder
źródło
4

Nie. Jedyne, co robisz, to ustawienie pierwszej wartości na „\ 0” lub 0.

Jeśli pracujesz z ciągami zakończonymi znakiem null, w pierwszym przykładzie otrzymasz zachowanie, które naśladuje to, czego oczekujesz, jednak pamięć jest nadal ustawiona.

Jeśli chcesz wyczyścić pamięć bez używania memset, użyj pętli for.

Alan
źródło
Mówię nie na pętli for. Staraj się nie pisać własnych „ulepszonych” (i zazwyczaj nie) funkcji bibliotecznych. W rzeczywistości memset i memcpy są raczej wyjątkowe i często są wbudowane w niestandardowy kod maszynowy dla procesora na podstawie tego, co wiadomo o wyrównaniu danych i długości.
Zan Lynx,
@Zan OP nie chce używać memset (być może jest osadzony i nie ma go dostępnego). Ale tak, memset jest zwykle wysoce optymalny i prawdopodobnie szybszy niż pętla for.
Adam Hawes
To prawda, jednak nie chciał używać memset, więc zasugerowałem pętlę for.
Alan
3

Powinieneś użyć memset. Ustawienie tylko pierwszego elementu nie zadziała, musisz ustawić wszystkie elementy - jeśli nie, to jak ustawić tylko pierwszy element na 0?

Michael
źródło
memset nie powinien być używany zamiast czytelności: stackoverflow.com/questions/453432/ ...
Johann Gerell
2

Zapisanie pustego znaku do pierwszego znaku właśnie to robi. Jeśli potraktujesz go jako łańcuch, kod przestrzegający znaku zakończenia zerowego potraktuje go jako łańcuch pusty, ale to nie to samo, co wyczyszczenie danych. Jeśli chcesz faktycznie wyczyścić dane, musisz użyć memset.

tvanfosson
źródło
2

Zwykle po prostu robię to:

memset(bufferar, '\0', sizeof(bufferar));
Jevgenij Kononov
źródło
1

Pomyślałem, że ustawienie pierwszego elementu na wartość null wyczyści całą zawartość tablicy char.

To nie jest poprawne, jak odkryłeś

Jednak to ustawia tylko pierwszy element na null.

Dokładnie!

Musisz użyć memset, aby wyczyścić wszystkie dane, nie wystarczy ustawić jeden z wpisów na null.

Jeśli jednak ustawienie elementu tablicy na wartość null oznacza coś specjalnego (na przykład przy użyciu ciągu kończącego wartość null w), może wystarczyć ustawienie pierwszego elementu na wartość null. W ten sposób każdy użytkownik tablicy zrozumie, że jest ona pusta, mimo że tablica nadal zawiera stare znaki w pamięci

hhafez
źródło
Nie używaj „memset”
zamiast
1

ustaw pierwszy element na NULL. wypisanie tablicy char nic ci nie da.


źródło
1

A co z następującymi:

bzero(my_custom_data,40);
codeconnundrum
źródło
-3
void clearArray (char *input[]){
    *input = ' '; 
}
Wilk
źródło
1
To nie jest CZYSZCZENIE, to po prostu ustawienie pierwszego znaku na „”! Myślę, że chciałeś napisać * input = '\ 0'
stviper
-4

Spróbuj wykonać następujące czynności:

strcpy(my_custom_data,"");
Greg Grady
źródło