2012-09-21 14 views
9

Jeśli musimy posiadać adres dowolnego typu danych, wymagamy wskaźnika tego typu danych. Ale wskaźnik jest po prostu adresem, a adres jest zawsze typem int, dlaczego adres trzymania dowolnego typu danych wymaga wskaźnika tego typu?Dlaczego różne typy wskaźnika dla różnych typów danych wc?

+0

Istnieje więcej informacji w wskaźniku (z widoku C) niż jego adres. Jest też ten typ. Jeśli wskaźnik nie miałby jakiegoś typu, co by to oznaczało wyrecytowanie? – nos

+0

Zobacz także: [Dlaczego wskaźniki funkcyjne i wskaźniki danych są niekompatybilne w C/C++] (http: // stackoverflow.com/questions/12358843/why-are-function-pointers-and-data-pointers-incompcending-in-cc) –

+0

Jeśli napiszesz w BCPL i B (poprzedniki C) lub w zespole, będziesz miał to, pointers = integer liczby. Wskaźniki C są ładowane: są zaprojektowane tak, aby wskazywały na rzeczy o różnych rozmiarach, ewentualnie umieszczone w różnych pamięciach. Dereferencji takich wskaźników nie można zaimplementować, jeśli wskaźniki są po prostu zwykłymi liczbami całkowitymi i niczym więcej (pod maską są jeszcze liczbami całkowitymi, ale to tylko wtedy, gdy wszystkie informacje o typie i wielkości zostały zajęte przez kompilator). –

Odpowiedz

12

Istnieje kilka powodów:

  • Nie wszystkie adresy są sobie równe; W szczególności, w non Von Neuman (np. Harvard) wskaźniki architektury do pamięci kodu (gdzie często przechowywane są stałe) i wskaźniki do pamięci danych są różne.
  • Musisz znać typ bazowy, aby poprawnie wykonać dostęp. Na przykład czytanie lub pisanie char różni się od czytania lub pisania double.
  • Potrzebne są dodatkowe informacje do wykonania arytmetyki wskaźników.

Należy zauważyć, że istnieje typ wskaźnika oznaczający "po prostu wskaźnik" w języku C o nazwie void*. Możesz użyć tego wskaźnika do przeniesienia adresu do pamięci, ale musisz go rzucić w coś użytecznego, aby wykonać operacje w pamięci wskazanej przez void*.

2

Ponieważ założenie, że "adres jest zawsze typu int" jest błędne.

Jest całkowicie możliwe stworzenie architektury komputerowej, w której na przykład wskaźniki do postaci są większe niż wskaźniki do słów, z jakiegoś powodu. C sobie z tym poradzi.

Oczywiście, wskaźniki mogą być z dereferencji, a kiedy to zrobisz, kompilator musi znać typ danych, które spodziewasz się znaleźć pod tym adresem. W przeciwnym razie nie może wygenerować odpowiednich instrukcji dotyczących tych danych.

Rozważmy:

char *x = malloc(sizeof *x); 
*x = 0; 

double *y = malloc(sizeof *y); 
*y = 0; 

Te dwa fragmenty będą pisać zupełnie różne ilości pamięci (albo wysadzić jeśli przydziały nie, nieważne, że do tej pory), ale rzeczywista stała dosłowna (0 który jest typu int) jest taki sam w obu przypadkach. Informacje o typach wskaźników pozwalają kompilatorowi wygenerować odpowiedni kod.

+0

Oprócz tego, wskaźnik matematyki zależy od rodzaju pointee. – DCoder

+2

Cóż, "jest całkowicie możliwe, aby stworzyć architekturę komputerową, gdzie ..." jest niebezpieczną krainą do odkrycia. W rzeczywistości możliwe jest również utworzenie takiego programu, w którym program napisany w języku C nie będzie działał, chyba że użyjesz jakiegoś bardzo powolnego symulatora (po prostu nie obsługując architektury pamięci podyktowanej przez C). –

2

Możesz bezdrzewny wskaźnik w C bardzo łatwo - wystarczy użyć void * dla wszystkich wskaźników. Byłoby to raczej głupie, z dwóch powodów, które mogę wymyślić.

Po pierwsze, określając dane wskazane w typie, kompilator oszczędza wielu głupich błędów, literówek lub innych. Jeśli zamiast tego pozbędziesz się kompilatora tych informacji, spędzisz dużo czasu na debugowaniu rzeczy, które nigdy nie powinny być problemem.

Ponadto prawdopodobnie użyłeś "arytmetyki wskaźnika". Na przykład: int *pInt = &someInt; pInt++; - która przesuwa wskaźnik do następnej liczby całkowitej w pamięci; działa to niezależnie od typu i zaliczki na właściwy adres, ale może działać tylko wtedy, gdy kompilator zna rozmiar wskazanego obiektu.

0

Przeważnie dla tych, którzy czytają kod po tobie, aby mogli wiedzieć, co jest przechowywane pod tym adresem.Ponadto, jeśli wykonasz arytmetykę wskaźnikową w kodzie, kompilator musi wiedzieć, ile ma przesunąć do przodu, jeśli zrobisz coś w stylu pSomething ++, które jest podane przez typ wskaźnika, ponieważ rozmiar twojego typu danych jest równy znane przed kompilacją.

0

Ponieważ Typ wskaźnika informuje kompilator, że na raz na ile bajtów można wykonać operację.

Przykład: - w przypadku char tylko 1 bajt
Może się różnić w przypadku 2 bajtu.

3

Wskaźniki to nie tylko int. W domyśle mają semantykę.

Oto kilka przykładów:

  • p->member ma sens tylko, jeśli wiesz, jakiego rodzaju p punkty.

  • p = p+1; zachowuje się inaczej w zależności od wielkości obiektu, na który wskażesz (w tym sensie, że "p" jest zwiększane, gdy jest postrzegane jako liczba całkowita bez znaku, w zależności od rozmiaru typu, na który wskazuje).

2

Poniższy przykład może pomóc zrozumieć różnice między wskaźnikami różnych typów:

#include <stdio.h> 

int main() 
{ 
    // pointer to char 
    char * cp = "Abcdefghijk"; 
    // pinter to int 
    int * ip = (int *)cp; // to the same address 

    // try address arithmetic 
    printf("Test of char*:\n"); 
    printf("address %p contains data %c\n", cp, *cp); 
    printf("address %p contains data %c\n", (cp+1), *(cp+1)); 
    printf("Test of int*:\n"); 
    printf("address %p contains data %c\n", ip, *ip); 
    printf("address %p contains data %c\n", (ip + 1), *(ip + 1)); 

    return 0; 
} 

wyjście

enter image description here

ważne jest, aby zrozumieć, że address+1 ekspresja daje inny wynik w zależności od typu address, tj. +1 oznacza sizeof(addressed data), np. sizeof(*address).

Tak więc, jeśli w systemie (dla kompilatora) sizeof(int) i sizeof(char) są różne (na przykład 4 i 1), wyniki cp+1 i ip+1 jest również inna. W moim systemie jest to:

E05859(hex) - E05858(hex) = 14702684(dec) - 14702681(dec) = 1 byte for char 
E0585C(hex) - E05858(hex) = 14702684(dec) - 14702680(dec) = 4 bytes for int 

Uwaga: konkretne wartości adresowe nie są w tym przypadku ważne, ważna jest tylko różnica.

Aktualizacja:

przez adres sposób (wskaźnik) arytmetyka nie jest ograniczona przez +1 lub ++, więc wiele przykładów mogą być wykonane, jak:

int arr[] = { 1, 2, 3, 4, 5, 6 }; 
int *p1 = &arr[1]; 
int *p4 = &arr[4]; 
printf("Distance between %d and %d is %d\n", *p1, *p4, p4 - p1); 
printf("But addresses are %p and %p have absolute difference in %d\n", p1, p4, int(p4) - int(p1)); 

z wyjściem

enter image description here

Aby lepiej zrozumieć, przeczytaj the tutorial

Powiązane problemy