2012-07-22 9 views
11
#include<stdio.h> 
int main(void){ 
    int *ptr,a,b; 
    a = ptr; 
    b = ptr + 1; 
    printf("the vale of a,b is %x and %x respectively",a,b); 

    int c,d; 
    c = 0xff; 
    d = c + 1; 
    printf("the value of c d are %x and %x respectively",c,d); 
    return 0; 
} 

obecnie wprowadzone wartość jestDlaczego wskaźnik + 1 dodatku 4 faktycznie

the vale of a,b is 57550c90 and 57550c94 respectively 
the value of c d are ff and 100 respectively% 

okazuje się, że ptr + 1 rzeczywiście, dlaczego zachowują się w ten sposób?

+5

Bo tak działa arytmetyka wskaźnikowa w C. Tak właśnie jest zdefiniowana. Po dodaniu 1 do wskaźnika 'int *' przeskakuje do następnego obiektu 'int'. Najwyraźniej na twojej platformie 'int' składa się z 4 bajtów. Jest to podstawowa wiedza na temat wskaźników C - o czym czytasz w książce. – AnT

+1

Zobacz [moja poprzednia odpowiedź] (http://stackoverflow.com/a/8772201/119527) na takie pytanie. –

+0

Powinieneś używać '% p' w łańcuchach formatu' printf' dla wskaźników. Nie używaj do tego '% x', nie jest przenośny (ponieważ wskaźniki i' int'-s mogą mieć inną szerokość bitową). –

Odpowiedz

20

Zastanów się nad wskaźnikiem ... jest to adres pamięci. Każdy bajt w pamięci ma adres. Tak więc, jeśli masz int, który ma 4 bajty, a jego adres to 1000, to w rzeczywistości jest to drugi bajt tego int, a 1002 to trzeci bajt, a 1003 jest czwarty. Ponieważ rozmiar pliku int może być różny w różnych kompilatorach, konieczne jest, aby przy zwiększaniu wskaźnika nie uzyskać adresu pewnego środkowego punktu w int. Tak więc zadanie ustalania liczby bajtów do pominięcia, w oparciu o twój typ danych, jest obsługiwane dla ciebie i możesz po prostu użyć dowolnej wartości, którą otrzymasz i nie martwić się o to.

Jak wskazuje Basile Starynkvitch, kwota ta będzie się różnić w zależności od właściwości wskazanego elementu danych. Bardzo łatwo jest zapomnieć, że chociaż adresy są sekwencyjne, wskaźniki obiektów muszą uwzględniać faktyczną przestrzeń pamięci wymaganą do pomieszczenia tych obiektów.

24

Ponieważ wskaźniki mają być kompatybilne z tablicami:

*(pointer + offset) 

jest równoważna

pointer[offset] 

Więc wskaźnik aritmetic nie działa w bajtach, ale pod względem sizeof(pointer base type) -bytes wielkości bloków.

+0

dla maszyn 64-bitowych, może być tak duży jak 8 bajtów. – Aftnix

+0

@Aftnix tak, ale w czym problem? –

+0

@Aftnix i nie, rozważ wprowadzenie wskaźnika do struktury o wielkości 256 bajtów ... –

2

Wskaźnik służy do wskazywania określonego bajta oznaczenia pamięci, w którym obiekt został przydzielony (technicznie może wskazywać dowolne miejsce, ale w ten sposób jest używany). Kiedy wykonujesz arytmetykę wskaźnikową, działa ona w oparciu o rozmiar wskazanych obiektów. W twoim przypadku jest to wskaźnik do liczb całkowitych, które mają rozmiar 4 bajty każdy.

7

Powinieneś trochę czasu na lekturę dobry języka programowania C (jak K&R "the C programming language")

Pointer arytmetyka jest trudny temat. Dodawanie wskaźnika oznacza przejście do następnego, spiczastego elementu. Więc adres jest zwiększany o sizeof zaostrzony element.

+0

Dziś poproszę o tę książkę z biblioteki! – mko

1

Rozważmy wskaźnik p. Wyrażenie p+n jest podobne do (unsigned char *)p + n * sizeof *p (ponieważ sizeof(unsigned char) == 1). Spróbuj tego:

#include <stdio.h> 
#define N 3 

int 
main(void) 
{ 
    int i; 
    int *p = &i; 
    printf("%p\n", (void *)p); 
    printf("%p\n", (void *)(p + N)); 
    printf("%p\n", (void *)((unsigned char *)p + N * sizeof *p)); 
    return 0; 
} 
5

Krótka odpowiedź

Adres wskaźnikiem będzie zwiększany o sizeof(T) gdzie T jest typem wskazał. Tak więc dla int, wskaźnik zostanie zwiększony o sizeof(int).

Dlaczego?

Przede wszystkim wymaga tego standard.Przyczyną takiego zachowania (poza kompatybilnością z C) jest to, że gdy masz strukturę danych, która używa ciągłej pamięci, takiej jak tablica lub std::vector, możesz przejść do następnego elementu w tablicy, po prostu dodając jedną do wskaźnik. Jeśli chcesz przejść do n-tego elementu w kontenerze, wystarczy dodać n.

Będąc w stanie napisać firstAddress + 2 jest znacznie prostsze niż firstAddress + (sizeof(T) * 2), a także pomaga zapobiegać błędów wynikających z twórców zakładając sizeof(int) wynosi 4 (nie może być) i pisania kodu jak firstAddress + (4 * 2).

W rzeczywistości, kiedy mówisz myArray[4], mówisz myArray + 4. Z tego powodu indeksy tablic zaczynają się od 0; po prostu dodajesz 0, aby pierwszy element (tj. myArray wskazuje na pierwszy element tablicy) oraz n, aby uzyskać n-ty.

Co zrobić, jeśli chcę przenieść jeden bajt na raz?

sizeof(char) gwarantuje się jeden bajt wielkości, dzięki czemu można używać char* jeśli naprawdę chce się przenieść jeden bajt na raz.