Ломаю голову над простой функцией

semaawp
semaawp аватар
Offline
Зарегистрирован: 29.05.2017

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

unsigned char String_Compare(unsigned char* Str1, unsigned char* Str2)
{
    unsigned char i;
    unsigned char flag = 1;
    unsigned char size1 = 0;
    unsigned char size2 = 0;
    size1 = sizeof Str1 / sizeof Str1[0];
    size2 = sizeof Str2 / sizeof Str2[0];
    if(size1 == size2)
    {
        for(i = 0; i < size1; i++)
        {
            if(Str1[i] != Str2[i])
            {
                flag = 0;
            }
        }
    }
    else
    {
        flag = 0;
    }
    return flag;
}
    unsigned char s1[] = {"abcde"};
    unsigned char s2[] = {"abcdd"};

void setup() {
    Serial.begin(9600);
}

void loop() {
    Serial.print(String_Compare(s1, s2));
    delay(1000);
}

я непойму почему функция возвращает единицу при заведомо ложных строках :)

rygoravich
Offline
Зарегистрирован: 04.05.2016

Видимо, потому, что первые буквы одинаковые. Посмотрите внимательно - у вас совпадение символа хотя бы на одной позиции меняет flag на ноль с концами. Кстати, если длина строк будет разная - то тоже гарантированно вернет ноль.

semaawp
semaawp аватар
Offline
Зарегистрирован: 29.05.2017

rygoravich пишет:

Видимо, потому, что первые буквы одинаковые. Посмотрите внимательно - у вас совпадение символа хотя бы на одной позиции меняет flag на ноль с концами. Кстати, если длина строк будет разная - то тоже гарантированно вернет ноль.


В строке 13 стоит != а значит любое НЕСОВПАДЕНИЕ в строке должно вернуть 0, но не возвращает

rygoravich
Offline
Зарегистрирован: 04.05.2016

Ой! Извиняюсь за невнимательность, наискосок код читал... Сейчас глянул повнимательнее.

Могу ошибаться, но видимо, ошибка в использовании sizeof - вы используете его для определения длины строки, а на самом деле Str1 у вас не строка, а указатель на массив. Хотя сам не сишник, возможно, меня кто-нибудь поправит :) .

rygoravich
Offline
Зарегистрирован: 04.05.2016

Упс, глянул вот тут: https://learnc.info/c/arrays.html.

Цитата:
При передаче массива в качестве аргумента функции будет передаваться указатель, поэтому размер массива будет невозможно узнать.

По ходу, для вашей задачи нужно вместо массива символов объект String пользовать.

semaawp
semaawp аватар
Offline
Зарегистрирован: 29.05.2017

rygoravich пишет:

Ой! Извиняюсь за невнимательность, наискосок код читал... Сейчас глянул повнимательнее.

Могу ошибаться, но видимо, ошибка в использовании sizeof - вы используете его для определения длины строки, а на самом деле Str1 у вас не строка, а указатель на массив. Хотя сам не сишник, возможно, меня кто-нибудь поправит :) .


Убрал if и for конструкции и написал return size1, действительно, вернул только 2 вместо 6

ratman
Offline
Зарегистрирован: 11.10.2015

Так не?...

// ----------------------------------------------------------------------------
//    Функция _strcmp() сравнивает в лексикографическом порядке две строки
//  и возвращает целое значение, зависящее следующим образом от результата
//  сравнения:
//    Нуль .......... str1 == str2
//    Больше нуля ... str1 != str2
//    !!! НЕ СООТВЕТСТВУЕТ БИБЛИОТЕЧНОЙ (C89) ФУНУЦИИ strcmp !!!
//
bool _strcmp(const char* str1, const char* str2) {
  uint8_t i = 0;

  for (i = 0; * (str1 + i) == *(str2 + i) != 0; i++)
    if (*(str1 + i) == 0) return 0;

  return *(str1 + i) - *(str2 + i);
}

 

rygoravich
Offline
Зарегистрирован: 04.05.2016

Пробуйте :) .

А вообще, такая форма записи мне кажется совершенно нечитаемой - я бы лучше вместо for в таких конструкциях пользовал бы while. Но это по вкусу. И еще - такой метод предполагает, что строка обязательно заканчивается нулевым символом. Про это вот тут почитать можно: http://arduino.ru/Reference/String.

semaawp
semaawp аватар
Offline
Зарегистрирован: 29.05.2017

ratman пишет:

Так не?...

// ----------------------------------------------------------------------------
//    Функция _strcmp() сравнивает в лексикографическом порядке две строки
//  и возвращает целое значение, зависящее следующим образом от результата
//  сравнения:
//    Нуль .......... str1 == str2
//    Больше нуля ... str1 != str2
//    !!! НЕ СООТВЕТСТВУЕТ БИБЛИОТЕЧНОЙ (C89) ФУНУЦИИ strcmp !!!
//
bool _strcmp(const char* str1, const char* str2) {
  uint8_t i = 0;

  for (i = 0; * (str1 + i) == *(str2 + i) != 0; i++)
    if (*(str1 + i) == 0) return 0;

  return *(str1 + i) - *(str2 + i);
}

 


Так да, просто хотел свое написать)

ratman
Offline
Зарегистрирован: 11.10.2015

semaawp пишет:
Так да, просто хотел свое написать)
Экономней не будет.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

semaawp пишет:

функцию в завел себя в тупик. 

Ну, так вылазьте!

Поскольку Вы упражняетесь, готовое решение Вам не нужно, а нужна" удочка" - правильно? Окей, держите.

Когда чего-то не понимаете, всегда ставьте кучу Serial.print буквально через строчку и смотрите на состояние своих переменных. Некоторые значения Вас удивят. Например, Вы убедитесь. что у Вас size1 и size2 всегда равны друг другу и не имеют никакого отношения к длинам строк.

Всегда печатайте значения переменных и анализируйте - не работайте вслепую.

semaawp
semaawp аватар
Offline
Зарегистрирован: 29.05.2017

ЕвгенийП пишет:

semaawp пишет:

функцию в завел себя в тупик. 

Ну, так вылазьте!

Поскольку Вы упражняетесь, готовое решение Вам не нужно, а нужна" удочка" - правильно? Окей, держите.

Когда чего-то не понимаете, всегда ставьте кучу Serial.print буквально через строчку и смотрите на состояние своих переменных. Некоторые значения Вас удивят. Например, Вы убедитесь. что у Вас size1 и size2 всегда равны друг другу и не имеют никакого отношения к длинам строк.

Всегда печатайте значения переменных и анализируйте - не работайте вслепую.

Да, я так понял, что в size хранится размер указателя, век живи - век учись) знания за день не даются ведь)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
Logik
Offline
Зарегистрирован: 05.08.2014

//Да, я так понял, что в size хранится размер указателя

Не совсем правильно, Вы ж еще чегото там делите.

1. Уберите оба size* и все что с ними связано как классово чуждые, завершение строки (и цикла  тоже) контролируйте по появлению нуля вместо очередной буквы. 

2. В цикле по обнаружению несовпадения сразу return ... Нечего цикл крутить если результат уже ясен.

3. Рассмотрите вариант с использованием указателей. Как правило эффективней.

ПС. Очень правильно что взялись сами написать такую функцию. Часто при работе с строками возникает ситуация требующая выполнения ряда действий: проверить на недопустимый символ, заменить нижний регистр на верхний, сравнить строки (иногда по сложным условиям частично совпадающие), найти положение некоторого символа-разделителя и пр. Их до чертиков. Как пишет полный лошара? - он юзает String, оно тормозит память жрет и падает. Продвинутый чел пользует strcmp, strlen и прочую стандартную лабутень. Оно работает но не так быстро, как возможно. Потому как в каждой стандартной функции будет свой цикл перебора символов в строке и сколько функций вызвали - столько раз по строке пробежатся надо. А вот в самописном цикле можна за один раз выполнить несколько действий сразу, что дает максимальную скорость. По умному - однопроходный алгоритм получите. Так что дерзайте, оно вознаградится.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

https://goo.gl/HVAHC5

Что значит "лучшую". В каких попугаях измерять лучшесть? Во времени выполнения? В памяти? С строках кода (самая длинная или самая короткая)? В каких-то ещё ресурсах?

И даже если фиксировать попугаев, всё равно "лушего" (не в смысле лучше данного, а самого лучшего) не бывает, если не оговоаривать специфику задачи. Например, если критерий лучшести время сравнения, то очень важен вопрос "какие строки (по длине) ожидаются?". Обычно из существа задачи это понятно, и чтобы написать лучшую функцию это надо знать. Функция заточенная под строки в единицы-десятки байтов будет одна, а под мегабайты - совсем другая. И каждая на своей поляне обставит другую.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ЕвгенийП, вот и не надо так нервничать. Каждый выбирает для себя ... https://www.youtube.com/watch?v=Ygkr-Iw6Mb8

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А с чего Вы взяли, что я нервничаю? Наоборот, у меня прекрасное настроение, вот и тянет на философские беседы. Или у Вас настроение паршивое и я не вовремя под руку, ну тогда извините.