zoukankan      html  css  js  c++  java
  • 万能指针void*学习

    1)可以用任何类型的指针对 void 指针进行赋值

      由于void 指针没有特定的类型,因此可以指向任何类型的数据。因此他可以指向任何类型的数据。也就是说,任何类型的指针都可以直接赋值给 void 指针,而无需进行其他相关的强制类型转换。

      例如:

      double d = 1.54;

      void * p = & d;

    2)void 指针不可以直接赋值给其它类型的指针

      因为 “空类型” 可以包容 “有类型”,而 “ 有类型” 则不能包容 “空类型”。

      由此可见,要将 void 指针赋值给其他类型的指针,必须进行强制类型转换。如:

    1 void * p1;
    2 int * p2;
    3 . . .
    4 p2 = (int *)p1;

    3)避免对 void 指针进行算术操作

      ANSI C 标准规定,进行算法操作的指针必须确定知道其指向数据类型大小,也就是说必须知道内存目的地址的确切值。

    1 char a[20]="qwertyuiopasdfghjkl";
    2 int *p=(int *)a;
    3 p++;
    4 printf("%s", p);  // tyuiopasdfghjkl

      p++;一步前进了sizeof(int)=4 个字节,而类型为char,sizeof(char)=1

      对于 void 指针,编译器并不知道所指对象的大小,所以对 void 指针进行算术操作都是不合法的,如下面的示例代码所示:

    1 void * p;
    2 p++;    // ANSI:错误
    3 p+= 1; // ANSI:错误

      

      但值得注意的是,GNU 则不这么认为,它指定“void*”的算法操作与“char*”一致。因此下列语句在 GNU 编译器中都是正确的:

    1 void * p;
    2 p++;      // GUN:正确
    3 p+=1;      // GUN:正确

      下面代码演示了在 GCC中 执行对 void 指针的自增操作:

    1 #include <stdio.h>
    2 int main(void)
    3 {
    4     void * p="ILoveC";
    5     p++;
    6     printf("%s
    ", p);  //输出:LoveC
    7 }

      由此可见,GNU 和 ANSI 还存在着一些区别,相比之下,GNU 较 ANSI 更“开放”,提供了对更多语法的支持。但是在真实的设计环境中,还是应该尽可能符合 ANSI 标准,尽量避免对 void 指针进行算术操作。

    4)应用:内存操作函数

      根据 1)中的内容,void 指针可以指向任意类型的数据,同时任何类型的指针都可以直接赋值给 void 指针,而无需进行其他相关的强制类型转换。因此,在编程中,如果函数的参数可以是任意类型指针,那么应该使用 void 指针作为函数的形参,这样函数就可以接受任意数据类型的指针作为参数。

     1 void *memset(void *buffer, int b, size_t size)
     2 {
     3     assert(buffer!=NULL);
     4     char* retAddr = (char*)buffer;
     5     while (size-- > 0)
     6     {
     7         *(retAddr++) = (char)b;
     8     }
     9     return retAddr;
    10 }
    11 
    12 
    13 void *memcpy (void *dst,  const void *src,  size_t size)
    14 {
    15     assert((dst!=NULL) && (src!=NULL));
    16     char *temp_dest = (char *)dst;
    17     char *temp_src = (char *)src;
    18     char* retAddr = temp_dest;
    19     size_t i = 0;
    20     /* 解决数据区重叠问题*/
    21     if ((retAddr>temp_src) && (retAddr<(temp_src+size)))
    22     {
    23         for (i=size-1; i>=0; i--)
    24         {
    25             *(temp_dest++) = *(temp_src++);
    26         }
    27     }
    28     else
    29     {
    30         for (i=0; i<size; i++)
    31         {
    32             *(temp_dest++) = *(temp_src++);
    33         }
    34     }
    35     *(retAddr+size)='';
    36     return retAddr;
    37 }
  • 相关阅读:
    第二十三讲:访问者模式
    第二十二讲:备忘录模式
    第二十讲:迭代模式
    第十九讲:职责链模式
    第十八讲:中介者模式
    UTC时间、GMT时间、本地时间、Unix时间戳
    【基础】SQL Server系统库的作用
    【基础】SQL Server系统库的作用
    【基础】SQL Server系统库的作用
    【收集】C#一些基础的面试题
  • 原文地址:https://www.cnblogs.com/guoyujiang/p/12294653.html
Copyright © 2011-2022 走看看