2015-12-19 2 views
3

Я изучаю C от «C на K & R». Я проходил через раздел «Указатели функций». Был пример сортировки массива строк с помощью указателей на функции и указателей void (в частности, на стр. 100). У меня есть ясное понимание указателей на функции и указателей void.C указатели функции

Пример, приведенный здесь называет

qsort((void**) lineptr, 0, nlines-1,(int (*)(void*,void*))(numeric ? numcmp : strcmp)); 

И seemlessly использует пустое PTR, вроде как ниже для сравнения и обмена.

Я понимаю, что он принимает массив указателей, и каждый элемент сам по себе является указателем на пустоту. Как можно сравнивать, поменяйте пустоту ptr на другую.

void sort(void *v[],int i,int j) 
{ 
    id *temp; 
    temp = v[i]; 
    v[i] = v[j]; 
    v[j] = temp; 
} 

Может кто-нибудь объяснить концепцию этого.

+5

При перестановке двух указателей, не изменять данные, которые он указывает в любом случае. – wimh

+3

Конечно, вы не можете разыменовать void *, но здесь вы просто изменяете то, на что указывают указатели. – ameyCU

+3

Действительно ли ваш код работает? –

ответ

1

Помните, что указатели - это просто переменные, которые хранят адрес памяти. Если между типами нет конфликта, я не понимаю, почему это невозможно! Единственное различие между void PTR и другим, что вы должны обратить внимание только во время разыменования (вам нужен бросок, чтобы закончить его) Например:

void *ptr; 
int m, n; 
ptr = &n; 
m = *((int *) ptr); 

Во всяком случае, не обращая внимания именно это, вы можете работать с void указателя обычно .. Вы можете, как ваш код показывает, например, поменять их так же, как они были int или других типов переменных

2

Как можно сравнивать, замещать void ptr с другой?

  • Для сравнения: сравнение void ptr друг с другом не имеет смысла, так как их значения адреса.

  • Swap: указатель представляет собой переменную, содержащую адрес. Изменяя значение указателя, вы меняете адрес, на который он указывает. Сами данные здесь даже не рассматриваются.


Примечание: недействительными указатели не интерпретирует данные, которые они указывают на. Вот почему вам требуется явное преобразование типов, когда вы их разыскиваете, так что существует соответствие между данными, на которые они указывают, и переменной, которой эти данные назначаются.

+0

Пожалуйста, объясните« * бессмысленный * ». –

+0

в контексте вопроса, если вы сравните значение void ptr, какую значащую информацию он вам даст? – Ziezi

+0

Независимо от того, указывают оба указателя на один и тот же адрес? Вы имеете в виду, что сортировка по адресу не имеет никакого значения, потому что заказ будет немного произвольным, не так ли? –

0

Указатель функции требуется qsort() имеет следующий вид

int (*compar)(const void *, const void *); 

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

Внутри Comparision несильно, вы ДОЛЖНЫ «отливать» в void * poitners для того, чтобы иметь возможность разыменования них. Поскольку указатель void * не может быть разыменован.

Swaping pointers - это правильный способ сортировки массива poitners, так же, как swaping integers будет способом сортировки массива целых чисел. Другим способом, с массивом строк, например, было бы скопировать строку во временный буфер и выполнить обмен в плане копирования данных, и я думаю, что нет необходимости объяснять, почему это плохо.


Когда я говорю отливать я не имею в виду, что вам нужно «бросить », просто преобразовать в соответствующий тип poitner. Например:

int compare_integers(const void *const x, const void *const y) 
{ 
    int *X; 
    int *Y; 

    X = x; 
    Y = y; 

    return (*X - *Y); 
} 

, хотя это, конечно, можно написать return (*((int *) x) - *((int *) y)).

0

В таких ситуациях часто полезно использовать typedef, чтобы получить лучшее понимание. Для целей иллюстрации, вы могли бы сделать

typedef void* address; //to emphasize that a variable of type void* stores an address 

Теперь ваша функция подкачки выглядит менее сложной,

void swap(address v[],int i,int j) //takes an array of addresses v 
{ 
    address temp; 
    temp = v[i]; 
    v[i] = v[j]; 
    v[j] = temp; 
} 

void *, однако, не содержит никакой информации о типе объекта, на которую он указывает. Поэтому, прежде чем разыменования его, вы должны привести его к правильному типу, что и strcmp и numcmp делать, например,

int strcmp(address a1, address a2) { //assumes a1 and a2 store addresses of strings 
    char *s1 = a1; 
    char *s2 = a2; 
    //s1 and s2 can be dereferenced and the strings they point to can be compared 
} 
+0

@Все: Большое спасибо. Я пропустил, что это адрес, а не данные, которые меняются местами.Не имел доступа в Интернет, отсюда и задержка. – user13252

Смежные вопросы