Моя функция strstr работает, но программа, предназначенная для ее тестирования, говорит, что это не так

#c #while-loop #c-strings #function-definition #strstr

Вопрос:

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

Я все еще изучаю это, но после нескольких часов устранения неполадок я этого не понимаю. Может кто-нибудь сказать мне, что в этом плохого по сравнению с strstr ?

 char    *ft_strstr(char *str, char *to_find)
{
    int i;
    int k;

    i = 0;
    k = 0;
    if (*to_find == 0)
        return (str);
    while (str[i] != 0)
    {
        while (str[i] == to_find[k])
        {
            i  ;
            k  ;
            if (to_find[k] == 0)
                return (amp;str[i - k]);
        }
        i  ;
        k = 0;
    }
    return (0);
}
 

Должен ли я включить основной для тестирования ?

Спасибо.

ИЗМЕНИТЬ : Вот код ошибки машины :

 >

gt; ./0z09k44vyodiwxihua4w30m9


gt; diff -U 3 user_output_test1
> test1.output | cat -e
> --- user_output_test1 2021-08-11 17:55:47.000000000 0000$
> test1.output 2021-08-11 17:55:47.000000000 0000$ @@ -2,7 2,7 @@$ 0$ -1$ 0$
> -7$
> -1$ 0$ 2$ 2$ @@ -12,7 12,7 @@$ -1$ -1$ -1$
> -87$
> -1$ -1$ -1$ -1$
>
> Diff KO 🙁 Grade: 0

Комментарии:

1. Проблема в том , что если внутренний цикл while соответствует первым нескольким символам to_find , но не более поздним, вы i слишком сильно увеличитесь для следующей итерации внешнего цикла while.

2. Не по теме, но вместо этого у вас должны быть оба ваших параметра const char * , так как их не следует изменять.

3. Попробуй str = "ababac", to_find = "abac" . Не имеет отношения к вашей проблеме, return не нуждается в круглых скобках, int i; i = 0; может быть объединен с int i = 0; , и его тип следует изменить на size_t . Параметры должны иметь тип const char * .

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

5. Что-то, что нужно помнить: когда имеешь дело с чем-то, даже наполовину заслуживающим доверия, что говорит о том, что ваш код неправильный, и вы думаете, что ваш код правильный: всегда начинайте с того, что ваш код неправильный, а не с «Мой код правильный. Тестовая программа/компилятор/что-то не так». Угадайте, что — скорее всего, ваш код неверен, и вы просто его не видите. И чем больше пользователей для всего, что говорит о том, что ваш код неверен, тем больше вероятность того, что ваш код на самом деле неверен. Если GCC скажет, что ваш код неверен, в 99,99999999% случаев ваш код будет неверным. Тест, проведенный вашим профессором? Вероятно, в 99,99% случаев ваш код будет неверным.

Ответ №1:

Эти циклы while неверны

 while (str[i] != 0)
{
    while (str[i] == to_find[k])
    {
        i  ;
        k  ;
        if (to_find[k] == 0)
            return (amp;str[i - k]);
    }
    i  ;
    k = 0;
}
 

Давайте предположим, что str это "aab" так и to_find есть "ab" . В этом случае внутренний цикл while получает управление, потому str[0] что равен tp to_find[0] . В цикле оба индекса увеличиваются и str[1] не равны to_find[1] . Таким образом, цикл прерывает свою итерацию, и после цикла индекс i снова увеличивается и становится равным 2 . Таким образом, подстрока не будет найдена.

Вам нужно ввести еще один индекс для внутреннего цикла while. Например

 while (str[i] != 0)
{
    int j = i;
    while (str[j] == to_find[k])
    {
        j  ;
        k  ;
        if (to_find[k] == 0)
            return (amp;str[j - k]);
    }
    i  ;
    k = 0;
}
 

На самом деле вам нужно использовать только одну переменную в качестве индекса. Циклы могут быть переписаны следующим образом

 for ( ; *str;   str )
{
    size_t i = 0;

    while ( str[i] == to_find[i] )
    {
        if ( to_find[  i] == '' ) return str;
    }
} 
 

Обратите внимание, что функция имеет следующее объявление

 char *strstr(const char *s1, const char *s2);
 

То есть его параметры имеют квалификатор const .

Если вы объявите функцию таким образом, то оператор return будет выглядеть так

 return ( char * )(amp;str[j - k]);
 

или

 return ( char * )str;
 

если использовать модифицированные циклы, показанные выше.

Вот демонстрационная программа.

 #include <stdio.h>

char * ft_strstr( const char *str, const char *to_find )
{
    if ( *to_find == '' ) return ( char * )str;
    
    for ( ; *str;   str )
    {
        size_t i = 0;

        while ( str[i] == to_find[i] )
        {
            if ( to_find[  i] == '' ) return ( char * )str;
        }
    }
    
    return NULL;
}

int main(void) 
{
    char *p = ft_strstr( "aab", "ab" );
    
    if ( p ) puts( p );
    
    return 0;
}
 

Вывод программы является

 ab
 

Комментарии:

1. Спасибо, что нашли время ответить на мой вопрос, я прочитаю это и попытаюсь исправить, хотя здесь, в Бельгии, уже поздно, поэтому я займусь этим завтра. Я обновлю тему, как только мне удастся ее исправить ! Но еще раз спасибо вам !

2. Эй! Спасибо за супер подробный и понятный ответ, я его прекрасно понял ! Только небольшой вопрос, в конце концов, для оператора return, вы имеете в виду, что я могу написать его так : return (amp;str[j — k]); ?

3. @Toyama70 Да, вы можете написать либо return amp;str[j — k]; или просто return amp;str[i]; или return str i;. Если вы объявите функцию так, как она объявлена в стандарте C, с определителем const для ее параметров, то вам нужно привести возвращаемое выражение, например, return ( char * )( str i );

4. Ваши комментарии были очень полезны, я все прекрасно понял, большое вам спасибо !

5. @Toyama70 Вместо того, чтобы писать «Решено» в названии вопроса, вы должны выбрать лучший ответ.

Ответ №2:

Основная проблема заключается в том , что ваш код необходимо сравнивать str с to_find каждым исходным индексом str , пока он не найдет совпадение. В настоящее время, если ваш код найдет частичное совпадение, он «пропустит» проверку определенных начальных индексов. Например, попробуйте использовать строку aab и подстроку ab . На самом деле это приведет к segfault.

Некоторые дополнительные советы:

  • Посмотрите точное определение функции и ее поведение на веб-сайте, таком как cppreference.
  • Для i и k ; Лучше определить и инициализировать переменную в одной строке.
  • Будьте явными: верните NULL (нулевой указатель) и сравните с для нулевого терминатора.
  • Когда вы думаете о тестовых примерах, думайте не о строке и подстроке, а о любом допустимом вводе и о том, как ваша программа будет его обрабатывать.

Ответ №3:

Твой strstr() не работает. У меня возникают трудности с построением контрпримера, но если вы продвинулись на несколько мест вперед, чтобы найти ложное совпадение, вы не перематываете назад и не начинаете в следующем месте и не повторяете совпадение снова.

Как написал Флюгер в комментариях, не увеличивайте i внутренний цикл. Вот в чем причина проблемы.

Комментарии:

1. Спасибо, я собираюсь переписать его, используя вместо этого str[i k]!

Ответ №4:

Основная проблема заключается в том, что вы не возвращаетесь к началу совпадения, когда у вас есть частичное совпадение: ваша функция не будет совпадать aab в строке aaab . Вы можете исправить это, установив i = i - k 1; вместо i ; «после внутреннего цикла».

Также обратите внимание, что 0 в вашем коде это означает очень разные вещи: байт-ограничитель null в строке, число ноль в качестве индекса и нулевой указатель. Это было бы более читабельно использовать '' для нулевого терминатора и NULL для нулевого указателя.

Кроме того, индексные переменные должны иметь тип size_t в случае, если длина строки превышает диапазон типов int .

Вот измененная версия:

 char    *ft_strstr(char *str, char *to_find)
{
    size_t i;
    size_t k;

    i = 0;
    k = 0;
    if (*to_find == '')
        return (str);
    while (str[i] != '')
    {
        while (str[i] == to_find[k])
        {
            i  ;
            k  ;
            if (to_find[k] == '')
                return (amp;str[i - k]);
        }
        i = i - k   1;
        k = 0;
    }
    return (NULL);
}