Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Своя версия strcmp(), кто предложит лучший вариант?

29K
07 июня 2009 года
EXAngel
29 / / 08.07.2008
[SIZE="2"]Задача:[/SIZE]
Цитата:
10.6. Создайте свою версию библиотечной функции strcmp(sl, s2), которая сравнивает две строки и возвращает -1, если s1 идет первой по алфавиту, 0, если в s1 и s2 одинаковые значения, и 1, если s2 идет первой по алфавиту. Назовите вашу функцию compstr(). Она должна принимать в качестве аргументов два указателя на строки char*, сравнивать эти строки посимвольно и возвращать число int. Напишите функцию main() для проверки работы вашей функции с разными строками. Используйте указатели во всех возможных ситуациях.



[SIZE="2"]Вот мой вариант:[/SIZE]

Код:
// linklist.cpp
// linked list
#include <iostream>
using namespace std;
//--------------------------------------------------------------
int main()
   {
    int compstr(char*,char*);

    char one[] = "abc";
    char two[] = "abc";

    cout << compstr(one,two) << endl;

   return 0;
   }
//--------------------------------------------------------------
int compstr (char* a, char* b)
{
    int current=0;     
    int previous=0;

    do
    {
        char one = *(a++);
        char two = *(b++);
        previous=current;

        if (&#111;&#110;e==two)
        {
            current=0;
        }
        else
        {
            if (one<two)
            {
                current=-1;
            }
            else
            {
                current=+1;
            }
        }
        loop++;
    }while(!(current!=0 && previous==0 || (*a=='\0')||(*b=='\0')) );

    return current;
}
//--------------------------------------------------------------

[SIZE="2"]Автор книги просил как можно чаще использовать указатели, но честно говоря я еле выработал алгоритм (методом проб и ошибок).
Я думаю можно оптимизировать функцию compstr()...[/SIZE]
87
08 июня 2009 года
Kogrom
2.7K / / 02.02.2008
Тему в раздел Студенты.
Наверное, требовалось примерно такое решение (особо не тестировал):
 
Код:
int compstr (const char* a, const char* b)
{
    while(*a && *b && (*a == *b))
    {
        a++; b++;
    }
    if (*a > *b) return 1;
    if (*a < *b) return -1;
    return 0;
}
29K
11 июня 2009 года
Ander Skirnir
109 / / 08.06.2009
Вот вам мой вариант:

 
Код:
int compstr (const char* a, const char* b)
{
    return (*a && *b && (*a == *b)) ? ((*(a+1) || *(b+1)) ? (compstr(a+1, b+1)) : (0)) : ((*a > *b) ? (1) : (-1));
}
307
13 июня 2009 года
Artem_3A
863 / / 11.04.2008
 
Код:
bool mystrcmp(const char* str1, const char* str2)
{
    for(int i=0; str1==str2!=0; i++)
        if(str1==0) return true;

    return false;
}


если через инт возвращать результат то

 
Код:
bool mystrcmp(const char* str1, const char* str2)
{
    for(int i=0; *(str1+i)==*(str2+i)!=0; i++)
        if(*(str1+i)==0) return 0;

    return *(str1+i)-*(str2+i);
}
29K
13 июня 2009 года
Ander Skirnir
109 / / 08.06.2009
Artem_3A, у Вас в условии цикла есть проверка
 
Код:
str1==str2!=0


То есть тело цикла будет выполено лишь в том случае, если i-й символ обеих строк совпадает и не равен 0. Затем Вы в теле цикла проверяете
 
Код:
if(str1==0)

что никогда не будет истинно так как запрещено условием цикла.

Таким образом Ваша функция возвращает всегда 0. Кстати говоря, тип возврата у неё bool и она не может возвращать три разных значения (для a > b, a = b, a < b) - а ведь именно такая поставлена задача.

А вот вторая функция будет работать, если поменять тип возврата на int, но код в теле цикла опять-таки не несёт смысла и может быть безболезненно удалён. А возвращать она будет не -1, 0, 1 (хотя и эти может в частных случаях), а расстояние в таблице ascii между соответствующими первыми несовпавшими либо нулевыми символами строк str1 и str2. Т.е. mystrcmp < 0 при a < b, mystrcmp = 0 при a = b и mystrcmp > 0 при a > b.
87
13 июня 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ander Skirnir
 
Код:
int compstr (const char* a, const char* b)
{
    return (*a && *b && (*a == *b)) ? ((*(a+1) || *(b+1)) ? (compstr(a+1, b+1)) : (0)) : ((*a > *b) ? (1) : (-1));
}



Прикольно, но не очень читаемо. И, вроде бы, можно оптимизировать:

 
Код:
int compstr (const char* a, const char* b)
{
    return (*a == *b) ? ((*a || *b) ? compstr(a+1, b+1) : 0) : ((*a > *b) ? 1 : -1);
}
29K
14 июня 2009 года
Ander Skirnir
109 / / 08.06.2009
Kogrom, Вы правы и спасибо что поддержали эстафету :)

Теперь моя очередь (:

 
Код:
int compstr (const char* a, const char* b)
{
    return (*a == *b && *b) ? compstr(a+1, b+1) : 1 - (*a == *b) - 2 * (*a < *b);
}
307
14 июня 2009 года
Artem_3A
863 / / 11.04.2008
Цитата: Ander Skirnir
Artem_3A, у Вас в условии цикла есть проверка
 
Код:
str1==str2!=0


То есть тело цикла будет выполено лишь в том случае, если i-й символ обеих строк совпадает и не равен 0. Затем Вы в теле цикла проверяете
 
Код:
if(str1==0)

что никогда не будет истинно так как запрещено условием цикла.

Таким образом Ваша функция возвращает всегда 0. Кстати говоря, тип возврата у неё bool и она не может возвращать три разных значения (для a > b, a = b, a < b) - а ведь именно такая поставлена задача.

А вот вторая функция будет работать, если поменять тип возврата на int, но код в теле цикла опять-таки не несёт смысла и может быть безболезненно удалён. А возвращать она будет не -1, 0, 1 (хотя и эти может в частных случаях), а расстояние в таблице ascii между соответствующими первыми несовпавшими либо нулевыми символами строк str1 и str2. Т.е. mystrcmp < 0 при a < b, mystrcmp = 0 при a = b и mystrcmp > 0 при a > b.



Друг, заканчивай курить бамбук и переходи на мздн, полезней будет!=)
Я даже не буду тебе ни чего объяснять!=)

вот код

Код:
#include <string>
#include <iostream>


using std::wstring;
using std::wcin;
using std::wcout;

bool mystrcmp(const wstring& str1,
              const wstring& str2)
{
    for(int i(0); str1==str2!=0; i++)
        if(str1==0) return true;
   
    return false;
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "Russian");
    wstring first;
    wstring next;
    std::wcout << _T("введите первую строчку для сравнения: ");
    std::wcin >> first;
    std::wcout << _T("введите вторую строчку для сравнения: ");
    std::wcin >> next;
    std::wcout << _T("результат сравнения: ");
   
    if(mystrcmp(first,next))
    std::wcout << _T("строки совпадают")<< std::endl;
    else
    std::wcout << _T("строки не совпадают")<< std::endl;
    system("PAUSE");
    return EXIT_SUCCESS;
}


убидись сам, надеюсь студия 2005я есть, а потом сам скажешь где ты был не прав!=)
не много подправив код для инта можешь убедиться, что и второй вариант работает без изменений!=)
ЗЫ: вообще то strcmp возвращает не 0,-1,1, а значение 0, если строки равны, и больше либо меньше нуля, если они не равны.=) читай Савича или МЗДН!=)
ЗЫЗЫ: раз уж мы напредлагали столько разных функции strcmp предлагаю провести мини соревнование, чья выполниться быстрее(к слову об оптимизовать)!=)
9.3K
14 июня 2009 года
iridum
175 / / 26.08.2007
Цитата: Artem_3A

{
for(int i(0); str1==str2!=0; i++)
if(str1==0) return true;

return false;
}
...
предлагаю провести мини соревнование, чья выполниться быстрее(к слову об оптимизовать)!=)



А ++i быстрее i++ ;) надо ж приблизить к совершенству, оптимизаторы несовершенны, могут не схавать

307
14 июня 2009 года
Artem_3A
863 / / 11.04.2008
Цитата: iridum
А ++i быстрее i++ ;) надо ж приблизить к совершенству, оптимизаторы несовершенны, могут не схавать



откуда такие сведения? если честно ни когда не слышал, не подскажешь ссылочку где можно почитать, очень интересно!?=)

9.3K
14 июня 2009 года
iridum
175 / / 26.08.2007
http://forum.ixbt.com/topic.cgi?id=26:37762
там эти ребята еще об оптимизаторах говорят, но не уверен что всегда вот будет оно оптимизироваться во всех компиляторах. А вообще еще в какойто книжке было написано, да и не особо оно то важно вообщем-то.
307
14 июня 2009 года
Artem_3A
863 / / 11.04.2008
Цитата: iridum
http://forum.ixbt.com/topic.cgi?id=26:37762
там эти ребята еще об оптимизаторах говорят, но не уверен что всегда вот будет оно оптимизироваться во всех компиляторах. А вообще еще в какойто книжке было написано, да и не особо оно то важно вообщем-то.



хм, логично, фишка!=) аналогично

 
Код:
int i(0);

быстрее чем
 
Код:
int i = 0;


хотя опять же для стандартных типо это дело оптимизировано как бы!=)
29K
14 июня 2009 года
Ander Skirnir
109 / / 08.06.2009
Artem_3A,
Вы были правы насчёт моего замечания по поводу "проверки, которая никогда не будет выполняться". Я действительно ошибся и связано это с тем, что в любом коде пытаюсь увидеть смысл. Таким образом, проверка
"str1==str2!=0", ничем не отличающаяся от "str1==str2" совершенно сбила меня с толку :)

Во всех реализациях strcmp с которыми я сталкивался, она всегда возвращала -1, 0 или 1.

Если такого требования нету, тогда Ваша вторая функция действительно будет работать правильно.

Ну а моя функция без этого требования будет выглядеть так:

 
Код:
int compstr (const char* a, const char* b)
{
    return (*a == *b && *b) ? compstr(a+1, b+1) : (*a - *b);
}
307
14 июня 2009 года
Artem_3A
863 / / 11.04.2008
Цитата: Ander Skirnir

Во всех реализациях strcmp с которыми я сталкивался, она всегда возвращала -1, 0 или 1.



ну не знаю, стркмп из стандартной библиотеки работает именно так!=)

29K
14 июня 2009 года
Ander Skirnir
109 / / 08.06.2009
Я старался сделать свой вариант красивым и с намёком на функциональный стиль, но в практическом применении Ваш вариант конечно же гораздо лучше, потому что у меня из-за рекурсии с ростом длины строк капитально пухнёт стэк вызовов.

Но в Вашем варианте присутствует переменная i и операции с ней, а можно было обойтись только входящими данными. Например так:
 
Код:
int compstr (const char* a, const char* b)
{
    while (*a++ == *b++ && *b);
    return *(a-1) - *(b-1);
}
87
14 июня 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Artem_3A
Друг, заканчивай курить бамбук
...
ЗЫ: вообще то strcmp возвращает не 0,-1,1, а значение 0, если строки равны, и больше либо меньше нуля, если они не равны.=) читай Савича или МЗДН!=)


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

Читать надо не МСДН - он тут совсем не указ. Читать надо стандарт по Си:

Цитата:
7.21.4.2 The strcmp function
Synopsis
1 #include <string.h>
int strcmp(const char *s1, const char *s2);
Description
2 The strcmp function compares the string pointed to by s1 to the string pointed to by s2.

Returns
3 The strcmp function returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string pointed to by s2.


То есть функция должна возвратить либо ноль, либо целочисленное число больше нуля, либо целочисленное число меньше нуля.

307
15 июня 2009 года
Artem_3A
863 / / 11.04.2008
Цитата: Kogrom
Ну так кто должен букварь читать после этого? Уж наверно тот, кто неправильно реализовал. В любом случае, грубить не надо.

Читать надо не МСДН - он тут совсем не указ. Читать надо стандарт по Си:


То есть функция должна возвратить либо ноль, либо целочисленное число больше нуля, либо целочисленное число меньше нуля.



эм, в смысле не правильно реализовал и читать букварь?0_о и я как раз и написал, что функция возвращает 0, и числа больше либо меньше нуля.

мой источник
[QUOTE=MSDN2005]
...
Return Value
The return value for each of these functions indicates the lexicographic relation of string1 to string2.

Value Relationship of string1 to string2
< 0
string1 less than string2

0
string1 identical to string2

> 0
string1 greater than string2

...
[/QUOTE]

Ander Skirnir,
[QUOTE=Ander Skirnir]
Я старался сделать свой вариант красивым и с намёком на функциональный стиль, но в практическом применении Ваш вариант конечно же гораздо лучше, потому что у меня из-за рекурсии с ростом длины строк капитально пухнёт стэк вызовов.

Но в Вашем варианте присутствует переменная i и операции с ней, а можно было обойтись только входящими данными. Например так:
Код:
int compstr (const char* a, const char* b)
{
while (*a++ == *b++ && *b);
return *(a-1) - *(b-1);
}
[/QUOTE]

да, так действительно будет быстрее, но смотри, ты передаешь const char* a, а потом делаешь с указателем следуюшую операцию, a = a+1; или a++, в конце выполнения функции а будет указыать в \0. как ни странно, в студии код выполнился корректно, то есть по завершении а как и положено указывал на первую букву строки, так как указатель был просто скопирован, но уверен ли ты, что такое же поведение будет наблюдаться всегда? если честно, я не уверен, и к сожалению у меня нет стандарта под рукой дабы посмотреть!=) будем надеяьтся Kogrom нас выручит в этом плане!=)

29K
15 июня 2009 года
Ander Skirnir
109 / / 08.06.2009
Хорошо, что Вы подняли этот вопрос, потому что так тема станет более информативной (:

const char* str - указатель на константу: запрещает изменять значение обьекта, на который указывает
char *const str - константный указатель: запрещает изменять себя
const char *const str - константный указатель на константу: запрещает изменять себя и значение обьекта на который указывает

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

PS: я за безопасное сравнение строк, а Вы? :)
307
15 июня 2009 года
Artem_3A
863 / / 11.04.2008
Цитата: Ander Skirnir
Хорошо, что Вы подняли этот вопрос, потому что так тема станет более информативной (:

const char* str - указатель на константу: запрещает изменять значение обьекта, на который указывает
char *const str - константный указатель: запрещает изменять себя
const char *const str - константный указатель на константу: запрещает изменять себя и значение обьекта на который указывает

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

PS: я за безопасное сравнение строк, а Вы? :)



ну конечно же я за безопасное сравнение строк!=) было бы интересно после операции сравнения получить два нулевых указателя!=) думаю автор темы получил уже достаточно сведений и целую библиотеку функций сравнения строк!=))))))))))))

87
15 июня 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ander Skirnir
Я старался сделать свой вариант красивым и с намёком на функциональный стиль


Ишь. Сейчас еще выяснится, что Ander Skirnir на Хаскеле программирует :)

С Artem_3A спорить бесполезно - он знает МСДН, Савича и много других страшных слов...

307
15 июня 2009 года
Artem_3A
863 / / 11.04.2008
Цитата: Kogrom

С Artem_3A спорить бесполезно - он знает МСДН, Савича и много других страшных слов...



конечно, стараюсь вам соответствовать!=)

29K
15 июня 2009 года
Ander Skirnir
109 / / 08.06.2009
Цитата: Kogrom
Ишь. Сейчас еще выяснится, что Ander Skirnir на Хаскеле программирует :)



Пока что не очень, но после сессии планируется усиленное lisp, ml и что-нибудь эзотерическое (вроде brainfuck :)

Первым делом напишу на них strcmp и выложу сюда :)

29K
25 июня 2009 года
Ander Skirnir
109 / / 08.06.2009
strcmp.lisp :
 
Код:
(defun strcmp (str1 str2)
    (let ((pos (mismatch str1 str2)))
        (if (null pos) 0
            (- (if (< pos (length str1)) (char-int (char str1 pos)) 0)
               (if (< pos (length str2)) (char-int (char str2 pos)) 0)))))


Пока что лучше не выходит, но лето - впереди :)
297
03 июля 2009 года
koodeer
1.2K / / 02.05.2009
Очень полезная тема получилась. Решил и я принять в ней участие, внести свою лепту.

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

int compstr(const char*a, const char*b)
{
while(*a++ == *b++ && *b);
return *(a-1) - *(b-1);
}

Увлёкшись минимизацией кода и его быстродействием, были допущены ошибки работы с указателями.

Судите сами: если *a будет указывать, скажем, на строку "abc", а *b на строку "ab", то функция выдаст 0, вместо ожидаемого положительного значения. Происходит это потому, что сначала происходит инкремент указателей, а уж затем сравнение указателя b с нулём.

Предлагаю слегка модифицировать функцию:

int compstr(const char*a, const char*b)
{
while(*a == *b && *b)
a++, b++;
return *a - *b;
}

В этом варианте сначала указатель b сравнивается с нулём, а уж затем оба указателя инкрементируются. Таким образом не только избавляемся от указанной ошибки, но и чуть-чуть повышаем быстродействие, избавившись от двух последних инкрементов и двух вычитаний единицы в операторе return. Количество сравнений остаётся тем же самым.
29K
03 июля 2009 года
Ander Skirnir
109 / / 08.06.2009
koodeer, Вы правы, спасибо. Вот еще такой вариант, который хуже ващего по быстродействию, но демонстрирует удобство сишных логических операций (которые возвращают не true/false, а целое):

 
Код:
int compstr (const char* a, const char* b)
{
    while (*a++ == *b++ && *b);
    return *(a - (a == 0)) - *(b--);
}
297
29 июля 2009 года
koodeer
1.2K / / 02.05.2009
Цитата: Ander Skirnir
демонстрирует удобство сишных логических операций



К слову об удобстве Си. Этот язык поистине позволяет вольности, недоступные во многих других языках. Вот пример с оператором for:

 
Код:
int compstr(const char*a, const char*b)
{
    for( ; *a == *b && *b; a++, b++) ;
    return *a - *b;
}

Скажем, на Basic'е так не сделаешь.

-----------
Любопытно было бы узнать мнение автора темы: научился он работе с указателями и писать функции сравнения строк?
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог