为什么我无法访问此void类型数组的第二个元素

时间:2014-10-29 15:49:05

标签: c arrays function-pointers void-pointers

我正在尝试对void类型的数组进行排序,只是为了刷新我的void指针和函数指针,它已经有一段时间了。

这是我的主要文件:

    #include "hawksort.h"
    #include <stdlib.h>
    #define ARR_LEN 10

    int compareNumbers(void*,void*);

    int main (int argc, char** argv)
    {
       int i =0;
       int* arr = malloc(sizeof(int)*ARR_LEN);
       for(i = 0; i < ARR_LEN; i++){
           arr[i] = ARR_LEN - i;
           printf("%d\n",arr[i]);
       }
       printf("here\n");
       hawkBubbleSort(&compareNumbers, (void*)&arr, ARR_LEN);
       return 0;
    }

    int compareNumbers(void* a, void* b)
    {
       printf("%d\n", *(int*)a);
       printf("%d\n", *(int*)b);

       if(*(int*)a > *(int*)b)
           return 1;
       if(*(int*)a < *(int*)b)
           return -1;
       if(*(int*)a == *(int*)b)
           return 0;
       return 0;
}

这是我的头文件包含排序

    int hawkBubbleSort(int (*comparisonAlgo)(void*,void*), void** a, int size){
       int i = 0;

       printf("%d\n",*(int*)a[0]);
       printf("%d\n",*(int*)a[1]);

       int swapped = 1;
       while(swapped == 1){
           swapped = 0;
           for(i = 1; i < size; i++){
               if(comparisonAlgo(a[i-1],a[i]) >= 1){
                   printf("Bigger\n");
                   void* temp = a[i];
                   a[i] = a[i-1];
                   a[i-1] = temp;
                   swapped = 1;
               }
           }
       }

       return 1;
   }

问题是,当我尝试访问[1]时,我遇到了分段错误。 a [0]返回正确的数字10.我不知道问题出在哪里。我感觉它的类型大小和数组递增有问题,虽然我可能搞砸了将arr传递给hawkBubbleSort函数。

示例输出: 10 9 8 7 6 五 4 3 2 1 这里 10 分段错误(核心转储)

4 个答案:

答案 0 :(得分:1)

您的指针使用不正确。你不能简单地传递一个void**并剥离它,期望它作为通用的序列寻址机制。

构建一个采用任意序列和比较函数的通用排序例程比直接的基于类型的排序例程要繁琐得多。对于您的排序功能,应提供以下内容。

  • 正在排序的序列的基地址。
  • 任何单个序列元素的宽度(或步幅)。
  • 正在排序的元素数量。
  • 比较功能。

库函数qsort()并非巧合,它采用这些参数来完成其任务,同样如此。另一个派上用场的实用工具是一个从两个非重叠区域交换存储器的功能,以及上述所有区域,您的任务变得简单如下。我强烈建议你检查它与你的代码相比,特别是如何根据元素步幅调整传递给比较器的指针。作为奖励,我优化了冒泡排序算法(如果有的话,这是一个矛盾的说法):

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

#define ARR_LEN 10

void memswp(void *a, void *b, size_t len)
{
    unsigned char *lhs = a, *rhs = b;
    size_t i=0;
    for (i=0;i<len;++i)
    {
        unsigned char tmp = lhs[i];
        lhs[i] = rhs[i];
        rhs[i] = tmp;
    }
}


int hawkBubbleSort(void* a, size_t len, size_t elemsiz, int (*cmp)(const void*,const void*))
{
    unsigned char *p = a;
    size_t i=0;

    int swapped = 1;
    while(swapped && len-- > 0)
    {
        swapped = 0;
        for(i = 0; i < len; ++i)
        {
            if(cmp(p+(i*elemsiz), p+((i+1)*elemsiz)) > 0)
            {
                memswp(p+(i*elemsiz), p+((i+1)*elemsiz), elemsiz);
                swapped = 1;
            }
        }
    }
    return 0;
}

int compareNumbers(const void* a, const void* b)
{
    int const *lhs = a, *rhs = b;
    int res = (*lhs < *rhs) ? -1 : (*rhs < *lhs);
    printf("cmp(%d,%d) ==> %d\n", *lhs, *rhs, res);
    return res;
}


int main (int argc, char** argv)
{
    int *arr = malloc(ARR_LEN * sizeof(*arr)), i;

    for(i = 0; i < ARR_LEN; i++)
    {
        arr[i] = ARR_LEN - i;
        printf("%d ",arr[i]);
    }
    printf("\n");

    hawkBubbleSort(arr, ARR_LEN, sizeof(*arr), &compareNumbers);

    for(i = 0; i < ARR_LEN; i++)
        printf("%d ",arr[i]);
    printf("\n");

    hawkBubbleSort(arr, ARR_LEN, sizeof(*arr), &compareNumbers);

    for(i = 0; i < ARR_LEN; i++)
        printf("%d ",arr[i]);
    printf("\n");
    return 0;
}

<强>输出

10 9 8 7 6 5 4 3 2 1 
cmp(10,9) ==> 1
cmp(10,8) ==> 1
cmp(10,7) ==> 1
cmp(10,6) ==> 1
cmp(10,5) ==> 1
cmp(10,4) ==> 1
cmp(10,3) ==> 1
cmp(10,2) ==> 1
cmp(10,1) ==> 1
cmp(9,8) ==> 1
cmp(9,7) ==> 1
cmp(9,6) ==> 1
cmp(9,5) ==> 1
cmp(9,4) ==> 1
cmp(9,3) ==> 1
cmp(9,2) ==> 1
cmp(9,1) ==> 1
cmp(8,7) ==> 1
cmp(8,6) ==> 1
cmp(8,5) ==> 1
cmp(8,4) ==> 1
cmp(8,3) ==> 1
cmp(8,2) ==> 1
cmp(8,1) ==> 1
cmp(7,6) ==> 1
cmp(7,5) ==> 1
cmp(7,4) ==> 1
cmp(7,3) ==> 1
cmp(7,2) ==> 1
cmp(7,1) ==> 1
cmp(6,5) ==> 1
cmp(6,4) ==> 1
cmp(6,3) ==> 1
cmp(6,2) ==> 1
cmp(6,1) ==> 1
cmp(5,4) ==> 1
cmp(5,3) ==> 1
cmp(5,2) ==> 1
cmp(5,1) ==> 1
cmp(4,3) ==> 1
cmp(4,2) ==> 1
cmp(4,1) ==> 1
cmp(3,2) ==> 1
cmp(3,1) ==> 1
cmp(2,1) ==> 1
1 2 3 4 5 6 7 8 9 10 
cmp(1,2) ==> -1
cmp(2,3) ==> -1
cmp(3,4) ==> -1
cmp(4,5) ==> -1
cmp(5,6) ==> -1
cmp(6,7) ==> -1
cmp(7,8) ==> -1
cmp(8,9) ==> -1
cmp(9,10) ==> -1
1 2 3 4 5 6 7 8 9 10 

祝你好运。

答案 1 :(得分:1)

我注意到你的代码中有几个严重的错误:

  1. 您通过compareNumbers的方式。函数的函数指针应该是名称本身。如果你通过&compareNumbers,那么你正在通过int (**)(void*,void*),我认为你不想要它。

  2. compareNumbers的实施表明我仍然希望在这种情况下对int进行排序,但是您希望对排序功能进行排序。但是,您的排序功能没有反映出来。所以要修复它,你应该让你的排序函数采用另一个参数,该参数应该是数组的元素大小。所以函数的结果原型应该是:

    int hawkBubbleSort(int(* comparisonAlgo)(void *,void *),void * arr [],int length,size_t elem_size);

  3. 传递数组的方式。你的演员是错的。它应该是(void **)arr

答案 2 :(得分:0)

使用void指针时要遵循一条非常重要的规则:永远不要取消引用它们

这样做的原因是无论何时在C中进行指针运算,场景背后会发生的事情是,编译器知道你正在处理的类型的大小,将取代这样的访问:

int* anArray = calloc(5, sizeof(int));
int i = anArray[2]; // which, is the same as *(anArray + 2);

获取到该变量所需的实际适当偏移量:

int i = anArray + 2*sizeof(int);

但是如果我们使用void *,编译器就无法知道数组中存储的类型的大小!因此,它将移动1个字节,即最小的内存增量。

解决方法是在解除引用之前始终将void *转换为具有正确类型的变量。

在你的情况下:

int hawkBubbleSort(int (*comparisonAlgo)(void*,void*), void** a, int size){
   int i = 0;
   int** array = (int**)a;

   printf("%d\n",*(int*)array[0]);
   printf("%d\n",*(int*)array[1]);

   int swapped = 1;
   while(swapped == 1){
       swapped = 0;
       for(i = 1; i < size; i++){
           if(comparisonAlgo(array[i-1],array[i]) >= 1){
               printf("Bigger\n");
               int* temp = array[i];
               array[i] = array[i-1];
               array[i-1] = temp;
               swapped = 1;
           }
       }
   }

使用原始代码段编辑。

答案 3 :(得分:0)

我认为你想要这个int数组指针的地址,它是(void**) &arr

这将通过引用传递数组,它必须是双指针,因为C中的数组已经是指针。