首页 > 编程知识 正文

void c语言(C语言空类型void的作用,void指针及其应用,C语言void指针及使用注意事项详解)

时间:2023-05-03 11:23:42 阅读:123294 作者:1884

void指针是一个特殊指针,表示为“无类型指针”,在ANSI C中用作通用指针的类型,而不是“char*”。 void指针没有特定类型,因此可以指向任何类型的数据。 也就是说,任何类型的指针都可以直接分配给void指针,而无需执行其他相关的强制类型转换,如下面的代码示例所示。

void *p1;

int *p2;

.

p1=p2;

然而,这并不意味着可以将void指针直接指定给其他类型的指针,而无需强制类型转换。 因为“空类型”包含“有类型”,“有类型”不包含“空类型”。 我们可以说“男人女人都是人”,但不要说“人是男人”或“人是女人”。 因此,以下示例代码编译失败,VC 2010显示错误消息“avalueoftype ' void * ' cannotbeassignedtoanentityoftype ' int *”

void *p1;

int *p2;

.

p2=p1;

由此可见,要将void指针指定给其他类型的指针,必须强制执行类型转换。 如下所示:

void *p1;

int *p2;

.

P2=(int* ) p1;

避免计算void指针

ANSI C标准规定,执行算法操作的指针必须知道数据类型的大小,也就是说,必须知道内存目标地址的准确值。 如下所示:

char a[20]='qwertyuiopasdfghjkl ';

int*p=(int* ) a;

p;

printf('%s ',p );

在上面的示例代码中,指针变量p的类型初始化为" int* ",指向的类型初始化为int,指向整数变量a。

执行语句“p”时,编译器将指针p的值加上“sizeof(int )() 32位系统中int占4字节,这里是加上4 () ),并将p 但是,由于char型的长度为1字节,所以语句“printf(%s ),p”输出“tyuiopasdfghjkl”。

对于void指针,编译器不知道指向的对象的大小,因此不能对void指针进行算术运算,如以下代码示例所示。

void * p;

p; //ANSI :错误

p=1; //ANSI :错误

上面的代码在VC 2010中显示错误消息“expressionmustbeapointertoacompleteobjecttype”。

但值得注意的是,GNU并不这么认为。 指定" void* "的算法操作与" char* "匹配。 因此,以下语句在GNU编译器中也是正确的。

void * p;

p; //GUN :正确

p=1; //GUN :正确

下面的代码示例演示如何在GCC上执行void指针自增长操作。

#包含

输入主(语音) )。

{

void * p='ILoveC ';

p;

printf(%s(n ),p );

}

执行结果如下。

洛韦克

由此可见,GNU和ANSI还有一些区别,而GNU比ANSI更“开放”,支持更多的语法。 但在实际设计环境中,应尽量遵循ANSI标准,避免void指针的算术操作。

如果函数的参数是任意类型的指针,请将该参数转换为void*

如上所述,void指针可以指向任何类型的数据。 此外,任何类型的指针都可以直接分配给void指针,而无需执行其他相关的强制类型转换。 因此,在编程中,如果函数的参数是任意类型的指针,则必须使用void指针作为函数的参数。 这样,函数就可以接受任何数据类型的指针作为参数。

典型的函数包括内存操作函数memcpy和memset,如以下代码所示。

void*memset(void*buffer,int b,size_t size ) )。

{

资产(缓冲区!=NULL;

char*retaddr=(char* ) buffer;

wile (大小----0 ) ) ) )。

{

*(retaddr )=)=(char ) b;

}

返回重做;

}

(void*memcpy(void*dst,const void *src,size_t size ) ) ) ) ) ) ) )

{

宏碁

t((dst!=NULL) && (src!=NULL));

char *temp_dest = (char *)dst;

char *temp_src = (char *)src;

char* retAddr = temp_dest;

size_t i = 0;

/* 解决数据区重叠问题*/

if ((retAddr>temp_src) && (retAddr

{

for (i=size-1; i>=0; i--)

{

*(temp_dest++) = *(temp_src++);

}

}

else

{

for (i=0; i

{

*(temp_dest++) = *(temp_src++);

}

}

*(retAddr+size)='';

return retAddr;

}

这样,任何类型的指针都可以传入 memcpy 函数和 memset 函数中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型。memcpy 函数的调用示例如下面的代码所示:

char buf[]="abcdefg";

// buf+2(从c开始,长度3个,即cde)

memcpy(buf, buf+2 ,3);

printf("%sn", buf);

或者进行如下形式的调用:

int dst[100];

int src[100];

memcpy(dst, src, 100*sizeof(int));

因为参数类型是 void*,所以上面的调用都是正确的。现在假设 memcpy 函数的参数类型不是 void*,而是 char*,如下面的代码所示:

char *memcpy(char* dst, const char* src, size_t size)

{

assert((dst !=NULL) && (src != NULL));

char *retAddr = dst;

size_t i = 0;

if ((retAddr>src) && (retAddr

{

for (i=size-1; i>=0; i--)

{

*(dst++)= *(src++);

}

}

else

{

for (i=0; i

{

*(dst++) = *(src++);

}

}

*(retAddr+size)='';

return retAddr;

}

现在继续执行如下形式的调用:

int dst[100];

int src[100];

memcpy(dst, src, 100*sizeof(int));

由于类型不匹配,编译器就会报错,如图 1 所示。

图 1

由此可见,这样的函数同时也失去了通用性。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。