Segfault на srandom_r
Я в своем уме. Этот тривиальный код дает мне Segfault, что может быть не так??
struct random_data *qq;
qq = calloc(50, sizeof(struct random_data));
srandom_r(time(NULL), qq);
Теперь, если я изменю это так, это работает:
struct random_data qq;
srandom_r(time(NULL), &qq);
Я должен быть полным идиотом, но я не могу понять это. Пожалуйста помоги.
Обновление: calloc возвращает действительный указатель
(uint64_t) 1aa5010
Тем не менее, &qq представляет указатель
(uint64_t) 7fffbb428090
и в этом разница, но неясно, почему srandom_r не выполняется. Я пытаюсь в Linux 2.6.32-44-server #98-Ubuntu
2 ответа
Похоже, что большинство ответов никогда не пытались запустить ваш код. вот очень минималистичная программа, которая действительно показывает вашу проблему:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main() {
int seed = time(NULL);
struct random_data *qq = NULL;
qq = calloc(1, sizeof(struct random_data));
if(qq) {
srandom_r(seed, qq); /* segfault! */
} else {
printf("failed to allocate `qq`\n");
}
return 0;
}
valgrind не показывает ничего, кроме нелегального доступа к памяти:
== 22907 == Неверная запись размером 4 ==22907== в 0x409CE8D: srandom_r (random_r.c:182) ==22907== по 0x80484A1: main (srand_ko.c:10) ==22907== Адрес 0x0: не в стеке, в Malloc'd или (недавно) free'd
теперь, когда смотрю на random_data
Структура, вы найдете, что он содержит указатель на буфер состояния:
struct random_data
{
int32_t *fptr; /* Front pointer. */
int32_t *rptr; /* Rear pointer. */
int32_t *state; /* Array of state values. */
int rand_type; /* Type of random number generator. */
int rand_deg; /* Degree of random number generator. */
int rand_sep; /* Distance between front and rear. */
int32_t *end_ptr; /* Pointer behind state table. */
};
очевидно, что все эти указатели будут NULL, если вы выделите с calloc()
, а также srandom_r
не очень нравится Вы можете помочь ему вручную распределить массив значений состояния и назначить его random_data
использовать структуру initstate_r
, поскольку initstate_r
уже занимает seed
Вам не нужно звонить srandom_r
больше (но вы можете, если хотите):
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define STATESIZE 64
int main() {
int seed = time(NULL);
char*buf = (char*)calloc(STATESIZE, sizeof(char));
struct random_data *qq = NULL;
qq = calloc(1, sizeof(struct random_data));
initstate_r(seed, buf, STATESIZE, qq);
/* generate some random numbers */
/* ... */
srandom_r(seed, qq);
/* generate the same random numbers again */
/* ... */
/* cleanup */
free(buf);
free(qq);
return 0;
}
'random_data' не содержит памяти, которая хранит состояние генератора случайных чисел - она хранит состояние, в котором находится состояние....
"Правильный способ" использования random_r:
struct random_data rstate;
char random_bin[256];
initstate_r(MY_SEED,random_bin,256,&rstate);
Теперь вы можете вызывать srandom_r и random_r.
Нет необходимости выполнять malloc или вызывать что-либо, и это замедлит вас, так как вы будете получать промахи кеша каждый раз, когда вы идете для генерации случайного числа.
Вы можете не добавить тест calloc()
удалось, как прохождение NULL
наиболее вероятно провоцирует нарушение сегментации.
#include <stdlib.h>
...
struct random_data * qq = calloc(50, sizeof(*qq));
if (NULL == qq)
perror("malloc() failed");
else
srandom_r(time(NULL), qq);