Почему у нас есть указатели, кроме void - PullRequest
27 голосов
/ 04 февраля 2010

Я знаю, что у нас есть разные указатели, такие как int, float и char. void указатель является единственным указателем, который может содержать все остальные.

Существуют ли другие указатели только для гибкости выполнения арифметики с указателями?

Есть ли какая-либо другая причина, по которой в языке C присутствуют указатели, отличные от void?

Ответы [ 10 ]

20 голосов
/ 04 февраля 2010

Тип безопасности. Определение типа указателей помогает компилятору находить ошибки, когда вы пытаетесь использовать данные неверного типа через указатель. Это причина, по которой С имеет типы в первую очередь.

14 голосов
/ 04 февраля 2010

Компилятор должен знать типы, на которые он указывает, иначе все виды кода не будут работать.Рассмотрим следующее:

*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 и C ++ строго типизированы, и это переносится на указатели по довольно очевидным причинам.

8 голосов
/ 04 февраля 2010
int o = 12;
void *i = &o;

Как бы вы получили доступ к int, на который указывает i, если бы были только пустые указатели и нет int *. Возможно, вы знаете, что на вашей платформе значение int составляет 4 байта, так что вы можете записать 4 байта с начала всего, на что указывает void *, во временное int, а затем использовать его. Но это не очень удобно.

или дано

struct Pair {
   char *first;
   char *second;
};

насколько полезным будет пустой указатель на структуру Pair? Вы, вероятно, захотите получить доступ к его члену first, и это будет много работы, если у вас не будет указателя на структуру Pair.

4 голосов
/ 04 февраля 2010

Смертельно просто:

void* p;
*p; // compile error!

Или выразить это словами;указатель void не может быть разыменован.

Возможно, вам следует переименовать вопрос, почему у нас есть указатели, а точнее - нет, и просто искать этот вопрос в SO.

3 голосов
/ 04 февраля 2010

Когда вы используете указатель для float или int (например), компилятор знает, сколько байтов он должен извлечь из памяти (sizeof (int) для int *, например).

С void Вы должны будете каждый раз указывать компилятору, сколько байт ему потребуется (например, записывая (int *) some_void_ptr.

Но это большое упрощение.

2 голосов
/ 04 февраля 2010

Тип указателя в C сообщает компилятору, каков размер блока памяти, который нужно прочитать в случае, если вы попытаетесь разыменовать его. Другими словами, при разыменовании указателя типа int компилятор знает, что после адреса необходимо прочитать 4 байта. Вот почему разыменование пустого указателя без приведения его к типизированному указателю запрещено - в этом случае компилятор не знает, сколько байтов нужно прочитать после адреса.

2 голосов
/ 04 февраля 2010

На самом деле, это «указатель на пустоту», который необходимо объяснить.

В языках программирования в целом и в C, в частности, нам нравятся типы. Типы - это базовая сеть безопасности, которая проверяет, делаем ли мы что-то глупое, где «глупый» означает «интерпретировать кучу битов за то, чем они не являются». Можно программировать без типов, некоторые языки полностью лишены любого типа (например, ассемблер или Forth), но это не для слабонервных, и, вообще говоря, производительность программиста, кажется, значительно повышается благодаря использованию типов .

Поэтому, когда у нас есть указатель, мы хотим, чтобы компьютер знал, что он может найти в конце указателя. Нам нужен «указатель на int», чтобы компьютер проверял, что когда мы смотрим на биты, которые находятся в конце указателя, мы рассматриваем их как «int», а не как что-то еще.

«Указатель на void» - это указатель без типа, который мы используем, когда система типов C не может захватить то, что мы делаем. Это признак того, что C не в состоянии понять сложность кода, который мы создаем (или, возможно, программист не был достаточно хорош, чтобы выразить то, что он делает в рамках ограничений системы типов C). Следовательно, хотя «void *» удобно в некоторых ситуациях, следует рассматривать его как исключение и стараться избегать его.

0 голосов
/ 04 февраля 2010

Есть ли какая-либо другая причина, по которой в языке Си присутствуют указатели, кроме void?

Это отличный способ свободно обрабатывать фрагменты памяти. :)

0 голосов
/ 04 февраля 2010

Когда вы перебираете блок памяти, на который указывает указатель, необходимо знать размер типа данных, который содержит память. Скажем, у вас есть два указателя, char charptr и int intptr, оба указателя на память на байт 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);
}

Это должно:

  • генерирует предупреждения о указателях разного размера (тип безопасности),
  • выводит идентичные числа в первом столбце (все указатели указывают на один и тот же адрес в памяти), но разные числа во 2-м столбце (который является базовым адресом + размер типа указателя: 1, 2, 4 и 8 байтов) .
0 голосов
/ 04 февраля 2010

Два слова: тип безопасности

В C в Википедии есть небольшая информация о безопасности типа (или ее отсутствии), которая может пролить свет на вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...