Ответ 1
Введите безопасность. Определение типа указателей помогает компилятору найти ошибки, когда вы пытаетесь использовать данные неправильного типа с помощью указателя. То, что причина C имеет типы в первую очередь.
Я знаю, что у нас есть разные указатели, такие как int
, float
и char
. Указатель void
- единственный указатель, который может содержать все остальные.
Существуют ли другие указатели только для гибкости для арифметики указателей?
Есть ли другая причина, по которой указатели, отличные от void
, присутствуют на языке C?
Введите безопасность. Определение типа указателей помогает компилятору найти ошибки, когда вы пытаетесь использовать данные неправильного типа с помощью указателя. То, что причина C имеет типы в первую очередь.
Компилятор должен знать типы, указав, что в противном случае все виды кода не будут работать. Рассмотрим следующее:
*a = *b + *c; // Should this add char? int? float? s_ptr->x = 0; // How does the compiler know anything about the structure s_ptr points to? a[5] = 0; // How far is a[5] from a[0]?
Не имея типов для указателей, они бы не имели типов для чего-либо. Компилятор будет полностью потерян. Короче говоря, C и С++ строго типизированы, и это переносится на указатели по довольно очевидным причинам.
int o = 12;
void *i = &o;
Как вы получите доступ к int, который указывает i
, если были только указатели void и нет int *. Возможно, вы знаете, что на вашей платформе int составляет 4 байта, поэтому вы можете memcpy 4 байта от начала того, что void * указывает на временный int, а затем использовать это. Но это не очень удобно.
Или задан
struct Pair {
char *first;
char *second;
};
Насколько полезен указатель void на struct Pair? Вероятно, вы захотите получить доступ к своему члену first
и много работать, если у вас не было указателя на структурную пару.
Мертвый просто:
void* p;
*p; // compile error!
Или выразить словами; указатель void не может быть разыменован.
Возможно, вам следует переименовать вопрос, почему у нас есть указатели, или, скорее, нет, и просто искать этот вопрос на SO.
Когда вы используете указатель на float или int (например), компилятор знает, сколько байтов оно должно взять из памяти (sizeof (int) для int * например).
С void Вам нужно было бы каждый раз рассказать о том, сколько байтов оно должно принять (например, путем записи (int *) some_void_ptr.
Но это большое упрощение.
Собственно, это объясняется "указатель на пустоту".
В языках программирования вообще и в C, в частности, нам нравятся типы. Типы - это базовая система безопасности, которая проверяет, делаем ли мы что-то глупое, где "глупо" означает "интерпретировать кучу бит для чего-то, чего нет". Можно программировать без типов, некоторые языки полностью лишены какого-либо типа (например, сборка или Forth), но это не для слабонервных, и, вообще говоря, производительность программиста значительно улучшается за счет использования типов.
Поэтому, когда у нас есть указатель, мы хотим, чтобы компьютер знал, что он может найти в конце указателя. Нам нужен "указатель на int", чтобы компьютер проверял, что, когда мы смотрим на биты, которые находятся в конце указателя, мы рассматриваем их как "int", а не как что-то еще.
"Указатель на void" - это указатель без указания типа, который мы используем, когда система типов C не может захватить то, что мы делаем. Это признак того, что C не может выполнить сложность кода, который мы производим (или, может быть, программист недостаточно хорош, чтобы выразить то, что он делает в рамках ограничений системы типа C). Следовательно, в то время как "void *" удобно в некоторых ситуациях, следует рассматривать его как исключение и стремиться избегать его.
Тип указателя в C указывает компилятору, какой размер блока памяти следует читать, если вы попытаетесь разыменовать его. Другими словами, при разыменовании указателя int компилятор знает, что после адреса нужно прочитать 4 байта. Вот почему разыменование указателя void без его указания на типизированный указатель запрещается - в этом случае компилятор не знает, сколько байтов следует читать после адреса.
Два слова: безопасность типа
Там немного лакомый кусочек введите безопасность (или ее отсутствие) в C в Википедии, которая может пролить некоторый свет для вас.
Когда вы повторяете блок памяти, на который указывает указатель, необходимо знать размер типа данных, который содержит память. Скажем, у вас есть два указателя: charcharptr и intintptr, указывающие на память в байте X. charptr + 1 укажет на байт X + 1, а intptr + 1 укажет на байт X + 4.
Быстрый и грязный кусок плохо написанного кода, чтобы проиллюстрировать это:
#include <stdio.h>
int main()
{
char * cptr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
short * sptr = (short*)cptr;
int * iptr = (int*)cptr;
long long * lptr = (long long*)cptr;
printf ("CHAR: %d, +1: %d\n",cptr,cptr+1);
printf ("SHORT: %d, +1: %d\n",sptr,sptr+1);
printf ("INT: %d, +1: %d\n",iptr,iptr+1);
printf ("LONG LONG: %d, +1: %d\n",lptr,lptr+1);
}
Это должно:
Есть ли другая причина, по которой указатели, отличные от void, присутствуют на языке C?
Они - отличный способ свободно обрабатывать куски памяти.:)