Понимание функции тасования - PullRequest
0 голосов
/ 30 мая 2019

Я нашел в этой теме следующую функцию для перетасовки любых типов данных:

#define NELEMS(x)  (sizeof(x) / sizeof(x[0]))

/* arrange the N elements of ARRAY in random order.
 * Only effective if N is much smaller than RAND_MAX;
 * if this may not be the case, use a better random
 * number generator. */
static void shuffle(void *array, size_t n, size_t size) {
    char tmp[size];
    char *arr = array;
    size_t stride = size * sizeof(char);

    if (n > 1) {
        size_t i;
        for (i = 0; i < n - 1; ++i) {
            size_t rnd = (size_t) rand();
            size_t j = i + rnd / (RAND_MAX / (n - i) + 1);

            memcpy(tmp, arr + j * stride, size);
            memcpy(arr + j * stride, arr + i * stride, size);
            memcpy(arr + i * stride, tmp, size);
        }
    }
}

Я тестировал, и, кажется, он работает нормально, но мне трудно понять, как и почему это работает.

  1. Как и почему он не может поменять элемент массива непосредственно на array
  2. Почему можно присвоить массив символу *: char *arr = array;
  3. Смещение i * stride или j * stride в функциях memcpy больше, чем общий размер массива (sizeof(array)). Почему здесь работает арифметика указателей?

Ответы [ 2 ]

1 голос
/ 30 мая 2019

Для лучшего понимания я перетасую порядок ответов:

2 - array - указатель типа void. В C указатели могут быть назначены указателям типа void* и от них. Любой указатель на объект может быть преобразован в тип void* без потери информации. Если результат преобразуется обратно в исходный тип указателя, исходный указатель восстанавливается.

1 - Он не работает одинаково для отдельных элементов, у вас нет универсального типа, который может быть назначен любому типу. Таким образом, код переключает содержимое указанной памяти.

3 - n - количество элементов в массиве, а size - размер одного элемента в массиве. stride = size * sizeof(char); означает, что stride равно size, поскольку sizeof(char) равно 1. Размер массива sizeof(array) равен n * size - количество элементов в массиве, умноженное на размер элемента. Поскольку i и j меньше n, i * stride и j * stride никогда не будет больше памяти, используемой массивом. Хотя мне интересно, почему использование этого stride, насколько я знаю, sizeof(char) всегда равно 1.

0 голосов
/ 30 мая 2019
  1. array относится к типу void*.Это просто указатель без интерпретации, поэтому мы не знаем, на какой тип данных он указывает.Количество элементов дано в n, а размер каждого в size.Это сделано таким образом, что функцию можно использовать с массивами любого типа.
  2. char *arr = array; интерпретирует указатель void как указывающий на последовательность байтов.
  3. sizeof(array) даетразмер указателя , а не размер фактического массива.Фактический размер в байтах составляет i * size.

Алгоритм случайного воспроизведения выглядит как случайный случай Фишера-Йейтса .

. Также отмечу, что * sizeof(char) бессмысленно, поскольку sizeof(char) равно 1 по определению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...