#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);
}