由void *data[ ]引发的思考

最近在某个代码的函数原型中遇到了形如void* data[ ] 的参数类型表述,在这里兜兜转转了很久,终于在多番查阅资料后解决了一些困惑,特此记录。

void *data[ ]是个什么鬼?

1、先来解决形如 type *name[ ]的问题。

   这里有一个比较实在的推断方法

   int buf[48] ,指的是一个数组有48个元素,每个元素都是int类型

   char buf[48],指的是一个数组有48个元素,每个元素都是int类型

  ......

 需要注意先表述元素个数再表述元素类型,这么表述的情况下就会容易理解数组里带指针的情况:

   int *buf[48] ,指的是一个数组有48个元素,每个元素都是int*类型,因此这个是包含有48个int* 类型数据的数组;

   char *buf[48],指的是一个数组有48个元素,每个元素都是char*类型,因此这个是包含有48个char *类型数据的数组;

由此我们就能知道, 对于void *data[ ] ,我们先分析[ ],再分析void *,可知,这个是包含了若干个void *类型的数组;

 为什么说是若干,因为[ ]里面未指定具体的数字。我们在定义数组时有这么一种定义形式,如 int buf[ ] ={0,1,2,3,4};

  如果[ ]里不指定具体的大小,则大小由实际赋值的内容决定,这种通配的形式会比较灵活。

       这么来解答这个问题是不是有点耍流氓,其实还有理论基础的:在运算符的优先级中,[ ]运算符的优先级是处于第一级的,而*运算符作为一元运算符时,优先级处于第二级,作为乘法运算符时,处于第四级,[ ]的优先级高于*,因此在*和[ ]同时出现时,我们应该先考虑[],再考虑*,上述推断的方法也只是提供了一个方便记忆的方法;

2 、有关void *类型的困惑 

   确定了void *data[ ]是一个包含由若干个void *指针的元素的数组外,又有了新的问题,那么void *又是个什么鬼?

从多方查阅资料得知:void *有如下的特性: (来源:void *指针是什么含义

void指针是一种没有类型的指针

任何指针都可以赋值给void指针

void指针转换为其他指针时需要进行类型转换

void指针由于不确定类型不能解引用

因此,可以这么说,void *的存在就是为了通配各种参数类型的,如果在一个函数的参数列表中有个void *的参数,那么给它传入任何类型的指针参数都是正确的。

 3、引发血案的罪魁祸首

  那么void*也讲清了,那么参数列表中出现void *data[ ]时,到底该传入什么参数呢?

  来讨论下如下的函数场景

   void func1(void *_data0[ ]);

  然后有一个int类型的数组: int data[10]={0};

  如何给这个函数传参呢?我们都知道数组名data代表数组的首元素data[0]的地址,data本身是一个指针,那么我们传入的方式是下面的形式吗?

   func1(data);

  如果是这么传入参数的话,那么如果有一个如下的函数原型

   void func1(void * _data0); 

   这个该怎么传入数据呢?还是func1(data)吗?

  如果照这么说,那么  void func1(void *data0[ ]) 和 void func1(void *data0)是等价的吗?

  一时没有搞清楚,到底是不是一样的呢,于是简单的写了如下的测试代码看了下效果:

#include <stdio.h>
#include <stdint.h>
#include <string.h>

char a[12] = {0,1,2,3,4,5,6,7,8,9,10,11};

void function1(void *data,int length)
{
    char tmp[12] = {0};
    memcpy(tmp,data,length);
    for(int i = 0 ; i < length ; i++)
        printf("%d\r\n",tmp[i]);
    
    printf("\r\n");
}

void function2(void *data[],int length)
{
    char tmp[12] = {0};
    memcpy(tmp,data,length);
    
    for(int i = 0 ; i < length ; i++)
        printf("%d\r\n",tmp[i]);
    printf("\r\n");
}

void function3(void **data,int length)
{
    char tmp[12] = {0};
    memcpy(tmp,data,length);
    
    for(int i = 0 ; i < length ; i++)
        printf("%d\r\n",tmp[i]);
    printf("\r\n");
}

int main()
{
      function1(a,12);
      function2(a,12);
      function3(a,12);
}

  通过gcc编译该程序,则有如下的打印:

gcc void_pointer.c -o void_pointer.c 
gcc: fatal error: input file ‘void_pointer.c’ is the same as output file
compilation terminated.
test@test-PC:~/Works/code_code/C/pointer$ gcc void_pointer.c -o void_pointer
void_pointer.c: In function ‘main’:
void_pointer.c:42:17: warning: passing argument 1 of ‘function2’ from incompatible pointer type [-Wincompatible-pointer-types]
       function2(a,12);
                 ^
void_pointer.c:18:6: note: expected ‘void **’ but argument is of type ‘char *’
 void function2(void *data[],int length)
      ^
void_pointer.c:43:17: warning: passing argument 1 of ‘function3’ from incompatible pointer type [-Wincompatible-pointer-types]
       function3(a,12);
                 ^
void_pointer.c:29:6: note: expected ‘void **’ but argument is of type ‘char *’
 void function3(void **data,int length)
      ^

  从上面的打印可以看出,我们给 function2(void *data[],int length) 函数的 void *data[ ]相当于 void **,而我们给这个参数传递的是一个char*的数据,这个类型是不兼容的,我又特意写了个void function3(void **data,int length),从编译日志上 void *data[ ]和 void **data的类型是一致的,由此可见, void *data[ ]是一个指针的指针.因此给void **传入 char *是不正确的操作.

    参考资料:

彻底理解c语言中int (*p)[3]和int *p[3]的意思
二维数组指针表示,C语言指针引用二维数组详解
二维数组名 二级指针 数组指针
一维数组中指针数组和数组指针的区别
C 语言中 void* 详解及应用
C语言二维数组指针(指向二维数组的指针)详解
运算符优先级和结合律
void *指针是什么含义

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值