it-swarm.com.ru

Как вы перевернуть строку на месте в C или C++?

Как перевернуть строку в C или C++, не требуя отдельного буфера для хранения перевернутой строки?

163
uvote

Зло C:

#include <stdio.h>

void strrev(char *p)
{
  char *q = p;
  while(q && *q) ++q;
  for(--q; p < q; ++p, --q)
    *p = *p ^ *q,
    *q = *p ^ *q,
    *p = *p ^ *q;
}

int main(int argc, char **argv)
{
  do {
    printf("%s ",  argv[argc-1]);
    strrev(argv[argc-1]);
    printf("%s\n", argv[argc-1]);
  } while(--argc);

  return 0;
}

(Это XOR-swap вещь. Обратите внимание, что вы должны избегать поменяться местами с self, потому что a ^ a == 0.)


Хорошо, давайте исправим символы UTF-8 ...

#include <bits/types.h>
#include <stdio.h>

#define SWP(x,y) (x^=y, y^=x, x^=y)

void strrev(char *p)
{
  char *q = p;
  while(q && *q) ++q; /* find eos */
  for(--q; p < q; ++p, --q) SWP(*p, *q);
}

void strrev_utf8(char *p)
{
  char *q = p;
  strrev(p); /* call base case */

  /* Ok, now fix bass-ackwards UTF chars. */
  while(q && *q) ++q; /* find eos */
  while(p < --q)
    switch( (*q & 0xF0) >> 4 ) {
    case 0xF: /* U+010000-U+10FFFF: four bytes. */
      SWP(*(q-0), *(q-3));
      SWP(*(q-1), *(q-2));
      q -= 3;
      break;
    case 0xE: /* U+000800-U+00FFFF: three bytes. */
      SWP(*(q-0), *(q-2));
      q -= 2;
      break;
    case 0xC: /* fall-through */
    case 0xD: /* U+000080-U+0007FF: two bytes. */
      SWP(*(q-0), *(q-1));
      q--;
      break;
    }
}

int main(int argc, char **argv)
{
  do {
    printf("%s ",  argv[argc-1]);
    strrev_utf8(argv[argc-1]);
    printf("%s\n", argv[argc-1]);
  } while(--argc);

  return 0;
}
  • Почему, да, если ввод не работает, это будет весело поменять местами.
  • Полезная ссылка при вандализме в UNICODE: http://www.macchiato.com/unicode/chart/
  • Кроме того, UTF-8 более 0x10000 не проверен (поскольку у меня, кажется, нет ни одного шрифта для этого, ни терпения, чтобы использовать гекседитор)

Примеры:

$ ./strrev Räksmörgås ░▒▓○◔◑◕●

░▒▓○◔◑◕● ●◕◑◔○▓▒░

Räksmörgås sågrömskäR

./strrev verrts/.
120
Anders Eurenius
#include <algorithm>
std::reverse(str.begin(), str.end());

Это самый простой способ в C++.

446
Greg Rogers

Читайте Керниган и Ричи

#include <string.h>

void reverse(char s[])
{
    int length = strlen(s) ;
    int c, i, j;

    for (i = 0, j = length - 1; i < j; i++, j--)
    {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}
159
Evgeny

Переверните строку на месте (визуализация):

Reverse a string in place

56
slashdottir

Не злой C, если принять общий случай, когда строка представляет собой массив char с нулевым символом в конце:

#include <stddef.h>
#include <string.h>

/* PRE: str must be either NULL or a pointer to a 
 * (possibly empty) null-terminated string. */
void strrev(char *str) {
  char temp, *end_ptr;

  /* If str is NULL or empty, do nothing */
  if( str == NULL || !(*str) )
    return;

  end_ptr = str + strlen(str) - 1;

  /* Swap the chars */
  while( end_ptr > str ) {
    temp = *str;
    *str = *end_ptr;
    *end_ptr = temp;
    str++;
    end_ptr--;
  }
}
40
Chris Conway

Вы используете std::reverse алгоритм из стандартной библиотеки C++.

34
Nemanja Trifunovic

Прошло какое-то время, и я не помню, какая книга научила меня этому алгоритму, но я подумал, что он довольно гениален и прост для понимания:

char input[] = "moc.wolfrevokcats";

int length = strlen(input);
int last_pos = length-1;
for(int i = 0; i < length/2; i++)
{
    char tmp = input[i];
    input[i] = input[last_pos - i];
    input[last_pos - i] = tmp;
}

printf("%s\n", input);
25
karlphillip

Используйте метод std :: reverse из STL :

std::reverse(str.begin(), str.end());

Вам нужно будет включить библиотеку «алгоритма», #include<algorithm>.

22
user2628229

Обратите внимание, что прелесть std :: reverse заключается в том, что он работает со строками char * и std::wstrings так же, как и с std::strings

void strrev(char *str)
{
    if (str == NULL)
        return;
    std::reverse(str, str + strlen(str));
}
20
Eclipse

В интересах полноты следует отметить, что существуют представления строк на различных платформах, в которых число байтов на символ варьируется в зависимости от символа. Программисты старой школы называют это DBCS (двухбайтовый набор символов) . Современные программисты чаще сталкиваются с этим в UTF-8 (а также UTF-16 и другие). Есть и другие подобные кодировки.

В любой из этих схем кодирования с переменной шириной простые выложенные здесь простые алгоритмы ( зло , не зло или иначе ) не будут работать правильно вообще! Фактически, они могут даже привести к тому, что строка станет неразборчивой или даже недопустимой строкой в ​​этой схеме кодирования. Смотрите ответ Хуана Пабло Калифано для некоторых хороших примеров.

std :: reverse () потенциально все равно будет работать в этом случае, если реализация Стандартной библиотеки C++ (в частности, итераторы строк) на вашей платформе должным образом учитывает это.

11
Tim Farley

Если вы ищете реверсивные буферы с завершением NULL, большинство решений, размещенных здесь, в порядке. Но, как уже заметил Тим Фарли, эти алгоритмы будут работать только в том случае, если допустимо предположить, что строка является семантически массивом байтов (то есть однобайтовых строк), что, на мой взгляд, является неверным предположением. 

Взять, к примеру, строку «año» (год по-испански).

Кодовые точки Unicode: 0x61, 0xf1, 0x6f.

Рассмотрим некоторые из наиболее часто используемых кодировок:

Latin1/iso-8859-1 (однобайтовая кодировка, 1 символ - 1 байт и наоборот):

Оригинал:

0x61, 0xf1, 0x6f, 0x00

Задний ход:

0x6f, 0xf1, 0x61, 0x00

Результат в порядке

UTF-8:

Оригинал:

0x61, 0xc3, 0xb1, 0x6f, 0x00

Задний ход:

0x6f, 0xb1, 0xc3, 0x61, 0x00

Результатом является бред и недопустимая последовательность UTF-8

UTF-16 Big Endian:

Оригинал:

0x00, 0x61, 0x00, 0xf1, 0x00, 0x6f, 0x00, 0x00

Первый байт будет обрабатываться как NUL-терминатор. Обратного хода не будет.

UTF-16 Little Endian:

Оригинал:

0x61, 0x00, 0xf1, 0x00, 0x6f, 0x00, 0x00, 0x00

Второй байт будет обрабатываться как NUL-терминатор. Результат будет 0x61, 0x00, строка, содержащая символ «a».

11
Juan Pablo Califano
#include <cstdio>
#include <cstdlib>
#include <string>

void strrev(char *str)
{
        if( str == NULL )
                return;

        char *end_ptr = &str[strlen(str) - 1];
        char temp;
        while( end_ptr > str )
        {
                temp = *str;
                *str++ = *end_ptr;
                *end_ptr-- = temp;
        }
}

int main(int argc, char *argv[])
{
        char buffer[32];

        strcpy(buffer, "testing");
        strrev(buffer);
        printf("%s\n", buffer);

        strcpy(buffer, "a");
        strrev(buffer);
        printf("%s\n", buffer);

        strcpy(buffer, "abc");
        strrev(buffer);
        printf("%s\n", buffer);

        strcpy(buffer, "");
        strrev(buffer);
        printf("%s\n", buffer);

        strrev(NULL);

        return 0;
}

Этот код производит этот вывод:

gnitset
a
cba
4
uvote

Другой способ C++ (хотя я бы, вероятно, сам использовал std :: reverse () :) как более выразительный и быстрый)

str = std::string(str.rbegin(), str.rend());

Способ C (более или менее :)) И, пожалуйста, будьте осторожны с трюком XOR для подкачки, Компиляторы иногда не могут его оптимизировать.

В таком случае это обычно намного медленнее.

char* reverse(char* s)
{
    char* beg = s, *end = s, tmp;
    while (*end) end++;
    while (end-- > beg)
    { 
        tmp  = *beg; 
        *beg++ = *end;  
        *end =  tmp;
    }
    return s;
} // fixed: check history for details, as those are interesting ones
4
pprzemek

Мне нравится ответ Евгения K & R. Тем не менее, приятно видеть версию с использованием указателей. Иначе, это по сути то же самое:

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

char *reverse(char *str) {
    if( str == NULL || !(*str) ) return NULL;
    int i, j = strlen(str)-1;
    char *sallocd;
    sallocd = malloc(sizeof(char) * (j+1));
    for(i=0; j>=0; i++, j--) {
        *(sallocd+i) = *(str+j);
    }
    return sallocd;
}

int main(void) {
    char *s = "a man a plan a canal panama";
    char *sret = reverse(s);
    printf("%s\n", reverse(sret));
    free(sret);
    return 0;
}
3
Rob

Если вы используете GLib, для этого есть две функции: g_strreverse () и g_utf8_strreverse ()

3
dmityugov

Используйте std::reverse()

reverse(begin(str), end(str));

И это все.

2
Andreas DM

Рекурсивная функция, чтобы перевернуть строку на месте (без дополнительного буфера, malloc).

Короткий, сексуальный код. Плохое, плохое использование стека. 

#include <stdio.h>

/* Store the each value and move to next char going down
 * the stack. Assign value to start ptr and increment 
 * when coming back up the stack (return).
 * Neat code, horrible stack usage.
 *
 * val - value of current pointer.
 * s - start pointer
 * n - next char pointer in string.
 */
char *reverse_r(char val, char *s, char *n)
{
    if (*n)
        s = reverse_r(*n, s, n+1);
   *s = val;
   return s+1;
}

/*
 * expect the string to be passed as argv[1]
 */
int main(int argc, char *argv[])
{
    char *aString;

    if (argc < 2)
    {
        printf("Usage: RSIP <string>\n");
        return 0;
    }

    aString = argv[1];
    printf("String to reverse: %s\n", aString );

    reverse_r(*aString, aString, aString+1); 
    printf("Reversed String:   %s\n", aString );

    return 0;
}
2
Simon Peverett

Поделитесь моим кодом. Как ученик C++, как вариант использования swap (), я скромно спрашиваю комментарии.

void reverse(char* str) {
    int length = strlen(str);
    char* str_head = str;
    char* str_tail = &str[length-1];
    while (str_head < str_tail) 
        swap(*str_head++, *str_tail--);
}
1
Pei

Если вы используете ATL/MFC CString, просто вызовите CString::MakeReverse().

1
Michael Haephrati

С C++ лямбда: 

 auto reverse = [](std::string& s) -> std::string {
        size_t start = 0, end = s.length() -1;
        char temp;

        while (start < end) {
          temp = s[start];
          s[start++] = s[end];
          s[end--] = temp;
        } 

        return s;
   };
0
adem

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

void Rev()
{
 char ch;
 cin.get(ch);
 if (ch != '\n')
 {
    Rev();
    cout.put(ch);
 }

}

0
Alok

Еще один:

#include <stdio.h>
#include <strings.h>

int main(int argc, char **argv) {

  char *reverse = argv[argc-1];
  char *left = reverse;
  int length = strlen(reverse);
  char *right = reverse+length-1;
  char temp;

  while(right-left>=1){

    temp=*left;
    *left=*right;
    *right=temp;
    ++left;
    --right;

  }

  printf("%s\n", reverse);

}
0
Mike Marrotte

Мой ответ будет похож на большинство из них, но, пожалуйста, найдите мой код здесь.

//Method signature to reverse string
string reverseString(string str);

int main(void){
    string str;
    getline(cin, str);
    str =  reverseString(str);
    cout << "The reveresed string is : " << str;
    return 0;
}

/// <summary>
///     Reverses the input string.
/// </summary>
/// <param name="str">
///    This is the input string which needs to be reversed.
/// </param>
/// <return datatype = string>
///     This method would return the reversed string
/// </return datatype>

string reverseString(string str){
    int length = str.size()-1;
    char temp;
    for( int i=0 ;i<(length/2);i++)
    {
        temp = str[i];
        str[i] = str[length-i];
        str[length-i] = temp;
    }
    return str;
}
0
GANESH B K
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

unsigned char * utf8_reverse(const unsigned char *, int);
void assert_true(bool);

int main(void)
{
    unsigned char str[] = "mañana mañana";
    unsigned char *ret = utf8_reverse(str,  strlen((const char *) str) + 1);

    printf("%s\n", ret);
    assert_true(0 == strncmp((const char *) ret, "anãnam anañam", strlen("anãnam anañam") + 1));

    free(ret);

    return EXIT_SUCCESS;
}

unsigned char * utf8_reverse(const unsigned char *str, int size)
{
    unsigned char *ret = calloc(size, sizeof(unsigned char*));
    int ret_size = 0;
    int pos = size - 2;
    int char_size = 0;

    if (str ==  NULL) {
        fprintf(stderr, "failed to allocate memory.\n");
        exit(EXIT_FAILURE);
    }

    while (pos > -1) {

        if (str[pos] < 0x80) {
            char_size = 1;
        } else if (pos > 0 && str[pos - 1] > 0xC1 && str[pos - 1] < 0xE0) {
            char_size = 2;
        } else if (pos > 1 && str[pos - 2] > 0xDF && str[pos - 2] < 0xF0) {
            char_size = 3;
        } else if (pos > 2 && str[pos - 3] > 0xEF && str[pos - 3] < 0xF5) {
            char_size = 4;
        } else {
            char_size = 1;
        }

        pos -= char_size;
        memcpy(ret + ret_size, str + pos + 1, char_size);
        ret_size += char_size;
    }    

    ret[ret_size] = '\0';

    return ret;
}

void assert_true(bool boolean)
{
    puts(boolean == true ? "true" : "false");
}
0
masakielastic