Пустой указатель используется в C как своего рода общий указатель.Переменная указателя void может использоваться для хранения адреса любого типа переменной.Проблема с указателем void заключается в том, что после назначения адреса указателю информация о типе переменной больше не доступна для проверки компилятором.
В общем случае следует избегать указателей void, так кактип переменной, адрес которой находится в указателе void, больше не доступен для компилятора.С другой стороны, есть случаи, когда указатель void очень удобен.Однако программист должен знать тип переменной, адрес которой находится в переменной указателя void, и правильно ее использовать.
У большей части старого источника C есть приведения в стиле C между указателями типов и указателями void.В современных компиляторах этого нет необходимости, и его следует избегать.
Размер переменной void-указателя известен.Что не известно, так это размер переменной, указатель которой находится в переменной void pointer.Например, вот несколько исходных примеров.
// create several different kinds of variables
int iValue;
char aszString[6];
float fValue;
int *pIvalue = &iValue;
void *pVoid = 0;
int iSize = sizeof(*pIvalue); // get size of what int pointer points to, an int
int vSize = sizeof(*pVoid); // compile error, size of what void pointer points to is unknown
int vSizeVar = sizeof(pVoid); // compiles fine size of void pointer is known
pVoid = &iValue; // put the address of iValue into the void pointer variable
pVoid = &aszString[0]; // put the address of char string into the void pointer variable
pVoid = &fValue; // put the address of float into the void pointer variable
pIvalue = &fValue; // compiler error, address of float into int pointer not allowed
Один из способов использования указателей void - использование нескольких различных типов структур, которые предоставляются в качестве аргумента для функции, обычно это своего рода диспетчерская функция.,Поскольку интерфейс для функции допускает разные типы указателей, в списке аргументов должен использоваться указатель void.Затем тип указанной переменной определяется либо дополнительным аргументом, либо проверкой указанной переменной.Примером такого использования функции может быть что-то вроде следующего.В этом случае мы включаем индикатор типа структуры в первый член различных перестановок структуры.Пока все структуры, которые используются с этой функцией, имеют в качестве первого члена int
, указывающий тип структуры, это будет работать.
struct struct_1 {
int iClass; // struct type indicator. must always be first member of struct
int iValue;
};
struct struct_2 {
int iClass; // struct type indicator. must always be first member of struct
float fValue;
};
void func2 (void *pStruct)
{
struct struct_1 *pStruct_1 = pStruct;
struct struct_2 *pStruct_2 = pStruct;
switch (pStruct_1->iClass) // this works because a struct is a kind of template or pattern for a memory location
{
case 1:
// do things with pStruct_1
break;
case 2:
// do things with pStruct_2
break;
default:
break;
}
}
void xfunc (void)
{
struct struct_1 myStruct_1 = {1, 37};
struct struct_2 myStruct_2 = {2, 755.37f};
func2 (&myStruct_1);
func2 (&myStruct_2);
}
Что-то подобное выше имеет ряд проблем проектирования программного обеспечения.с помощью сцепления и сцепления, поэтому, если у вас нет веских причин для использования этого подхода, лучше переосмыслить свой дизайн.Однако язык программирования C позволяет вам это делать.
В некоторых случаях необходим указатель void.Например, функция malloc()
, которая выделяет память, возвращает указатель void, содержащий адрес области, которая была выделена (или NULL, если выделение не удалось).В этом случае указатель void допускает одну функцию malloc()
, которая может возвращать адрес памяти для любого типа переменной.Ниже показано использование malloc()
с различными типами переменных.
void yfunc (void)
{
int *pIvalue = malloc(sizeof(int));
char *paszStr = malloc(sizeof(char)*32);
struct struct_1 *pStruct_1 = malloc (sizeof(*pStruct_1));
struct struct_2 *pStruct_2Array = malloc (sizeof(*pStruct_2Array)*21);
pStruct_1->iClass = 1; pStruct_1->iValue = 23;
func2(pStruct_1); // pStruct_1 is already a pointer so address of is not used
{
int i;
for (i = 0; i < 21; i++) {
pStruct_2Array[i].iClass = 2;
pStruct_2Array[i].fValue = 123.33f;
func2 (&pStruct_2Array[i]); // address of particular array element. could also use func2 (pStruct_2Array + i)
}
}
free(pStruct_1);
free(pStruct_2Array); // free the entire array which was allocated with single malloc()
free(pIvalue);
free(paszStr);
}