我有一个指向结构的指针数组。
我尝试使用这个问题的第一个答案来尝试解决这个问题,但我遇到了一个段错误:
尝试此代码后,我尝试使用此功能进行改组:
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);
}
}
}
但是我收到了以下错误:
warning: dereferencing 'void *' pointer [enable by default]
error: invalid use of void expression
我收到了这个警告和错误3次:每个memcpy()一个。
我更改了代码,因为我试图使用这个新代码而不是旧代码。
答案 0 :(得分:4)
你不能取消引用void*
也不能在C中对它进行算术运算,因为它实际上是#34;指向未知类型的对象&#34;,所以编译器不知道该做什么(有些编译器)算术作为一个扩展,好像它是char*
,但不要依赖它。)
因此:
将void*
投射到char*
并改为使用它们。不要忘记为指针算法做自己的缩放
此外,memcpy
应该获得指针,而不是指向的对象,因此请使用+
,而不是[]
。
旁白:请避免内存泄漏,free
您分配的任何内存
最后,请注意random()
可能同时具有微小范围和不良统计属性
最后+ 1:chux answer dissects the range-mapping used in this case,显示它完成得有多糟糕。
How to Debug Small Programs
C99 with Technical corrigenda TC1, TC2, and TC3 included
答案 1 :(得分:3)
除了@Deduplicator好建议外,还需要按j
缩放size
偏移量。
此代码也会更改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);
}
}
澄清size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
在公式中将rand()
替换为值0
到RAND_MAX
将生成样本分布。示例(i = 0,n = 30265,RAND_MAX = 2147483647)生成值j = 0 to 30263
,每次70957次,j = 30264
= 41000.这是一个不好的情况,可能不是最坏的情况。
使用size_t j = i + r%(n-i);
生成几乎统一结果。
示例(i = 0,n = 30265,RAND_MAX = 2147483647)生成值j = 0 to 307
,每次生成70957次,j = 308 to 30264
= 70956次。存在补偿这种小偏差的方法。许多SO帖子。
注意:这些方法中的任何一种都无法修复穷人rand()
中的继承弱点,但在尝试使用0
到{{1的子范围时,方法选择会使事情明显变得更糟}}
[编辑]
孔显示为RAND_MAX
关于size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
和n > sqrt(RAND_MAX)
的某处,将不会生成i=0
附近的值。示例:n
不生成值104638到104642。
答案 2 :(得分:1)
array[i]
- &gt; &array[i]
sizeof(void)
无法保证定义,请使用char
static void shuffle(char *array, size_t n, size_t size)
{
char* 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);
assert(j + size <= ???);
assert(i + size <= ???);
memcpy(aux, &array[j], size);
memcpy(&array[j], &array[i], size);
memcpy(&array[i], aux, size);
}
}
}
答案 3 :(得分:1)
这是另一种选择:
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_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!
返回数组的每个排列。这对于{{3}来说是一个有趣的练习。 }。)