[英]Why can't I access the second element of this void type array
我试图对一个类型为void的数组进行排序,只是想弄清楚我的void指针和函数指针,已经有一段时间了。
这是我的主要c文件:
#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;
}
问题是,当我尝试访问a [1]时出现分段错误。 a [0]返回正确的数字10。我不知道问题出在哪里。 我有一种感觉,它的类型大小和在数组中的递增有一个问题,尽管我可能把arr传递给hawkBubbleSort函数时有些混乱。
样本输出:10 9 8 7 6 5 4 3 2 1此处10分段故障(核心已转储)
您的指针用法不正确。 您不能简单地传递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
祝你好运。
我注意到您的代码中有几个严重错误:
您传递compareNumbers
的方式。 函数的函数指针应为名称本身。 如果您通过&compareNumbers
,那么您正在传递int (**)(void*,void*)
,我认为您不想要它。
compareNumbers
表明,在这种情况下,您仍然希望对int
进行排序,但是您希望使排序函数具有通用性。 但是,您的排序功能对此没有反映。 因此,要解决此问题,您应该让排序函数采用另一个参数,该参数应该是数组的元素大小。 因此该函数的结果原型应为:
int hawkBubbleSort(int(* comparisonAlgo)(void *,void *),void * arr [],int length,size_t elem_size);
您传递数组的方式。 你的演员选错了。 它应该(void **)arr
。
使用空指针时,有一个非常重要的规则要遵循: 永远不要取消引用它们 。
这样做的原因是,每当您在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;
}
}
}
使用原始代码段进行编辑。
我认为您想要此int数组指针的地址,该地址应为(void**) &arr
。
这将通过引用传递数组,并且它必须是双指针,因为C中的数组已经是指针。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.