zoukankan      html  css  js  c++  java
  • C++ void*解惑

    最近遇到void *的问题无法解决,发现再也无法逃避了(以前都是采取悄悄绕过原则),于是我决定直面它。

    在哪遇到了?


    线程创建函数pthread_create()的最后一个参数void *arg,嗯?传地址还是传值?传值好像有警告。

    还有别的出现的地方呢

     

    看memcpy(),返回值和参数都有void *,那又怎么传呢?下面我们首先来说说void *是什么。

    一:void *是什么?

    C语言中,*类型就是指针类型。比如 int *p,double *q,虽然是不一样的指针,但是大小却一样sizeof(p) == sizeof(q),其实很容易理解,因为他们都是同一种类型*类型的。C语言是强类型的语言。对类型的区分十分严格。那这两个有什么不同点吗?有,+1就不同了,看下面的图:


    也就是对于一个指针而言,如果我们在前面规定了它的类型。那就相当于决定了它的“跳跃力”。“跳跃力”就比如说上面图中int跳了4个字节,但是double跳了8个字节。基于这样的理解,我要对void *下定义了:

    void * 是一个跳跃力未定的指针
    二:跳跃力什么时候定?

    这就是它的神奇之处了,我们可以自己控制在需要的时候将它实现为需要的类型。这样的好处是:编程时候节约代码,实现泛型编程。比如我们经常写的排序算法,就可以这么写:


    #include <stdio.h>
    #include <string.h>
    static void Swap(char *vp1, char *vp2, int width)
    {
    char tmp;
    if ( vp1 != vp2 ) {
    while ( width-- ) {
    tmp = *vp1;
    *vp1++ = *vp2;
    *vp2++ = tmp;
    }
    }
    }
    void BubbleSort(void *base, int n, int elem_size,
    int (*compare)( void *, void * ))
    {
    int i, last, end = n - 1;
    char *elem_addr1, *elem_addr2;
    while (end > 0) {
    last = 0;
    for (i = 0; i < end; i++) {
    elem_addr1 = (char *)base + i * elem_size;
    elem_addr2 = (char *)base + (i + 1) * elem_size;
    if (compare( elem_addr1, elem_addr2 ) > 0) {
    Swap(elem_addr1, elem_addr2, elem_size);
    last = i;
    }
    }
    end = last;
    }
    }
    int compare_int(void *elem1, void *elem2)
    {
    return (*(int *)elem1 - *(int *)elem2);
    }
    int compare_double(void *elem1, void *elem2)
    {
    return (*(double *)elem1 > *(double *)elem2) ? 1 : 0;
    }
    int main(int argc, char *argv[])
    {
    int num_int[8] = {8,7,6,5,4,3,2,1};
    double num_double[8] = {8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1};
    int i;
    BubbleSort(num_int, 8, sizeof(int), compare_int);
    for (i = 0; i < 8; i++) {
    printf("%d ", num_int[i]);
    }
    printf(" ");
    BubbleSort(num_double, 8, sizeof(double), compare_double);
    for (i = 0; i < 8; i++) {
    printf("%.1f ", num_double[i]);
    }
    printf(" ");
    return 0;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57


    上面的compare_int和compare_double就是定它跳跃力的时候。

    三:再来说memcpy

    我们先来看下面这段代 码:

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

    struct stu{
    int id;
    int num;
    };

    #define LEN sizeof(struct stu) /*LEN 为stu的大小*/

    int main(int argc,char *argv[])
    {
    struct stu stu1,stu2;
    stu1.id = 2;
    stu1.num = 3;

    char str[LEN];

    memcpy(str,&stu1,LEN); /*将stu1保存进str*/

    memcpy(&stu2,str,LEN); /*将str转换成stu2*/

    printf("%d %d ",stu2.id,stu2.num); /*访问stu2仍然得到 2 和 3*/
    return 0;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26


    说明:str 是一个char *类型的,但是&stu是一个struct stu *类型的,就像我们前面说的那样,他们的“跳跃力”是不一样的,但是memcpy之所以能将它们都接受,就是因为它的参数是(void *)类型的。在参数传递的时候包容万象,全都接受,这才能体现人家是memcpy()吗,mem是内存,肯定可以不非要按照某种具体类型处理,具体至于还想memcpy的内部怎么处理,看下面:

    http://blog.csdn.net/yangbodong22011/article/details/53227560

    四:总结

    void *是一种指针类型,常用在函数参数、函数返回值中需要兼容不同指针类型的地方。我们可以将别的类型的指针无需强制类型转换的赋值给void *类型。也可以将void *强制类型转换成任何别的指针类型,至于强转的类型是否合理,就需要我们程序员自己控制了。

    #include<stdio.h>

    int main(int argc,char *argv[])
    {
    int a = 2;
    double b = 2.0;
    void *c; //定义void *
    int *p = &a;
    c = p; //将int * 转成void *,
    double *q = (double *)c; //将void *转成double *
    printf("%.f ",*q);

    return 0;
    }

    oid * 为 “不确定类型指针”。
    void *不可以解引用

    (1)void *可以接受任何类型的赋值:
        任何类型的指针都可以直接赋值给void *型指针,无需进行强制类型转换,相当于void *包含了其他类型的指针。

      
    (2)void *可以赋值给任何类型的变量
    但是需要进行强制转换,应为void *的范围较大,所以强制转换,使其进行范围缩小。


    void *主要使用在函数里,可以接受其他类型的指针,让函数使用起来更加便捷。

    void * 1,不能解引用 2,+ - 运算


    结果是不是正确呢?自己试一试吧~

  • 相关阅读:
    JeePlus:代码生成器
    JeePlus:API工具
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
  • 原文地址:https://www.cnblogs.com/tsh292278/p/11289739.html
Copyright © 2011-2022 走看看