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?
Odpowiedz
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 pisaniadouble
. - 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*
.
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.
Oprócz tego, wskaźnik matematyki zależy od rodzaju pointee. – DCoder
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). –
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.
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ą.
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.
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 rodzajup
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).
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
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
Aby lepiej zrozumieć, przeczytaj the tutorial
- 1. Różne typy list
- 2. Różne typy typów CATransakcji dostępne w iPhone sdk
- 3. Prawidłowe sposobem odlewania typy wskaźnika
- 4. Dlaczego są różne typy ciągów i wektorów?
- 5. Metoda rozszerzenia dla dokładnie dwóch różnych typów
- 6. Utwórz funkcję C, która akceptuje parametry różnych typów danych
- 7. Django - Rozróżniaj różne typy IntegrityError
- 8. Java 8 Completable Futures allOf różnych typów danych
- 9. Różne ustawienia dla różnych urządzeń?
- 10. Terminologia dla różnych typów funkcji
- 11. Błąd C2371: redefinicja; różne podstawowe typy - dlaczego?
- 12. Czy jest możliwe stosowanie różnych typów zwracania dla przeciążonej metody?
- 13. xsd sam element, różne typy?
- 14. Jaki jest poprawny sposób inicjowania wskaźnika wc?
- 15. Do czego służą różne typy próbników HLSL?
- 16. Dlaczego standard C++ wymaga std :: partition w celu spełnienia różnych złożoności dla różnych typów iteratorów?
- 17. Null dla pierwotnych typów danych
- 18. Dlaczego AST w innym aspekcie używa różnych typów dla tego i innego?
- 19. Dlaczego potrzebujemy "algebraicznych typów danych"?
- 20. Django - Profile użytkowników różnych typów
- 21. Czytanie współrzędnych shapefile wC#
- 22. Porównanie różnych typów w szablonie
- 23. Lista list różnych typów
- 24. Biblioteka typów typów danych dla C
- 25. ASP.NET MVC - Publikowanie formularza z niestandardowymi polami różnych typów danych
- 26. Różne limity czasu sesji dla różnych użytkowników
- 27. XCode Różne zasoby dla różnych celów
- 28. Różne konstrukcje Androida dla różnych środowisk
- 29. Różne tła dla różnych stanów UI-router
- 30. Dlaczego ma się osobny moduł dla typów?
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
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) –
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). –