Своя версия strcmp(), кто предложит лучший вариант?
[SIZE="2"]Вот мой вариант:[/SIZE]
// 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 (one==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]
Наверное, требовалось примерно такое решение (особо не тестировал):
{
while(*a && *b && (*a == *b))
{
a++; b++;
}
if (*a > *b) return 1;
if (*a < *b) return -1;
return 0;
}
{
return (*a && *b && (*a == *b)) ? ((*(a+1) || *(b+1)) ? (compstr(a+1, b+1)) : (0)) : ((*a > *b) ? (1) : (-1));
}
{
for(int i=0; str1==str2!=0; i++)
if(str1==0) return true;
return false;
}
если через инт возвращать результат то
{
for(int i=0; *(str1+i)==*(str2+i)!=0; i++)
if(*(str1+i)==0) return 0;
return *(str1+i)-*(str2+i);
}
То есть тело цикла будет выполено лишь в том случае, если i-й символ обеих строк совпадает и не равен 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.
{
return (*a && *b && (*a == *b)) ? ((*(a+1) || *(b+1)) ? (compstr(a+1, b+1)) : (0)) : ((*a > *b) ? (1) : (-1));
}
Прикольно, но не очень читаемо. И, вроде бы, можно оптимизировать:
{
return (*a == *b) ? ((*a || *b) ? compstr(a+1, b+1) : 0) : ((*a > *b) ? 1 : -1);
}
Теперь моя очередь (:
{
return (*a == *b && *b) ? compstr(a+1, b+1) : 1 - (*a == *b) - 2 * (*a < *b);
}
То есть тело цикла будет выполено лишь в том случае, если i-й символ обеих строк совпадает и не равен 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 <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 предлагаю провести мини соревнование, чья выполниться быстрее(к слову об оптимизовать)!=)
{
for(int i(0); str1==str2!=0; i++)
if(str1==0) return true;
return false;
}
...
предлагаю провести мини соревнование, чья выполниться быстрее(к слову об оптимизовать)!=)
А ++i быстрее i++ ;) надо ж приблизить к совершенству, оптимизаторы несовершенны, могут не схавать
откуда такие сведения? если честно ни когда не слышал, не подскажешь ссылочку где можно почитать, очень интересно!?=)
там эти ребята еще об оптимизаторах говорят, но не уверен что всегда вот будет оно оптимизироваться во всех компиляторах. А вообще еще в какойто книжке было написано, да и не особо оно то важно вообщем-то.
там эти ребята еще об оптимизаторах говорят, но не уверен что всегда вот будет оно оптимизироваться во всех компиляторах. А вообще еще в какойто книжке было написано, да и не особо оно то важно вообщем-то.
хм, логично, фишка!=) аналогично
быстрее чем
хотя опять же для стандартных типо это дело оптимизировано как бы!=)
Вы были правы насчёт моего замечания по поводу "проверки, которая никогда не будет выполняться". Я действительно ошибся и связано это с тем, что в любом коде пытаюсь увидеть смысл. Таким образом, проверка
"str1==str2!=0", ничем не отличающаяся от "str1==str2" совершенно сбила меня с толку :)
Во всех реализациях strcmp с которыми я сталкивался, она всегда возвращала -1, 0 или 1.
Если такого требования нету, тогда Ваша вторая функция действительно будет работать правильно.
Ну а моя функция без этого требования будет выглядеть так:
{
return (*a == *b && *b) ? compstr(a+1, b+1) : (*a - *b);
}
Во всех реализациях strcmp с которыми я сталкивался, она всегда возвращала -1, 0 или 1.
ну не знаю, стркмп из стандартной библиотеки работает именно так!=)
Но в Вашем варианте присутствует переменная i и операции с ней, а можно было обойтись только входящими данными. Например так:
{
while (*a++ == *b++ && *b);
return *(a-1) - *(b-1);
}
...
ЗЫ: вообще то strcmp возвращает не 0,-1,1, а значение 0, если строки равны, и больше либо меньше нуля, если они не равны.=) читай Савича или МЗДН!=)
Ну так кто должен букварь читать после этого? Уж наверно тот, кто неправильно реализовал. В любом случае, грубить не надо.
Читать надо не МСДН - он тут совсем не указ. Читать надо стандарт по Си:
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.
То есть функция должна возвратить либо ноль, либо целочисленное число больше нуля, либо целочисленное число меньше нуля.
Читать надо не МСДН - он тут совсем не указ. Читать надо стандарт по Си:
То есть функция должна возвратить либо ноль, либо целочисленное число больше нуля, либо целочисленное число меньше нуля.
эм, в смысле не правильно реализовал и читать букварь?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 нас выручит в этом плане!=)
const char* str - указатель на константу: запрещает изменять значение обьекта, на который указывает
char *const str - константный указатель: запрещает изменять себя
const char *const str - константный указатель на константу: запрещает изменять себя и значение обьекта на который указывает
А сами внешние указатели на строки не меняются потому, что, как Вы правильно подметили, функция просто создаёт их копии. Чтобы их изменить, необходимо функции передавать адреса этих указателей, а сама функция должна иметь в качестве формальных аргументов указатели на указатели.
PS: я за безопасное сравнение строк, а Вы? :)
const char* str - указатель на константу: запрещает изменять значение обьекта, на который указывает
char *const str - константный указатель: запрещает изменять себя
const char *const str - константный указатель на константу: запрещает изменять себя и значение обьекта на который указывает
А сами внешние указатели на строки не меняются потому, что, как Вы правильно подметили, функция просто создаёт их копии. Чтобы их изменить, необходимо функции передавать адреса этих указателей, а сама функция должна иметь в качестве формальных аргументов указатели на указатели.
PS: я за безопасное сравнение строк, а Вы? :)
ну конечно же я за безопасное сравнение строк!=) было бы интересно после операции сравнения получить два нулевых указателя!=) думаю автор темы получил уже достаточно сведений и целую библиотеку функций сравнения строк!=))))))))))))
Ишь. Сейчас еще выяснится, что Ander Skirnir на Хаскеле программирует :)
С Artem_3A спорить бесполезно - он знает МСДН, Савича и много других страшных слов...
С Artem_3A спорить бесполезно - он знает МСДН, Савича и много других страшных слов...
конечно, стараюсь вам соответствовать!=)
Пока что не очень, но после сессии планируется усиленное lisp, ml и что-нибудь эзотерическое (вроде brainfuck :)
Первым делом напишу на них strcmp и выложу сюда :)
(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)))))
Пока что лучше не выходит, но лето - впереди :)
Работа с указателями - вещь довольно сложная, при этом часто допускаются ошибки, и даже курение 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. Количество сравнений остаётся тем же самым.
{
while (*a++ == *b++ && *b);
return *(a - (a == 0)) - *(b--);
}
К слову об удобстве Си. Этот язык поистине позволяет вольности, недоступные во многих других языках. Вот пример с оператором for:
{
for( ; *a == *b && *b; a++, b++) ;
return *a - *b;
}
Скажем, на Basic'е так не сделаешь.
-----------
Любопытно было бы узнать мнение автора темы: научился он работе с указателями и писать функции сравнения строк?