如何在C语言中使用空指针?

3

以下是我不太理解如何完成的几个函数声明。我已经浏览了网页来了解什么是void指针,我知道它必须被转换为有用的内容(因为它只是指向某个内存块),但我不知道这如何有助于完成这些声明。

/* type of comparison function that specifies a unique order.
   Returns 1 if pointer1 should come before,
   0 if equal to, or -1 if after pointer2. */
typedef int (*compare_function) (const void* pointer1, const void* pointer2);

/* get the data object */
void* get_obj(const void* item_pointer);

这样的功能还有更多,但我认为如果我能理解这两个功能,那么就应该可以了。例如,对于第二个功能,我们如何将item_pointer转换为适当的任何内容以返回?


好问题,但范围太广。 - Fiddling Bits
你是负责实现get_obj的人吗?如果是,那么这很大程度上取决于item_pointer应该是什么。 - hugomg
第一个是函数指针。你很可能需要定义一个带有这个签名的函数。你知道pointer1pointer2的类型,所以你可以适当地进行类型转换。 - Fiddling Bits
Fiddling Bits 是正确的,你必须在函数中使用 compare_function 作为操作数。例如:compFunc(compare_function* cFunc); - Cartier
Void指针最适用于不需要对其进行解引用但仍然需要传递它们的函数。一个完美的例子是pthread_create()和family。此函数将接受一个指向函数的指针和一个void指针作为函数的参数。这个pthread_create()本身并不关心函数的参数是什么,因此void指针就像一个模板。被调用的函数负责知道void指针应该是什么类型。 - alvits
我正要评论你另一个问题,但你却刚刚删除了它:“在你问关于游戏开发图形的其他问题之前,请花时间理解哪些问题在这里受欢迎,哪些不受欢迎。即使涉及编程,模糊、开放式、闲聊式的问题也被认为是离题的。” - Pascal Cuoq
3个回答

9

void *通常意味着你只对数据的地址感兴趣,而不关心其类型,原因如下:

  • 这个void *指向的数据的内部表示是隐藏的,你不能直接访问数据,这是一种信息隐藏,函数2就是一个很好的例子。

  • 类型由调用链中的某个函数知道,例如qsort和大多数将参数传递给其他函数的函数。

  • 类型不是必需的,因为指针指向的数据将被处理为不同的类型,例如memcpy可能会将数据处理为字节,unsigned char *


1
在C语言中使用快速排序进行排序时,使用void指针可以对数组中的任何数据进行排序。如果参数b在参数a之前、之后或与参数a相同时,排序函数必须返回-1、+1或0。
#include <stdio.h>
#include <stdlib.h>

int sort_order( const void *, const void *);

int main(void)
{
  int i;
  char alfa[6] = { ’C’, ’E’, ’A’, ’D’, ’F’, ’B’ }; 
  qsort( (char*)alfa, 6, sizeof(char), sort_order); 
  for (i=0 ; i<5 ; i++)  // now in order?
     printf("\nchar %d = %c",i, alfa[i]);
  printf("\n");
  system("PAUSE");
  return 0;
}

int sort_order( const void* a, const void* b)
{
  if      ( *((char*)a) < *((char*)b) )     return -1 ;
  else if ( *((char*)a) > *((char*)b) )     return  1 ;
  else                                      return  0 ;
}

然后您可以对自己的数据类型进行排序:
typedef struct {   float left;   float right;} ears;
typedef struct{  char name[13];  int weight;  ears eararea;} monkey;    

monkey* Index[4];

for(i=0;i<4;i++)   
    Index[i]= (monkey* )malloc(sizeof(monkey));     

qsort((void* ) Index, 4, sizeof(monkey* ), sort_order);

// Sorted by weight    
int sort_order( const void* a, const void* b) {   
    if((**((monkey** )a)).weight < (**((monkey** )b)).weight) return -1 ;   
    else if ((**((monkey** )a)).weight > (**((monkey** )b)).weight ) return  1 ;
    else return  0 ;
}

完整程序

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    float left;
    float right;
} ears;

typedef struct {
    char name[13];
    int weight;
    ears eararea;
} monkey;

int sort_monkeys( const void *, const void *);

int main(void)
{   monkey* monkeys[4];
    int i;
    for(i=0; i<4; i++) {
        monkeys[i]= (monkey* )malloc(sizeof(monkey));
        monkeys[i]->weight=i*10;
        if (i==2)
            monkeys[i]->weight=1;
    }
    for (i=0 ; i<4; i++)
        printf("\nchar %d = %i",i, monkeys[i]->weight);

    qsort((void* ) monkeys, 4, sizeof(monkey* ), sort_monkeys);

    for (i=0 ; i<4; i++)  // now in order?
        printf("\nmonkey %d = %i",i, monkeys[i]->weight);
    return 0;
}

// Sorted by weight
int sort_monkeys( const void* a, const void* b) {
    if((**((monkey** )a)).weight < (**((monkey** )b)).weight) return -1 ;
    else if ((**((monkey** )a)).weight > (**((monkey** )b)).weight ) return  1 ;
    else return  0 ;
}

0
任何指针类型都可以赋值给 void*,这在函数不需要知道类型或类型信息通过其他方式传递的情况下非常有用。这样,您就可以编写一个函数来处理任何指针类型,而不是为每个数据类型编写单独的函数。
虽然您不能对 void* 进行解引用,但可以将其转换为任何类型并进行解引用 - 其语义即是否有意义取决于代码,并且不能由编译器强制执行。
经常情况下,通用 函数并不关心某个数据块的内容,只关心其地址和大小。
以下是一个简单的示例:
void memcopy( void* to, void* from, int length )
{
    char* source = (char*)from ;
    char* dest = (char*)to ;
    int i ;

    for( i = 0; i < lengt; i++ )
    {
        dest[i] = source[i] ;
    }
}

int main()
{
    typedef struct
    {
        int x ;
        int y ;

    } tItem

    tItem AllItems[256] = {0} ;
    tItem AllItemsCopy[256] ;

    memcopy( AllItemsCopy, AllItems, sizeof(AllItems) ) ;
}

看到 memcopy() 不需要知道一个 tItem 是什么就能复制一个数组,它只需要知道字节数组的地址和大小。它将 void* 指针参数强制转换为 char 数组以进行逐字节复制数据的重新解释。为了做到这一点,它不需要知道 tItem 或任何其他传递给它的数据对象的内部语义。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接