Объясните этот код C, чтобы перевернуть строку - PullRequest
3 голосов
/ 22 февраля 2011

Я действительно не понимаю, что делает последний цикл while, кто-нибудь может это объяснить?

void reverse(char *str) { 
    char * end = str; 
    char tmp; 

    if (str) {
        while (*end) { 
            ++end;
        }
        --end; 
        while (str < end) {
            tmp = *str; 
            *str++ = *end;
            *end-- = tmp;
        }
    }
}

Может кто-нибудь рассказать мне пример "привет"?

Ответы [ 5 ]

11 голосов
/ 22 февраля 2011

Основная идея этого кода состоит в том, чтобы работать в два прохода:

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

Этот первый проход задается следующей логикой:

char *end = str;
while (*end) { 
    ++end;
}
--end; 

ThisЦикл while начинается с указателя end, указывающего на начало строки.Затем он непрерывно продвигает указатель end на один шаг вперед, пока условие цикла *end больше не переходит в истинное значение.Поскольку строки C заканчиваются нулем, условие цикла будет иметь значение true, пока указатель end указывает где-то в середине строки, а не на нулевой терминатор в конце строки.Таким образом, когда этот цикл завершится, указатель end пройдёт весь путь до конца строки и остановится на нулевом терминаторе.Затем мы выполняем --end для резервного копирования указателя на один шаг.На данный момент указатель end указывает на самый последний символ в строке.Вот пример с «Hello:»

 H e l l o
 ^       ^
 |       |
str     end

Теперь, когда у нас есть этот end указатель, мы фактически запускаем логику для обращения строки.Это задается этим кодом:

while (str < end) {
    tmp = *str; 
    *str++ = *end;
    *end-- = tmp;
}

Идея этого кода состоит в том, что пока начальные и конечные указатели строки не пересекутся друг с другом, мы поменяем значения, на которые они указывают, затем переместим двауказатели внутрь друг к другу.Если мы переписываем это в эквивалент чуть более многословно

while (str < end) {
    tmp = *str; 
    *str = *end;
    *end = tmp;

    ++str;
    --end;
}

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

 H e l l o
 ^       ^
 |       |
str     end

 o e l l H
   ^   ^
   |   |
  str end

 o l l e H
     ^
     |
  str end

На этом этапе два указателя встречаются, и мы правильно перевернули строку.

Обратите внимание, что есть необычный крайний случай, который мы должны принять во внимание здесьи вот что происходит, когда строка является пустой строкой.Если это произойдет, то первый цикл будет вести себя немного странно.В частности, этот код:

char *end = str;
while (*end) { 
    ++end;
}
--end; 

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

while (str < end)

Это сразу ложно, если end - один шаг до начала строки, поэтому ничего не происходит.

Надеюсь, это поможет!

4 голосов
/ 22 февраля 2011

Что в основном происходит в самом внутреннем цикле while, так это то, что на каждой итерации символы, на которые указывают str и end, меняются местами, str увеличивается, чтобы указывать на следующий символ, а end уменьшается. указать на предыдущий.

Используя "hello" в качестве примера:

v   v
hello
 v v 
oellh
  v
olleh

И тогда цикл заканчивается, как str = end.

0 голосов
/ 11 октября 2013
#include<stdio.h>
#include<string.h>
main()
{
  int i=0,lenght,j;
  char str[100],st[100];
  printf("\nEnter a string");
  scanf("%s",str);
  lenght=strlen(str);
  for(i=0,j=(lenght-1);str[i]!='\0',j>=0;i++,j--)
   {
      st[j]=str[i];
   }
  st[i]='\0';
  printf("\nThe reversed string is %s\n",st);
 }
0 голосов
/ 22 февраля 2011

Хорошо, что это делает?

void reverse(char *str) { 
    char * end = str;  // copy the pointer 
    char tmp; 

    if (str) {
        // Now step through the string until you get to the last character.
        // which will be the null terminator \0
        while (*end) { 
            ++end;
        }
        // One step back, and we're pointing at the last actual character.
        --end; 
        // Now.  Move the start at either end and work your way inwards until
        // they meet in the middle.
        while (str < end) {
            // take copy of left character into tmp
            tmp = *str; 
            // copy right character into left position and move left pointer right
            *str++ = *end;
            // copy tmp character into right position and move right pointer left
            *end-- = tmp;
        }
    }
}
0 голосов
/ 22 февраля 2011

Первый пока находит последний символ; поэтому после него end будет указывать на него.

Второе время меняет местами символ, обозначенный str, на символ, обозначенный end, и перемещает str вперед на 1 символ и end назад на 1 символ. Таким образом, символы меняются местами, проходя от внешней части строки внутрь.

Просмотр заканчивается, когда end начинает указывать на символ до str, что означает, что мы достигли центра строки и все символы уже поменялись местами.

Пример "Hello":

S   E            S   E
V   V            V   V
Hello  >>swap>>  oellH

>>pointer increment/decrement>>

 S E              S E
 V V              V V
oellH  >>swap>>  olleH

>>pointer increment/decrement>>
it would result in

  E                
  S                
  V                
olleH

but now str is no longer before end, so the loop terminates
...