#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