Вопрос относительно функции сравнения, переданной в качестве параметра функции qsort () - PullRequest
1 голос
/ 05 августа 2020

Я специализируюсь на Coursera, и на уроке он объясняет функцию qsort (), которая сортирует заданный массив:

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

где мы должны предоставить qsort () с четырьмя параметрами - массив для сортировки, количество элементов в массиве, размер каждого элемента массива и указатель на функцию (сравнение), которая принимает два const void * s и возвращает int. В уроке говорится, что нам нужно написать функцию compar, чтобы она была совместима с функцией qsort, поэтому, если мы хотим сравнить две строки, функция должна выглядеть так:

int compareStrings(const void * s1vp, const void * s2vp) {
  // first const: s1vp actually points at (const char *)
  // second const: cannot change *s1vp (is a const void *)
  const char * const * s1ptr = s1vp;
  const char * const * s2ptr = s2vp;
  return strcmp(*s1ptr, *s2ptr);
}

void sortStringArray(const char ** array, size_t nelements) {
  qsort(array, nelements, sizeof(const char *), compareStrings);
}

Она говорит: Обратите внимание, что переданные указатели являются указателями на элементы в массиве (то есть, они указывают на поля в массиве), хотя сами эти элементы являются указателями (поскольку они являются строками). Когда мы конвертируем их из void * s, , мы должны позаботиться о том, чтобы преобразовать их в правильный тип - здесь const char * const * - и используйте их должным образом, иначе наша функция каким-либо образом будет нарушена. Например, рассмотрим следующий неработающий код:

// BROKEN DO NOT DO THIS!
int compareStrings(const void * s1vp, const void * s2vp) {
  const char * s1 = s1vp;
  const char * s2 = s2vp;
  return strcmp(s1, s2);
}

Я не могу понять, почему мы не рассмотрели s1vp и s2vp как указатели на указатели? Я имею в виду, поскольку аргументы, переданные в функцию compareStrings, являются адресами указателей, указывающих на строки (адрес указателя), не должны ли мы объявить s1vp и s2vp как int compareStrings(const void ** s1vp, const void ** s2vp), поскольку они получают адреса указателей?

Другими словами, я передаю, например, адрес первого элемента массива строк, который на самом деле является указателем, на s1vp. Итак, теперь s1vp получает адрес указателя, а не переменную, поэтому мы должны объявить его как указатель на указатель, верно? Это дает мне предупреждение, когда я пытаюсь это сделать ...

1 Ответ

2 голосов
/ 05 августа 2020

A void * может указывать на любой тип данных. Тот факт, что рассматриваемый тип данных также является указателем, ничего не меняет. может привести к неопределенному поведению .

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