Приведение const void * к const char * в C

Итак, у меня есть функция C, которая выглядит следующим образом:

int cmp (const void *a, const void* b)
 return rot13cmp( (const char*)a, (const char*)b );
}

и rot13cmp — еще одна функция, которая принимает два параметра типа const char *.

Я передаю эту функцию в параметр сравнения для функции C qsort, но это не кажется работать.

Однако, если вместо этого я приведу переменные const void *, выполнив

return rot13cmp ( *(const char **)a, *(const char **)b ); 

после этого функция начинает работать. Я посмотрел это на SO, но каждый источник сказал, что первый метод приведения должен работать, поэтому я хотел знать, почему у меня работал только второй?

Изменить: вот соответствующий код, который у меня есть,

int cmp (const void *a, const void *b) {
 return rot13cmp( (const char *)a, (const char *)b );
}

int rot13cmp (const char *a, const char *b) {
 while (*a == *b && *a != '\n') {
  a++;
  b++;
 }

 if (*a == *b) { return 0; }
 else if (*a == '\n') { return 1; }
 else if (*b == '\n') { return 1; }
 else { return rot13(*a) - rot13(*b);
}

а rot13 возвращает int для ASCII-кода буквы, повернутой на 13 букв в алфавите.

Я вызвал qsort, выполнив

qsort(words, word_count, sizeof(char*), cmp);

где слова — это массив char**, а word_count — целое число. cmp тоже просто


person Chang Liu    schedule 08.02.2015    source источник
comment
Мне кажется, SSCCE здесь действительно поможет.   -  person Baum mit Augen    schedule 08.02.2015
comment
Для этого должна быть другая причина.   -  person Iharob Al Asimi    schedule 08.02.2015
comment
Итак, как вы позвонили qsort()?   -  person timrau    schedule 08.02.2015
comment
Мы ничего не сможем узнать об этом, если вы не покажете нам, какой тип изначально у ваших a и b. Из того, что вы описываете, я бы предположил, что это указатели на указатели, но без информации это чистое предположение.   -  person Jens Gustedt    schedule 08.02.2015
comment
Извините, я добавил соответствующий код выше.   -  person Chang Liu    schedule 08.02.2015


Ответы (1)


qsort() вызывает функцию сравнения с указателями на элементы массива, которые необходимо сравнить.

Если ваш массив содержит const char*, это означает, что функция сравнения вызывается с указателями на эти указатели, и вы должны выполнить приведение и разыменование соответственно.

С (const char*)a вы интерпретируете параметр так, как если бы он был указателем на const char. Но это не так. На самом деле это указатель на const char* во входном массиве.

Вот почему (const char**)a является правильным приведением, он интерпретирует параметр как указатель на const char*. Чтобы выполнить сравнение строк, вам понадобится const char*, к которому вы обращаетесь, разыменовывая приведенное значение с помощью *.

Вы можете представить это как сначала исправление типа (путем приведения), а затем доступ к указываемому значению (путем разыменования).

Разница между двумя попытками заключается в том, что во втором случае выполняется дополнительное разыменование. Это важно, поскольку qsort() не передает const char* напрямую, а передает указатель на него. Таким образом, мы должны посмотреть на указанное значение, чтобы найти то, что мы ищем. Приводя напрямую к const char*, мы просто утверждаем, что переменная будет содержать такой указатель, что ничем хорошим не закончится, потому что это не так.

person sth    schedule 08.02.2015
comment
Как вы думаете, вы могли бы уточнить это? Я думал, что и (char*), и *(char **) являются допустимыми способами приведения/разыменования, но мне было интересно, почему последний работает. - person Chang Liu; 08.02.2015
comment
*(char **) разыменовывает указатель, который вы передаете, а (char *) - это просто приведение. - person Jake; 08.02.2015
comment
@ChangLiu: я добавил больше деталей. - person sth; 08.02.2015