C语言中的混洗泛型数组

C语言中的混洗泛型数组,c,arrays,shuffle,C,Arrays,Shuffle,我有一个指向结构的指针数组 我试图用这个问题的第一个答案来解决这个问题,但我遇到了一个seg故障: 在尝试此代码后,我尝试使用此函数进行洗牌: static void shuffle(void *array, size_t n, size_t size) { void * aux; aux = malloc (size); if (n > 1) { size_t i; for (i = 0; i < n - 1; ++i) {

我有一个指向结构的指针数组

我试图用这个问题的第一个答案来解决这个问题,但我遇到了一个seg故障:

在尝试此代码后,我尝试使用此函数进行洗牌:

static void shuffle(void *array, size_t n, size_t size) {
    void * aux;
    aux = malloc (size);

    if (n > 1) {
        size_t i;
        for (i = 0; i < n - 1; ++i) {

            size_t j = i + rand() / (RAND_MAX / (n - i) + 1);

            memcpy(aux, array[j], size);
            memcpy(array[j], array[i], size);
            memcpy(array[i], aux, size);
        }
    }
}
我收到这个警告和错误3次:每个memcpy一次

编辑 我更改了代码,因为我试图使用这个新代码而不是旧代码。

在C中,你不能取消对void*的引用,也不能对它进行算术运算,因为它实际上是指向未知类型对象的指针,所以编译器不知道该做什么。一些编译器允许算术作为扩展,就像它是char*,但不依赖它

因此:

将你的void*转换为char*并使用它们。别忘了为指针算法做自己的缩放。 另外,memcpy应该得到一个指针,而不是指向的对象,所以使用+,而不是[]。 旁白:请避免内存泄漏,释放您分配的所有内存。 最后,请注意,random可能具有很小的范围和不好的统计特性。 最后+1:,显示它做得多么糟糕

在C语言中,Vou不能取消对void*的引用,也不能对其进行算术运算,因为它实际上是指向未知类型对象的指针,因此编译器不知道该做什么。一些编译器允许将算术作为扩展,就像它是char*一样,但不依赖它

因此:

将你的void*转换为char*并使用它们。别忘了为指针算法做自己的缩放。 另外,memcpy应该得到一个指针,而不是指向的对象,所以使用+,而不是[]。 旁白:请避免内存泄漏,释放您分配的所有内存。 最后,请注意,random可能具有很小的范围和不好的统计特性。 最后+1:,显示它做得多么糟糕

确保你实际上编译了C代码和C++在类型转换方面的不同 将指针传递到数组中的元素,而不是取消对它们的引用:array[i]->&array[i] 不能保证定义sizeofvoid,请使用char 添加一些断言来检查memcpy的参数。人们可以使用模来钳制i和j,尽管这通常也不会产生良好的随机数分布。 确保你实际上编译了C代码和C++在类型转换方面的不同 将指针传递到数组中的元素,而不是取消对它们的引用:array[i]->&array[i] 不能保证定义sizeofvoid,请使用char 添加一些断言来检查memcpy的参数。人们可以使用模来钳制i和j,尽管这通常也不会产生良好的随机数分布。
除了@Deduplicator的好建议外,还需要按大小缩放j偏移量

此代码还更改了j计算。我认为你所拥有的不会很好地发挥作用

#include <stdlib.h>
static void shuffle(void *array, size_t n, size_t size) {
  // This if() is not needed functionally, but left per OP's style
  if (n > 1) {
    char *carray = array;
    void * aux;
    aux = malloc(size);
    size_t i;
    for (i = 1; i < n; ++i) {
      size_t j = rand() % (i + 1); 
      j *= size;
      memcpy(aux, &carray[j], size);
      memcpy(&carray[j], &carray[i*size], size);
      memcpy(&carray[i*size], aux, size);
    }
    free(aux);
  }
}
澄清尺寸j=i+rand/rand\u MAX/n-i+1的弱点

将公式中的值0替换为rand_MAX将生成样本分布。示例i=0,n=30265,RAND_MAX=2147483647生成值j=0到30263,每次70957次,j=30264=41000。这是一个坏情况,可能不是最坏的情况

使用尺寸j=i+r%n-i;生成几乎一致的结果

示例i=0,n=30265,RAND_MAX=2147483647分别生成值j=0到307、70957次和j=308到30264=70956次。存在补偿这种小偏差的方法。许多这样的帖子

注意:这两种方法都不能修复较差rand中的继承弱点,但是当尝试使用0到rand_MAX的子范围时,方法选择会使情况明显恶化

[编辑]

孔的尺寸为i+rand/rand\u MAX/n-i+1


在大约n>sqrtRAND_MAX且i=0的某个地方,将不会生成接近n的值。示例:i=0,n=104643,RAND_MAX=2147483647不生成值104638到104642。

除了@Deduplicator good advice外,还需要按大小缩放j偏移量

此代码还更改了j计算。我认为你所拥有的不会很好地发挥作用

#include <stdlib.h>
static void shuffle(void *array, size_t n, size_t size) {
  // This if() is not needed functionally, but left per OP's style
  if (n > 1) {
    char *carray = array;
    void * aux;
    aux = malloc(size);
    size_t i;
    for (i = 1; i < n; ++i) {
      size_t j = rand() % (i + 1); 
      j *= size;
      memcpy(aux, &carray[j], size);
      memcpy(&carray[j], &carray[i*size], size);
      memcpy(&carray[i*size], aux, size);
    }
    free(aux);
  }
}
澄清尺寸j=i+rand/rand\u MAX/n-i+1的弱点

将公式中的值0替换为rand_MAX将生成样本分布。示例i=0,n=30265,RAND_MAX=2147483647生成值j=0到30263,每次70957次,j=30264=41000。这是一个坏情况,可能不是最坏的情况

使用尺寸j=i+r%n-i;生成几乎一致的结果

示例i=0,n=30265,RAND_MAX=2147483647分别生成值j=0到307、70957次和j=308到30264=70956次。存在补偿这种小偏差的方法。许多这样的帖子

注意:这两种方法都不能修复较差rand中的继承弱点,但是当尝试使用0到rand_MAX的子范围时,方法选择会使情况明显恶化

[编辑]

孔的尺寸为i+rand/rand\u MAX/n-i+1

在大约n>sqrtRAND_MAX且i=0的某个地方,n附近的值将不会被忽略 估价。示例:i=0,n=104643,RAND_MAX=2147483647不生成值104638到104642。

这里有另一个选项:

void shuffle(void *arr, size_t n, size_t size) {
  char *tmp;
  char *array;
  int i, r;
  array = (char *)arr;
  tmp = (char *)malloc(size);
  for (i = n-1; i >= 0; --i) {
    r = rand() % (i+1);
    // swap 
    memcpy(tmp, &array[size*r], size);
    memcpy(&array[size*r], &array[size*i], size);
    memcpy(&array[size*i], tmp, size);
  }
  free(tmp);
}
到目前为止最简单的。注:无需检查n=1

如果确实要使用size\u t,请稍微修改代码:

void shuffle(void *arr, size_t n, size_t size) {
  char *tmp;
  char *array;
  size_t i, r;
  array = (char *)arr;
  tmp = (char *)malloc(size);
  for (i = n-1; i+1 > 0; --i) {
    r = rand() % (i+1);
    // swap 
    memcpy(tmp, &array[size*r], size);
    memcpy(&array[size*r], &array[size*i], size);
    memcpy(&array[size*i], tmp, size);
  }
  free(tmp);
}
感谢评论员指出使用int的问题。很明显,上面的代码可以随机均匀地返回数组的排列,即以1/n!的概率返回数组的每个排列!。这不是一个有趣的练习。

这里有另一个选项:

void shuffle(void *arr, size_t n, size_t size) {
  char *tmp;
  char *array;
  int i, r;
  array = (char *)arr;
  tmp = (char *)malloc(size);
  for (i = n-1; i >= 0; --i) {
    r = rand() % (i+1);
    // swap 
    memcpy(tmp, &array[size*r], size);
    memcpy(&array[size*r], &array[size*i], size);
    memcpy(&array[size*i], tmp, size);
  }
  free(tmp);
}
到目前为止最简单的。注:无需检查n=1

如果确实要使用size\u t,请稍微修改代码:

void shuffle(void *arr, size_t n, size_t size) {
  char *tmp;
  char *array;
  size_t i, r;
  array = (char *)arr;
  tmp = (char *)malloc(size);
  for (i = n-1; i+1 > 0; --i) {
    r = rand() % (i+1);
    // swap 
    memcpy(tmp, &array[size*r], size);
    memcpy(&array[size*r], &array[size*i], size);
    memcpy(&array[size*i], tmp, size);
  }
  free(tmp);
}

感谢评论员指出使用int的问题。很明显,上面的代码可以随机均匀地返回数组的排列,即以1/n!的概率返回数组的每个排列!。这不是一个有趣的练习。

编译器是否告诉您在哪些行上发现了错误?memcpy所在的行。我收到这个警告和错误3次:每个memcpy一次。我更改了代码,因为以前的代码是错误的!可疑尺寸j=i+rand/rand\u MAX/n-i+1;许多整数运算可能无法实现所需的功能。也许相反,i=1;iint\u MAX时,使用int代替size\t会导致问题。size\t通常是无符号的,这意味着i>=0将始终为真。您仍然可以检查i+1>0,这相当于i>=0。使用int代替当i,j需要i>j时,出现问题,通常是无符号的,这意味着i>=0将始终是真的。你仍然可以检查i+>>0,这相当于i>=0。@ De复复器在评论中发表了一个评论,我想在做更多之前给所有者时间考虑。答案不是错误的,只是有一个弱点。复制者发表评论,认为我会给主人时间考虑之前做更多。答案是没有错的,只是有一个弱点。