2015-06-12 18 views
5

W tym programie (C, nie C++), dlaczego malloc zawsze zwraca prawidłowy rozmiar, niezależnie od użycia operatora sizeof?Czy wymagany jest operator sizeof dla malloc?

#include <stdio.h> 
#include <stdlib.h> 

int main(void) { 
    char *c = malloc(3); 
    short *s = malloc(3); /* or malloc(3 * sizeof(short))? */ 
    int *i = malloc(3); /* or malloc(3 * sizeof(int))? */ 
    long *l = malloc(3); /* or malloc(3 * sizeof(long))? */ 

    printf("%p\n", c++); 
    printf("%p\n", c++); 
    printf("%p\n", c++); 

    printf("---\n"); 

    printf("%p\n", s++); 
    printf("%p\n", s++); 
    printf("%p\n", s++); 

    printf("---\n"); 

    printf("%p\n", i++); 
    printf("%p\n", i++); 
    printf("%p\n", i++); 

    printf("---\n"); 

    printf("%p\n", l++); 
    printf("%p\n", l++); 
    printf("%p\n", l++); 

    return 0; 
} 

Wyjście jest:

0x1e82010 (1 byte) 
0x1e82011 
0x1e82012 
--- 
0x1e82030 (2 bytes) 
0x1e82032 
0x1e82034 
--- 
0x1e82050 (4 bytes) 
0x1e82054 
0x1e82058 
--- 
0x1e82070 (8 bytes) 
0x1e82078 
0x1e82080 

Am I czegoś brakuje?

4.0.4-303.fc22.x86_64 dzyń wersja 3.5.0 (tags/RELEASE_350/końcowy) docelowa: x86_64-RedHat-linux-gnu modelu Temat: POSIX

+0

Robisz arytmetyczne adresy; nie masz dostępu do pamięci, która jest równie dobra, ponieważ przydzielono tylko 3 bajty, więc dla wszystkich z wyjątkiem części 'char *' uzyskujesz dostęp do pamięci poza granicami. –

+1

To, co robisz, to niezdefiniowane zachowanie. Fakt, że "wydaje się" działać, nie czyni go legalnym (lub ważnym). Możesz ustawić te wskaźniki na 'NULL' i uzyskać takie same wyniki. – Cornstalks

+1

W jaki sposób ustaliłeś, ile przydzielono pamięci malloc? –

Odpowiedz

2

Liczba bajtów zwiększany kiedy inkrementujesz wskaźnik, zależy tylko od jego typu - np jeśli zwiększysz wartość o int*, zwiększysz adres o 4 bajty. Nie ma to nic wspólnego z malloc lubani z czymkolwiek.

Przekonasz się, że jeśli zaczniesz przechowywania wartości tych wskaźników, będziesz napotkasz dziwne zachowanie, ponieważ nie zostały przydzielone wystarczająco dużo miejsca do przechowywania 3 short S lub 3 int S lub 3 long s.

4

Zwiększanie wskaźnika zwiększa zapisany adres o wielkość typu podstawowego. Nie zależy od tego, na co wskazuje wskaźnik.

10
long *l = malloc(3); 

ten przydziela (lub raczej próbuje przydzielić) 3 bajtów.

Zazwyczaj malloc() przydzieli więcej niż żąda, w celu dostosowania i prowadzenia rachunkowości. Więc po wywołaniu malloc(3), możesz być w stanie uciec z przechowywaniem 3 long wartości w przydzielonej pamięci. Ale nie jest to gwarantowane.

Tak, potrzebujesz sizeof.

A najlepszym sposobem, aby napisać, że jest:

long *l = malloc(3 * sizeof *l); 

Korzystając rozmiar co strzałka wskazywała (sizeof *l), nie trzeba określić typ long dwukrotnie, a kod wygrał 't break, jeśli typ zmienia się później.

Nawet lepiej:

long *l = malloc(3 * sizeof *l); 
if (l == NULL) { 
    /* malloc failed, recover or bail out */ 
} 

Jeśli wolisz, możesz napisać to jako:

long *l = malloc(3 * sizeof(*l)); 

ale dodatkowe nawiasy nie są konieczne, rozmiar sizeof to jednoskładnikowa, operator, a nie funkcja .

printf("%p\n", l++); 
printf("%p\n", l++); 
printf("%p\n", l++); 

Zwiększanie wskaźnika przesuwa go o wielkość typu, na który wskazuje. long jest najwyraźniej 8 bajtów w twoim systemie, więc zwiększy to o l co najmniej 24 bajty, znacznie poza 3 bajty, o które prosiłeś od malloc. Rezultatem jest niezdefiniowane zachowanie.

I zwiększając liczbę l, straciłeś oryginalną wartość zwróconą przez malloc; będziesz potrzebować, gdy nadejdzie czas, aby zadzwonić pod numer free().

Wreszcie specyfikator formatu %p wymaga argumentu typu void*. Przechodząc inny typ wskaźnika jest prawdopodobne, aby „praca”, ale naprawdę powinien miotać void*:

printf("%p\n", (void*)l++); 
+0

Idealny. Dzięki za dodatkowe wskazówki. – lmlf

+0

Kudos dla 'long * l = malloc (3 * sizeof * l);' zamiast 'long * l = malloc (3 * sizeof (long));' – chux

2

pan padł ofiarą błędem. Nie analizujesz tego, co powrócił malloc, widzisz, że przyrost ten wie, jak poprawnie zwiększyć wskaźnik w zależności od rozmiaru typu zmiennej. Nic o wywołaniu malloc nie mówi, ile faktycznie przydzielono RAM.

5

Czy brakuje mi czegoś?

Tak, całkowicie nie rozumiesz.

Testujesz arytmetykę wskaźnika, która jest zdefiniowana pod względem rozmiaru wskazanego typu. Nie ma to absolutnie nic wspólnego z ilością pamięci przydzielonej przez malloc(), ani nawet z tym, czy wskazany wskaźnik wskazuje w ogóle prawidłowy adres.

Powiązane problemy