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.


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.


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);

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.


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));

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++;
    }
}

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


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


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.


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


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.



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


Nie używaj „memset”
zamiast

1

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



-3
void clearArray (char *input[]){
    *input = ' '; 
}

1
To nie jest CZYSZCZENIE, to po prostu ustawienie pierwszego znaku na „”! Myślę, że chciałeś napisać * input = '\ 0'
stviper

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.