Como você inverte uma seqüência de caracteres no lugar em C ou C ++?

173

Como você reverte uma seqüência de caracteres em C ou C ++ sem exigir um buffer separado para armazenar a seqüência de caracteres revertida?

Mash de codificação
fonte
17
O código na resposta aceita está terrivelmente errado . Consulte stackoverflow.com/a/21263068/88656 para obter detalhes.
precisa saber é o seguinte

Respostas:

123

O algoritmo padrão é usar ponteiros para o início / fim e guiá-los para dentro até encontrarem ou cruzarem no meio. Troque conforme você for.


String ASCII reversa, ou seja, uma matriz terminada em 0 onde cada caractere se encaixa em 1 char. (Ou outros conjuntos de caracteres não multibyte).

void strrev(char *head)
{
  if (!head) return;
  char *tail = head;
  while(*tail) ++tail;    // find the 0 terminator, like head+strlen
  --tail;               // tail points to the last real char
                        // head still points to the first
  for( ; head < tail; ++head, --tail) {
      // walk pointers inwards until they meet or cross in the middle
      char h = *head, t = *tail;
      *head = t;           // swapping as we go
      *tail = h;
  }
}

// test program that reverses its args
#include <stdio.h>

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

O mesmo algoritmo funciona para matrizes inteiras com comprimento conhecido, basta usar em tail = start + length - 1vez do loop de localização final.

. (Nota do editor: esta resposta originalmente usado XOR-swap para esta versão simples, também fixa para o benefício de futuros leitores desta questão popular. XOR-swap é altamente não recomendado ; difícil de ler e fazer a sua compilação de código menos eficiente Você. você pode ver no Godbolt compiler explorer o quão mais complicado é o corpo do loop asm quando o xor-swap é compilado para x86-64 com o gcc -O3.)


Ok, tudo bem, vamos consertar os caracteres UTF-8 ...

(Isto é coisa XOR-swap. Tome o cuidado de nota que você deve evitar trocar com o eu, porque se *pe *qestão no mesmo local que você vai zerar-lo com a ^ a == 0. XOR-swap depende de ter dois locais distintos, usando cada um deles como armazenamento temporário.)

Nota do editor: você pode substituir o SWP por uma função em linha segura usando uma variável tmp.

#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;
}
  • Por que, sim, se a entrada for borked, isso será alterado alegremente fora do local.
  • Link útil ao vandalizar no UNICODE: http://www.macchiato.com/unicode/chart/
  • Além disso, o UTF-8 acima de 0x10000 não foi testado (como não tenho nenhuma fonte para isso nem paciência para usar um hexeditor)

Exemplos:

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

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

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

./strrev verrts/.
Anders Eurenius
fonte
162
Não há uma boa razão para usar a troca XOR fora de uma competição de código ofuscada.
Chris Conway
28
Você acha que "no local" significa "sem memória extra", nem mesmo memória O (1) para temporários? E o espaço na pilha para str e o endereço de retorno?
Chris Conway
55
@ Bill, não é isso que significa a definição comum de "no local". Algoritmos no local podem usar memória adicional. No entanto, a quantidade dessa memória adicional não deve depender da entrada - ou seja, deve ser constante. Portanto, a troca de valores usando armazenamento adicional está completamente implementada.
Konrad Rudolph
19
Não com direito a voto até que a troca xor desapareça.
Adam Rosenfield
34
A troca de XOR é mais lenta que a troca via registro nos modernos processadores fora de ordem.
Patrick Schlüter
465
#include <algorithm>
std::reverse(str.begin(), str.end());

Essa é a maneira mais simples em C ++.

Greg Rogers
fonte
6
Em C ++, uma sequência é representada pela classe de sequência. Ele não pediu "char star" ou "char brackets". Estadia elegante, C.
jokoon
10
@fredsbend, a versão "ridiculamente longa" da resposta selecionada lida com um caso que essa resposta simples não - entrada UTF-8. Isso mostra a importância de especificar completamente o problema. Além disso, a pergunta era sobre código que também funcionaria em C.
Mark Ransom
5
Esta resposta lida com o caso se você usar uma classe de sequência de caracteres UTF-8 (ou possivelmente uma classe de caracteres utf-8 com std :: basic_string). Além disso, a pergunta dizia "C ou C ++", não "C e C ++". C ++ apenas é "C ou C ++".
Taywee
161

Leia Kernighan e Ritchie

#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;
    }
}
Eric Leschinski
fonte
8
Testado no meu iphone este é mais lento do que usando endereços ponteiro bruto em cerca de 15%
jjxtra
3
A variável "c" não deveria ser um caractere em vez de um int?
Lesswire 17/11
17
É importante observar neste exemplo que a string sdeve ser declarada em um formato de matriz. Em outras palavras, char s[] = "this is ok"em vez de char *s="cannot do this"porque o último resulta de uma constante de cadeia que não podem ser modificados
user1527227
3
Com desculpas a "O Poderoso Chefão" .... "Deixe as armas, traga o K&R". Como um fanático C, eu uso os ponteiros, como eles são mais simples e mais direta para este problema, mas o código seria menos portátil para C #, Java, etc.
2
@ Eric Isso não é executado no tempo O (log (n)). Ele é executado em O (n) se você estiver se referindo ao número de trocas de caracteres que o código executa, para n de comprimento de sequência, então n trocas são executadas. Se você está falando sobre a quantidade de loops executados, ainda é O (n) - embora O (n / 2), mas você solta as constantes na notação Big O.
Stephen Fox
62

Inverta uma string no lugar (visualização):

Inverter uma string no lugar

slashdottir
fonte
Legal! O que você usou para criar isso? Eu acho que a resposta seria melhorada, incluindo um link para ele.
Pryftan
A implementação deste algoritmo está realmente nesta resposta .
karlphillip
Você pode explicar um pouco isso, se o link da imagem morrer, a resposta não será inútil?
SS Anne
41

C não mau, assumindo o caso comum em que a cadeia é uma charmatriz terminada em nulo :

#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--;
  }
}
Chris Conway
fonte
Em vez de usar um loop while para encontrar o ponteiro final, você não pode usar algo como end_ptr = str + strlen (str); Eu sei que isso fará praticamente a mesma coisa, mas acho mais claro.
Peter Kühne
Justo. Eu estava tentando (e falhando) evitar o erro de um por um na resposta do @ uvote.
Chris Conway
Além de uma possível melhoria de desempenho com talvez int temp, esta solução parece melhor. +1
chux - Restabelece Monica
@ chux-ReinstateMonica Sim. É lindo. Pessoalmente, eu removeria os () s do !(*str)though.
Pryftan
@ PeterKühne Sim ou strchr()procurando '\0'. Eu pensei em ambos. Não é necessário um loop.
Pryftan
35

Você usa o std::reversealgoritmo da Biblioteca Padrão C ++.

Nemanja Trifunovic
fonte
14
Biblioteca de modelos padrão é um termo pré-padrão. O padrão C ++ não o menciona, e os componentes STL anteriores estão na Biblioteca Padrão C ++.
Nemanja Trifunovic
16
certo. Eu sempre me pergunto por que tantas pessoas ainda chamam de "STL", mesmo que isso sirva para confundir o assunto. seria melhor se mais pessoas são como você e chamá-lo apenas "biblioteca padrão C ++" ou STL e dizer "padrão Library" :)
Johannes Schaub - litb
27

Já faz um tempo e não me lembro qual livro me ensinou esse algoritmo, mas achei que era bastante engenhoso e simples de entender:

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);
karlphillip
fonte
É uma variação interessante, sim. Tecnicamente deve ser um size_tpensamento.
Pryftan
24

Use o método std :: reverse do STL :

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

Você precisará incluir a biblioteca "algoritmo" #include<algorithm>,.

user2628229
fonte
1
Qual biblioteca precisa ser incluída?
quer tocar hoje? Don
#include <algorithm> eu esqueci de escrever e, em seguida, editado a resposta, mas que não era salvo, é por isso que o nome estava faltando ..
user2628229
Embora essa também tenha sido a minha resposta, apenas curiosa, porque o OP pediu "sem um buffer para manter a string invertida" (basicamente, troca no local), como provar que isso é verdade? Basta explicar que ele usa internamente std :: iter_swap <>, iterando até o ponto médio do buffer de ambos os pontos finais? Além disso, OP pediu tanto para C e C ++, isto é só para C ++ (podemos apenas esperar <string.h> tem strrev método ()?)
HidekiAI
21

Note que a beleza do std :: reverse é que ele trabalha com char *strings std::wstringes tão bem quanto std::strings

void strrev(char *str)
{
    if (str == NULL)
        return;
    std::reverse(str, str + strlen(str));
}
Eclipse
fonte
1
Por um lado, quero vomitar porque você usou C ++, mas por outro lado é uma coisa linda, linda e absolutamente linda ver alguém usar C ++ que não coloca *o tipo pelo tipo e o coloca pelo nome. Maravilhoso. Admito que sou purista, mas me encolho toda vez que vejo código char* str;.
Pryftan
11

Se você estiver procurando por inverter buffers terminados em NULL, a maioria das soluções postadas aqui estão OK. Mas, como Tim Farley já apontou, esses algoritmos funcionarão apenas se for válido assumir que uma string é semanticamente uma matriz de bytes (isto é, strings de byte único), o que é uma suposição errada, eu acho.

Tomemos, por exemplo, a string "año" (ano em espanhol).

Os pontos de código Unicode são 0x61, 0xf1, 0x6f.

Considere algumas das codificações mais usadas:

Latin1 / iso-8859-1 (codificação de byte único, 1 caractere é 1 byte e vice-versa):

Original:

0x61, 0xf1, 0x6f, 0x00

Reverter:

0x6f, 0xf1, 0x61, 0x00

O resultado está OK

UTF-8:

Original:

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

Reverter:

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

O resultado é sem sentido e uma sequência UTF-8 ilegal

UTF-16 Big Endian:

Original:

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

O primeiro byte será tratado como um terminador NUL. Nenhuma reversão ocorrerá.

Little Endian UTF-16:

Original:

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

O segundo byte será tratado como um terminador NUL. O resultado será 0x61, 0x00, uma sequência que contém o caractere 'a'.

Juan Pablo Califano
fonte
std :: reverse funcionará para tipos unicode de dois bytes, desde que você esteja usando o wstring.
Eclipse
Eu não estou muito familiarizado com C ++, mas meu palpite é que qualquer função de biblioteca padrão respeitável que lide com strings será capaz de lidar com codificações diferentes, então eu concordo com você. Por "esses algoritmos", eu quis dizer as funções reversas ad-hoc postadas aqui.
Juan Pablo Califano
Infelizmente, não existe "função respeitável que lida com seqüências de caracteres" no C ++ padrão.
Jem
@ Eclipse Se inverter um par substituto, o resultado não estará mais correto. Unicode não é realmente uma largura fixa charset
phuclv
O que eu gosto nessa resposta é que ela mostra a ordem real dos bytes (embora endianness possa ser alguma coisa - ah, eu vejo que você realmente a considerou) e como ela está correta ou incorreta. Mas acho que a resposta seria melhorada se você incorporasse algum código que demonstrasse isso.
Pryftan
11

No interesse da completude, deve-se ressaltar que existem representações de strings em várias plataformas nas quais o número de bytes por caractere varia dependendo do caractere. Os programadores da velha escola se refeririam a isso como DBCS (Double Byte Character Set) . Os programadores modernos costumam encontrar isso em UTF-8 (assim como em UTF-16 e outros). Existem outras codificações também.

Em qualquer um desses esquemas de codificação de largura variável, os algoritmos simples publicados aqui ( maus , não maus ou outros ) não funcionariam corretamente! Na verdade, eles podem até fazer com que a sequência se torne ilegível ou até mesmo uma sequência ilegal nesse esquema de codificação. Veja a resposta de Juan Pablo Califano para alguns bons exemplos.

O potencial std :: reverse () ainda funcionaria nesse caso, desde que a implementação da biblioteca C ++ padrão da plataforma (em particular, iteradores de string) levasse isso em consideração corretamente.

Tim Farley
fonte
6
std :: reverse NÃO leva isso em consideração. Inverte os value_type's. No caso std :: string, ele reverte os caracteres. Não caracteres.
MSalters
Diga antes que nós, programadores da velha escola, conhecemos o DBCS, mas também conhecemos o UTF-8: pois todos sabemos que os programadores são como adictos quando dizem 'mais uma linha e eu vou parar!' Tenho certeza de que alguns programadores acabaram desistindo, mas, francamente, a programação realmente é como um vício para mim; Recebo saques por não programar. É um bom ponto que você adiciona aqui. Eu não gosto de C ++ (tentei realmente gostar mesmo de escrever um pouco, mas ainda é esteticamente desagradável para dizer o mínimo), então não posso comentar lá, mas você faz um bom argumento de qualquer maneira. tem um +1.
Pryftan
5

Outra maneira de C ++ (embora eu provavelmente usaria std :: reverse () :) como sendo mais expressivo e mais rápido)

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

À maneira C (mais ou menos :)) e, por favor, tenha cuidado com o truque do XOR para trocar, os compiladores às vezes não conseguem otimizar isso.

Nesse caso, geralmente é muito mais lento.

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
pprzemek
fonte
Eu usaria strlenpara encontrar o final da string, se for potencialmente longa. Uma boa implementação de biblioteca usará vetores SIMD para pesquisar mais rápido que 1 byte por iteração. Porém, para cadeias muito curtas, while (*++end);isso será feito antes que uma chamada de função da biblioteca comece a pesquisar.
Peter Cordes
@ PeterCordes bem, concordou, strlen deve ser usado de qualquer maneira para facilitar a leitura. Para cordas mais longas, você deve sempre manter o comprimento em um varialbe de qualquer maneira. strlen no SIMD é geralmente dado como exemplo com este aviso, que não é um aplicativo da vida real, ou pelo menos há 5 anos, quando o código foi escrito. ;)
pprzemek 04/04
1
Se você quisesse que isso funcionasse rapidamente em CPUs reais, usaria as embaralhamento SIMD para fazer o inverso em pedaços de 16B. : P, por exemplo, em x86, _mm_shuffle_epi8(PSHUFB) pode reverter a ordem de um vetor 16B, dado o vetor de controle de reprodução aleatória correto. Provavelmente, pode ser executado a uma velocidade quase incorreta com alguma otimização cuidadosa, especialmente com o AVX2.
Peter Cordes
char* beg = s-1tem um comportamento indefinido (pelo menos se saponta para o primeiro elemento de uma matriz, que é o caso mais comum). while (*++end);tem comportamento indefinido se sfor uma sequência vazia.
Melpomene
@pprzemek Bem, você está afirmando que s-1definiu o comportamento mesmo que saponte para o primeiro elemento de uma matriz, então é você quem deve ser capaz de citar o padrão no suporte.
precisa
4
#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;
}

Este código produz esta saída:

gnitset
a
cba

fonte
2
@uvote, Não use strcpy. Sempre. Se você precisar usar algo como strcpy, use strncpy. strcpy é perigoso. A propósito, C e C ++ são duas linguagens separadas, com recursos separados. Eu acho que você está usando arquivos de cabeçalho disponíveis apenas em C ++, então você realmente precisa de uma resposta em C?
Onorio Catenacci
6
strcpy é perfeitamente seguro se o programador puder acompanhar o tamanho de suas matrizes, muitos argumentam que o strncpy é menos seguro, pois não garante que a sequência resultante seja nula. De qualquer forma, não há nada errado com o uso do strcpy pelo uvote aqui.
Robert Gamble
1
@Onorio Catenacci, strcpy não é perigoso se você souber que a string de origem caberá no buffer de destino, como nos casos fornecidos no código acima. Além disso, o strncpy preenche com zero o número de caracteres especificado no parâmetro size se houver espaço sobrando, o que pode não ser desejado.
22680 Chris Young
3
Qualquer um que não pode usar strcpy corretamente não deve ser programando em C.
Robert Gamble
2
@ Robert Gamble, eu concordo. No entanto, como não conheço nenhuma maneira de impedir as pessoas de programar em C, independentemente da sua competência, geralmente recomendo isso.
Onorio Catenacci
3

Eu gosto da resposta K&R da Evgeny. No entanto, é bom ver uma versão usando ponteiros. Caso contrário, é essencialmente o mesmo:

#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;
}
Roubar
fonte
3

Função recursiva para reverter uma string no lugar (sem buffer extra, malloc).

Código curto e sexy. Mau, mau uso da pilha.

#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;
}
Simon Peverett
fonte
1
Essa é uma solução bastante divertida, você deve adicionar alguns rastreamentos, como printf ("% * s> [% d] reverse_r ('% c',% p = \"% s \ ",% p = \"% s \ ") \ n ", profundidade", "profundidade, val, s, (s? s:" nulo "), n, (n? n:" nulo ")); no início e <no final.
Benoît
Empurrar cada um charna pilha não conta como "no lugar". Especialmente quando você está pressionando 4 * 8B por caractere (em uma máquina de 64 bits: 3 args + um endereço de retorno).
Peter Cordes
A pergunta original é "Como você reverte uma string em C ou C ++ sem precisar de um buffer separado para armazenar a string revertida?" - não havia necessidade de trocar 'no lugar'. Além disso, esta solução menciona o uso incorreto da pilha desde o início. Estou sendo rejeitado por causa da falta de compreensão de leitura de outras pessoas?
Simon Peverett
1
Eu não chamaria isso de 'sexy', mas diria que é demonstrativo e instrutivo. Se a recursão for usada corretamente, pode ser muito valiosa. No entanto, deve-se salientar que - pela última vez que eu sabia - C nem sequer exige uma pilha em si; no entanto, faz recursão. De qualquer maneira, é um exemplo de recursão que, se usada corretamente, pode ser muito útil e valiosa. Acho que nunca vi isso reverter uma string.
Pryftan
1

Compartilhe meu código. Como aluno de C ++, como uma opção para usar swap (), estou humildemente pedindo comentários.

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--);
}
Espectral
fonte
1

Se você estiver usando ATL / MFC CString, basta ligar CString::MakeReverse().

Michael Haephrati
fonte
0

Ainda outra:

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

}
Mike Marrotte
fonte
Isso demonstra a aritmética dos ponteiros, muito parecida com a minha resposta, mas a combina com Swap. Acredito que essa resposta acrescenta muito, na verdade. Você deve entender esse tipo de código antes de adicionar um bilhão de bibliotecas como dependências apenas para obter uma caixa de texto simples (algo que eu vejo com muita frequência em aplicativos modernos com os quais trabalho)
Stephen J
0
#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");
}
masakielastic
fonte
0

Com C ++ lambda:

 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;
   };
adem
fonte
0

Minha resposta seria semelhante à maioria deles, mas encontre meu código aqui.

//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;
}
GANESH BK
fonte
0

Eu acho que existe outra maneira de reverter a string. obter a entrada do usuário e inverter.

void Rev() {
    char ch;
    cin.get(ch);
    if(ch != '\n') {
        Rev();
        cout.put(ch);
    }
}
Alok
fonte
É verdade, mas isso apenas imprime a ordem inversa, certo? (Eu não uso C ++, talvez o .put () não faça o que acho que faz).
Pryftan
-1

Se você não precisar armazená-lo, poderá reduzir o tempo gasto assim:

void showReverse(char s[], int length)
{
    printf("Reversed String without storing is ");
    //could use another variable to test for length, keeping length whole.
    //assumes contiguous memory
    for (; length > 0; length--)
    {
        printf("%c", *(s+ length-1) );
    }
    printf("\n");
}
Stephen J
fonte
Eu pareço ser a única resposta que não tem um buffer ou variável de temperatura. Eu uso o comprimento da corda, mas os outros que fazem isso adicionam outra para a cabeça (vs tail). Estou assumindo que a função reversa padrão armazena a variável, por meio de uma troca ou algo assim. Assim, estou com a impressão, assumindo a matemática dos ponteiros e a linha do tipo UTF, que essa é possivelmente a única resposta que realmente responde à pergunta. Os printf () adicionados podem ser retirados, eu apenas fiz isso para parecer melhor com o resultado. Eu escrevi isso para a velocidade. Sem alocações ou vars extras. Provavelmente o algoritmo mais rápido para exibir str () reverso
Stephen J
-3

Aqui está minha opinião sobre C. Fiz isso por prática e tentei ser o mais conciso possível! Você insere uma string via linha de comando, ou seja, ./program_name "insira string aqui"

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

void reverse(int s,int e,int len,char t,char* arg) {
   for(;s<len/2;t=arg[s],arg[s++]=arg[e],arg[e--]=t);
}

int main(int argc,char* argv[]) {
  int s=0,len=strlen(argv[1]),e=len-1; char t,*arg=argv[1];
  reverse(s,e,len,t,arg);
  for(s=0,e=0;e<=len;arg[e]==' '||arg[e]=='\0'?reverse(s,e-1,e+s,t,arg),s=++e:e++);
  printf("%s\n",arg);
}
Kevin Heffernan
fonte
1
É uma bagunça ilegível, mas aparentemente você não está buscando o código mais curto possível ( código golf ) porque alguns nomes de variáveis ​​têm mais de um caractere.
Peter Cordes
-4

Mas acho que o algoritmo de troca XOR é o melhor ...

char str[]= {"I am doing reverse string"};
char* pStr = str;

for(int i = 0; i != ((int)strlen(str)-1)/2; i++)
{
    char b = *(pStr+i);
    *(pStr+i) = *(pStr+strlen(str)-1-i);
    *(pStr+strlen(str)-1-i) = b;
}
Hasenbeck
fonte
Uma chamada para strlen()na condição do loop e no corpo do loop pode não ser otimizada.
Peter Cordes
-5

Aqui está a maneira mais limpa, segura e fácil de reverter uma string em C ++ (na minha opinião):

#include <string>

void swap(std::string& str, int index1, int index2) {

    char temp = str[index1];
    str[index1] = str[index2];
    str[index2] = temp;

}

void reverse(std::string& str) {

    for (int i = 0; i < str.size() / 2; i++)
        swap(str, i, str.size() - i - 1);

}

Uma alternativa é usar std::swap, mas eu gosto de definir minhas próprias funções - é um exercício interessante e você não precisa fazer includenada extra.

Oleksiy
fonte
-5
#include<stdio.h>
#include<conio.h>

int main()
{
    char *my_string = "THIS_IS_MY_STRING";
    char *rev_my_string = my_string;

    while (*++rev_my_string != '\0')
        ;

    while (rev_my_string-- != (my_string-1))
    {
        printf("%c", *rev_my_string);
    }

    getchar();
    return 0;
}

Este é um código otimizado na linguagem C para reverter uma string ... E é simples; basta usar um ponteiro simples para fazer o trabalho ...

Nit kt
fonte
Isso imprime a string, um caractere de cada vez. Não o inverte no local. Ele também aguarda a entrada do usuário sem motivo.
Peter Cordes