2009-02-24 1 views
0

У меня есть один буфер и несколько указателей на него. Я хочу сортировать указатели на основе байтов в буфере, на который они указывают.memcmp sort

qsort() и stl :: sort() могут быть предоставлены пользовательскими функциями сравнения. Например, если буфер был нулем я мог бы использовать STRCMP:

int my_strcmp(const void* a,const void* b) { 
    const char* const one = *(const char**)a, 
    const two = *(const char**)b; 
    return ::strcmp(one,two); 
} 

однако, если буфер не нуль, я должен использовать memcmp(), который требует параметра длины.

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

ответ

3

Есть ли причина, по которой вы не можете обнулить нулевые буферы?

Если нет, так как вы используете C++ вы можете написать свой собственный функциональный объект:

struct MyStrCmp { 
    MyStrCmp (int n): length(n) { } 
    inline bool operator< (char *lhs, char *rhs) { 
     return ::strcmp (lhs, rhs, length); 
    } 
    int length; 
}; 
// ... 
std::sort (myList.begin(), myList.end(), MyStrCmp (STR_LENGTH)); 
+0

избили меня на 30 секунд :) +1 –

+0

Примечание: std :: sort принимает итераторы ** не ** контейнеры. –

+0

ха-ха! - По крайней мере, вы получили правильный вызов std :: sort .. забыли об итераторах;) – eduffy

2

Можете ли вы уложить указатель + длины в структуру и передать указатель этой структуры как void *?

+0

Как это работает с 'qsort' или' std :: sort'? – jfs

+0

Вы создаете новый массив этих структур и сортируете его, используя пользовательскую функцию сравнения. Если вы должны получить доступ к исходному массиву (вместо базовых данных), вы можете поддерживать указатели или индексы от нового массива до старого, который вы можете использовать после сортировки. –

7

С станд :: сортировать, вы можете использовать Functor так:

struct CompString { 
    CompString(int len) : m_Len(len) {} 
    bool operator<(const char *a, const char *b) const { 
     return std::memcmp(a, b, m_Len); 
    } 
private: 
    int m_Len; 
}; 

Тогда вы можете сделать это:

std::sort(begin(), end(), CompString(4)); // all strings are 4 chars long 

EDIT: от комментариев предложений (I думаю, обе строки в общем буфере):

struct CompString { 
    CompString (const unsigned char* e) : end(e) {} 
    bool operator()(const unsigned char *a, const unsigned char *b) const { 
     return std::memcmp(a, b, std::min(end - a, end - b)) < 0; 
    } 
private: 
    const unsigned char* const end; 
}; 
+0

struct CompString { CompString (const unsigned char * e): end (e) {} \t \t bool operator() (const unsigned char * a, const unsigned char * b) const { \t return (-1 == :: memcmp (a, b, __min (end-a, end-b))); \t \t} \t частное: \t \t Const символ без знака * Const конец; \t}; – Will

+0

Этот подход получил меня начал .Я только что опубликовал некоторые незначительные исправления. Pls обновляет код. – Will

+0

Я не мог заставить оператора <скомпилировать, но с перегрузкой функтора() он работал в обаянии! – Will

0

Вы можете функторы (дать длину конструктору функтор в) или Boost.Lambda (используйте длину в месте).

0

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

  • У вас есть один буфер
  • У вас есть массив указателей некоторого рода, которые были обработаны в некотором роде, так что некоторые или все его содержимое указывают в буфер

То есть код, эквивалентный:

char *buf = (char*)malloc(sizeof(char)*bufsize); 
for (int i=0; i<bufsize; ++i){ 
    buf[i] = some_cleverly_chosen_value(i); 
} 

char *ary[arraysize] = {0}; 
for(int i=0; i<arraysize; ++i){ 
    ary[i] = buf + some_clever_function(i); 
} 

/* ...do the sort here */ 

Теперь, если вы контролировать выделение буфера, вы могли бы заменить

char *buf = (char*)malloc(sizeof(char)*(bufsize+1)); 
buf[bufsize]='\0'; 

и в дальнейшем использовать strcmp. Это возможно, даже если вы не контролируете заполнение буфера.

Если вам придется жить с буфером передал вам кто-то еще вы можете

  1. Используйте некоторые глобальные хранения (которые вы просили, чтобы избежать и хорошего мышления).
  2. Передайте функцию сортировки что-то более сложное, чем необработанный указатель (адрес структуры или класса, который поддерживает дополнительные данные).Для этого вам необходимо управлять дефиницией ary в приведенном выше коде.
  3. Используйте функцию сортировки, которая поддерживает дополнительный вход. Либо sort_r, как предложено Adam, или домашним прокатом (которое я рекомендую в качестве упражнения для ученика и не рекомендую в реальной жизни). В любом случае дополнительные данные, вероятно, являются указателями на конец буфера.
+0

Какие?!? Заявление о проблеме _is_ неясно. Один байт? Два байта? До конца буфера? Это значение указателя? Все это правильное понимание того, что написал Уилл. – dmckee

+0

Второе предложение: «Я хочу сортировать указатели на основе байтов в буфере, на который они указывают». OP спрашивает, как передать размер буфера в функцию сравнения процедуры сортировки. Ваш ответ не дает ничего полезного в этом отношении. –

+0

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

-2

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

(BTW, я склоняюсь к сортировки слиянием сам. Это стабильный и хорошо себя вели.)

+0

Да, но как memcmp() знает, насколько большой буфер? Это проблема. –

+0

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

+0

... и, конечно же, qsort_r также действителен, если он у вас есть. –

4

С помощью функции C qsort(), нет, нет никакого способа, чтобы передать длину к вашей функции сравнения без использования глобальной переменная, что означает, что она не может быть выполнена поточно-безопасным способом. Некоторые системы имеют qsort_r() функцию (г обозначает реентерабельные), который позволяет передавать дополнительный контекст параметр, который затем пропускается на вашу функцию сравнения:

int my_comparison_func(void *context, const void *a, const void *b) 
{ 
    return memcmp(*(const void **)a, *(const void **)b, (size_t)context); 
} 

qsort_r(data, n, sizeof(void*), (void*)number_of_bytes_to_compare, &my_comparison_func); 
+0

Системы BSD, включая MacOS X, включают qsort_r(); на других платформах этого нет. –

1

Вы можете использовать хак, как:

int buffcmp(const void *b1, const void *b2) 
{ 
    static int bsize=-1; 
    if(b2==NULL) {bsize=*(int*)(b1); return 0;} 
    return memcmp(b1, b2, idsize); 
} 

который вы бы сначала позвонить в buffcmp(&bsize, NULL), а затем передать его в качестве функции сравнения для qsort.

Возможно, вы можете сделать сравнение более естественно в случае buffcmp(NULL, NULL) и т. Д., Добавив еще if операторов.