Застрял поиск ошибки в решении вопроса с кодом

#c #reverse #c-strings #letter #function-definition

#c #обратный #c-строки #письмо #функция-определение

Вопрос:

Проблема проста: возьмите строку и измените положение ТОЛЬКО букв (строчных или прописных). Оставьте все специальные символы там, где они есть. Мое решение:

 char * reverseOnlyLetters(char * S){
    
    int Len = strlen(S);
    char *StrBeg, *StrEnd, tempCh;
    bool FoundStart = 0, FoundEnd = 0;
    
    StrBeg = S;
    StrEnd = S   (Len - 1);
    
    for (int i = 0; i < (Len/2); i  )
    {
        if (((*StrBeg>= 'A') amp;amp; (*StrBeg <= 'Z')) || ((*StrBeg >= 'a') amp;amp; (*StrBeg <= 'z')))            
        {
            FoundStart = 1;
        }
        else
        {
            StrBeg  ;
        }
        
        if (((*StrEnd >= 'A') amp;amp; (*StrEnd <= 'Z')) || ((*StrEnd >= 'a') amp;amp; (*StrEnd <= 'z')))            
        {
            FoundEnd = 1;
        }
        else
        {
            StrEnd--;
        }
        
        if(FoundStart amp;amp; FoundEnd)
        {
            tempCh = *StrEnd;
            *StrEnd = *StrBeg;
            *StrBeg = tempCh;
            
            StrBeg  ;
            StrEnd--;
            
            FoundStart = 0;
            FoundEnd = 0;
        }
            
    }

    return S;
}
  

Проблема заключается в сбое тестового примера типа «a-bC-dEf-ghIj»; буквы «E» и «f» в середине либо вообще не меняются местами, либо (как я подозреваю) меняются местами, но затем меняются местами ОБРАТНО. Кто-нибудь видит, что я делаю не так?

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

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

2. Лакомый кусочек: используйте isalpha() макрос из <ctype.h> заголовка; вызов isalpha(*StrBeg) выполняет тот же тест, но быстрее и чище.

3. Ваш цикл выполняется Len/2 несколько раз. На каждой итерации он увеличивает / уменьшает одно StrBeg StrEnd или оба, в зависимости от обстоятельств. Хотя он нашел букву спереди или сзади и увеличивает / уменьшает другой указатель, чтобы найти в нем букву, никакого прогресса в front / back не происходит. Поэтому Len/2 для полной работы с одной стороны может потребоваться больше итераций. Вам нужно другое условие завершения для вашего цикла.

4. Возможно for (int i = 0; i < (Len/2); i ) , —> while (StrBeg <= StrEnd) ? (и, возможно, обнаружение отсутствия прогресса)

5. @chux — Восстановление Моника использовала ваше предложение о цикле while. Работает отлично. Спасибо.

Ответ №1:

Проблема в этом для (int i = 0; i < (Len / 2); i ). Если длина строки четная, все в порядке, но в случае, если она четная, она не проходит через средний символ. E в этом случае «a-bC-dEf-ghIj», поэтому он не может переключить его с помощью f.

Ответ №2:

Подход, использующий этот цикл for

 for (int i = 0; i < (Len/2); i  )
  

неверно. Давайте предположим, что строка "@AB" . Результирующая строка будет выглядеть следующим образом "@BA"

Но, используя ваш цикл, вы будете иметь (как Len / 2 равно 1 )

 for (int i = 0; i < 1; i  )
  

На первой и единственной итерации цикла указатель StrBeg будет увеличен

 StrBeg  ;
  

потому что указанный символ не является буквой.

Так что ничего не будет отменено.

Функция может быть написана проще следующим образом

 #include <stdio.h>
#include <string.h>
#include <ctype.h>

char * reverse_letters( char *s )
{
    for ( char *first = s, *last = s   strlen( s ); first < last;   first )
    {
        while ( first != last amp;amp; !isalpha( ( unsigned char )*first ) )   first;
        while ( last != first amp;amp; !isalpha( ( unsigned char )*--last ) );
        
        if ( first != last )
        {
            char c = *first;
            *first = *last;
            *last = c;
        }
    }
    
    return s;
}

int main( void ) 
{
    char s[] = "one, two, three";
    puts( s );
    puts( reverse_letters( s ) );

    char s1[] = "@AB";
    puts( s1 );
    puts( reverse_letters( s1 ) );
}   
  

Вывод программы

 one, two, three
eer, hto, wteno
@AB
@BA