2011-08-26 13 views
41

Czy nie jest możliwe użycie zestawu memlit w tablicy liczb całkowitych? Próbowałem następującego wywołania zestawu pamięci i nie otrzymałem prawidłowych wartości całkowitych w tablicy int.Dlaczego "memset (arr, -1, sizeof (arr)/sizeof (int))" nie wyczyści tablicy liczb całkowitych do -1?

int arr[5]; 
memset (arr, -1, sizeof(arr)/sizeof(int)); 

Vaules mam to:

arr[0] = -1 
arr[1] = 255 
arr[2] = 0 
arr[3] = 0 
arr[4] = 0 
+1

może być łatwiejsze do zrobienia: int arr [5] = {-1}; –

+24

@ Tom Dignan: Z wyjątkiem tego, że tylko inicjalizuje pierwszy element do -1, a reszta do 0. – tinman

Odpowiedz

69

Wystarczy zmienić memset (arr, -1, sizeof(arr));

Zauważ, że dla innych wartości niż 0 i -1 to nie będzie działać od czasu memset Ustawia wartości bajtów dla bloku pamięci, który rozpoczyna się w zmiennej wskazanej przez *ptr dla następujących num bajtów.

void * memset (void * ptr, int value, size_t num); 

A ponieważ int jest reprezentowany na więcej niż jeden bajt, nie dostaniesz żądaną wartość dla liczb całkowitych w swojej tablicy.

Wyjątki:

  • 0 jest wyjątkiem, ponieważ jeśli ustawienie wszystkich bajtów 0, wartość będzie zero
  • -1 to kolejny wyjątek, ponieważ, jak podkreślił Patrick -1 jest 0xFF (= 255) w int8_t i 0xffffffff w int32_t

powodem masz:

arr[0] = -1 
arr[1] = 255 
arr[2] = 0 
arr[3] = 0 
arr[4] = 0 

Ponieważ w twoim przypadku długość int wynosi 4 bajty (reprezentacja 32-bitowa), długość tablicy w bajtach wynosi 20 (= 5 * 4), a tylko 5 bajtów to -1 (= 255) zamiast 20.

+5

Cóż, w tym konkretnym przypadku (dla -1 jako wartości), zbiór faktycznie działa. Ponieważ -1 jest 0xff w int8_t i 0xffffffff w int32_t i tak dalej. IOW: memset działa poprawnie dla 0 i -1, ale nie jest bardzo użyteczny dla wszystkich pozostałych przypadków. –

+0

Masz rację Patrick, dziękuję .. Zmieniłem odpowiednio odpowiedź –

+6

@Patrick B.: to będzie działać dobrze na wielu platformach, ale nie wszystkie. Nie wszystkie platformy używają dopełnienia dwójki, a ty możesz także wyzwalać reprezentacje pułapek za pomocą 'memset', aby zainicjować' int'. –

5

Dlaczego podział?

memset(arr, -1, sizeof(arr)); 

Twoja wersja, sizeof(arr)/sizeof(int), podaje liczbę elementów w tablicy.

+3

Zauważ, że 'memset()' ustawia wartość _bytes_ w zaadresowanej lokalizacji, nie ile "elementów". Chciałbyś ustawić 5 intów wartości bajtów na '-1'. Może to spowodować ustawienie wartości int na "-1" jako zbieżność formatu. –

+1

@Jeff: Rzeczywiście, zbieg okoliczności, ponieważ int -1 wynosi zwykle $ FFFFFFFF (przy założeniu 32-bitowej int i dwójki dopełnienia), a bajt -1 wynosi $ FF. Gdyby wybrał -2 ($ FE), stałoby się $ FEFEFEFE, który jest int -16843010. –

30

Nie używaj memset, aby zainicjować coś innego niż jednobajtowe typy danych.

Na pierwszy rzut oka mogłoby się wydawać, że to powinno działać dla Inicjowanie int do 0 lub -1 (i na wielu systemach będzie działać), ale wtedy nie bierzesz pod uwagę możliwość, że może wygenerować pułapkę reprezentacja, powodując niezdefiniowane zachowanie lub fakt, że reprezentacja całkowita to not necessarily two's complement.

Prawidłowy sposób zainicjowania tablicy int na -1 polega na przepętleniu się przez tablicę i ustawieniu każdej wartości jawnie.

+8

Myślę, że ta odpowiedź powinna być rozważana przez klauzulę taką jak "Nie używaj' memset() '... ** jeśli chcesz napisać absolutnie przenośny kod **". Większość ludzi nie pisze ani nie zamierza pisać przenośnego kodu. Większość ludzi nazywa kod "przenośnym", gdy działa na dwóch architekturach. Słowo "poprawny" w "Właściwy sposób ..." można również zmienić na "przenośny". Jeśli nie próbujesz pisać absolutnie przenośnego kodu, nie jest to ani bardziej, ani mniej poprawne. –

+0

+1 @Complicatedseebio nie mógł się zgodzić, zbyt wielu programistów przeskakuje gardła ludzi z takimi rzeczami jak "poprawny" i "stl to". Zbyt często szukają tego, co jest potrzebne w danym problemie. –

+7

@Komplikowany patrz bio @Adam: Rzecz w tym, że inicjowanie tablicy 'int' za pomocą pętli jest gwarantowane we wszystkich przypadkach, podczas gdy użycie' memset' może nie zrobić tego poprawnie (lub gorzej może się_poprosić_ do pracy). Nie powiem, że nie możesz użyć 'memset', jeśli masz intymną wiedzę na temat platform, na których będzie działał kod i wiesz, że nie spowoduje to problemu. Ale nie mam takiej wiedzy o platformach dla wszystkich, którzy mogą przeczytać tę odpowiedź, więc wolę grać bezpiecznie. Mam nadzieję, że równoważy niektóre "skrajności" (z powodu argumentów), których użyłem w mojej odpowiedzi. –

4

można zaoszczędzić sobie trochę pisania przez inicjowanie tablicy bezpośrednio:

int arr[5] = {-1, -1, -1, -1, -1}; 

Ta linia jest krótsza niż memset, a także działa.

+0

+1 dla inicjatora macierzy, choć jest przydatny tylko dla kilku wartości. –

9

gcc zapewnia dobry skrót inicjalizacji tablicy

int arr[32] = {[0 ... 10] = 3, [11 ... 31] = 4}

uwadze przestrzeń przed i po ...

1
void * memset (void * ptr, int value, size_t num); 

Funkcja ta działa dobrze na większości systemów, gdy stosowane ustawić char tablicę. Ustawia pierwszą liczbę BYTES bloku pamięci wskazywanego przez ptr na określoną wartość (interpretowaną jako unsigned char). memset-C++ Reference Za każdym razem działa jeden bajt. To działa dobrze, jeśli przypiszesz drugie argumenty o wartości int nie większej niż 0xff.

Jeśli chodzi o twoją wersję, trzecim argumentem jest liczba elementów tablicy, więc masz swoje wyniki. Właściwie to prawda, że ​​masz przypisać trzeci argument LICZBĄ BYTÓW, które chcesz. Tak więc poprawna wersja powinna wyglądać następująco:

memset (arr, -1, sizeof(arr)); 
Powiązane problemy