Come si inverte una stringa in atto in C o C ++?


Risposte:


123

L'algoritmo standard prevede l'uso dei puntatori all'inizio / alla fine e li guida verso l'interno fino a quando si incontrano o si incrociano nel mezzo. Scambia mentre vai.


Stringa ASCII inversa, ovvero un array con terminazione 0 in cui ogni carattere rientra in 1 char. (O altri set di caratteri non 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;
}

Lo stesso algoritmo funziona per array di numeri interi con lunghezza nota, basta usare tail = start + length - 1invece il ciclo di ricerca finale.

(Nota del redattore: questa risposta originariamente utilizzava XOR-swap anche per questa versione semplice. Risolto per il beneficio dei futuri lettori di questa domanda popolare. XOR-swap non è altamente raccomandato ; difficile da leggere e rendere la compilazione del codice meno efficiente. può vedere sull'esploratore del compilatore Godbolt quanto è più complicato il corpo del loop asm quando xor-swap viene compilato per x86-64 con gcc -O3.)


Ok, bene, sistemiamo i caratteri UTF-8 ...

(Questo è XOR-swap. Fai attenzione a notare che devi evitare di scambiare con te stesso, perché se *pe *qnella stessa posizione lo azzererai con un ^ a == 0. XOR-swap dipende dall'avere due posizioni distinte, usandoli ciascuno come memoria temporanea.)

Nota dell'editore: puoi sostituire SWP con una funzione inline sicura usando una variabile 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;
}
  • Perché, sì, se l'ingresso è interrotto, questo si scambia allegramente fuori dal luogo.
  • Link utile per atti di vandalismo in UNICODE: http://www.macchiato.com/unicode/chart/
  • Inoltre, UTF-8 su 0x10000 non è testato (poiché non sembra avere alcun font, né la pazienza di usare un hexeditor)

Esempi:

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

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

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

./strrev verrts/.

162
Non ci sono buoni motivi per usare lo scambio XOR al di fuori di una competizione di codice offuscata.
Chris Conway,

28
Pensi che "sul posto" significhi "nessuna memoria aggiuntiva", nemmeno memoria O (1) per i provvisori? Che dire dello spazio nello stack per str e l'indirizzo di ritorno?
Chris Conway,

55
@Bill, non è questo che significa la definizione comune di "sul posto". Gli algoritmi sul posto possono utilizzare memoria aggiuntiva. Tuttavia, la quantità di questa memoria aggiuntiva non deve dipendere dall'input, ovvero deve essere costante. Pertanto, lo scambio di valori utilizzando memoria aggiuntiva è completamente a posto.
Konrad Rudolph,

19
Non effettuare il voto fino a quando lo scambio xor non scompare.
Adam Rosenfield,

34
Lo scambio XOR è più lento dello scambio tramite registro sui moderni processori fuori servizio.
Patrick Schlüter,

465
#include <algorithm>
std::reverse(str.begin(), str.end());

Questo è il modo più semplice in C ++.


6
In C ++ una stringa è rappresentata dalla classe string. Non ha chiesto "char star" o "char brackets". Resta di classe, C.
jokoon

10
@fredsbend, la versione "ridicolmente lunga" della risposta selezionata gestisce un caso in cui questa semplice risposta non è: input UTF-8. Mostra l'importanza di specificare completamente il problema. Inoltre la domanda era sul codice che avrebbe funzionato anche in C.
Mark Ransom,

5
Questa risposta gestisce il caso se si utilizza una classe di stringa consapevole UTF-8 (o possibilmente una classe di caratteri utf-8 con std :: basic_string). Inoltre, la domanda diceva "C o C ++", non "C e C ++". Solo C ++ è "C o C ++".
Taywee,

161

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

8
Testato sul mio iPhone, questo è più lento rispetto all'utilizzo di indirizzi di puntatore non
elaborati

3
La variabile "c" non dovrebbe essere un carattere anziché un int?
Lesswire,

17
È importante notare in questo esempio che la stringa sdeve essere dichiarata in una forma di matrice. In altre parole, char s[] = "this is ok"anziché char *s="cannot do this"perché quest'ultima si
traduca

3
Si scusa con "Il padrino" .... "Lascia le pistole, porta il K&R". Come bigotto C, utilizzerei i puntatori, poiché sono più semplici e più diretti per questo problema, ma il codice sarebbe meno portabile su C #, Java, ecc.

2
@Eric Questo non viene eseguito nel tempo O (log (n)). Funziona in O (n) se ti riferisci al numero di scambi di caratteri che il codice esegue, per n di lunghezza stringa, quindi vengono eseguiti n scambi. Se parliamo della quantità di loop eseguiti, allora è ancora O (n) - anche se O (n / 2) ma lasci cadere le costanti nella notazione Big O.
Stephen Fox,

62

Invertire una stringa in posizione (visualizzazione):

Invertire una stringa in posizione


Freddo! Cosa hai usato per creare questo? Penso che la risposta sarebbe migliorata includendo un link ad essa.
Pryftan,

L'implementazione di questo algoritmo è in realtà in questa risposta .
karlphillip,

Puoi spiegarlo un po ', quindi se il collegamento all'immagine muore la risposta non sarà inutile?
SS Anne

41

C non male, presupponendo il caso comune in cui la stringa è un chararray con terminazione null :

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

Invece di usare un ciclo while per trovare il puntatore finale, non puoi usare qualcosa come end_ptr = str + strlen (str); So che farà praticamente la stessa cosa, ma lo trovo più chiaro.
Peter Kühne,

Giusto. Stavo cercando (e non riuscendo) di evitare l'errore off-by-one nella risposta di @ uvote.
Chris Conway,

A parte un potenziale miglioramento delle prestazioni con forse int temp, questa soluzione sembra migliore. +1
chux - Ripristina Monica il

@ chux-ReinstateMonica Sì. È bellissimo. Personalmente rimuoverei il () s dal !(*str)però.
Pryftan,

@ PeterKühne Sì o strchr()alla ricerca '\0'. Ho pensato a entrambi. Non è necessario un loop.
Pryftan,

35

Si utilizza l' std::reversealgoritmo dalla libreria standard C ++.


14
Standard Template Library è un termine pre-standard. Lo standard C ++ non lo menziona e gli ex componenti STL si trovano nella libreria standard C ++.
Nemanja Trifunovic,

16
giusto. mi chiedo sempre perché così tante persone lo chiamano ancora "STL" anche se serve solo a confondere la questione. sarebbe più bello se più persone fossero come te e la chiamassero solo "C ++ Standard Library" o STL e dicessero "STandard Library" :)
Johannes Schaub - litb

27

È passato un po 'di tempo e non ricordo quale libro mi abbia insegnato questo algoritmo, ma ho pensato che fosse abbastanza ingegnoso e semplice da capire:

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

È una variazione interessante sì. Tecnicamente dovrebbe essere un size_tpensiero.
Pryftan,

24

Utilizzare il metodo std :: reverse da STL :

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

Si dovrà includere la libreria "algoritmo", #include<algorithm>.


1
Quale libreria deve essere inclusa?
Don Cruickshank,

#include <algorithm> Ho dimenticato di scriverlo e poi ho modificato la risposta ma non è stata salvata, ecco perché mancava il nome ..
user2628229

Anche se questa sarebbe stata anche la mia risposta, solo curioso, perché l'OP ha chiesto "senza buffer per contenere la stringa invertita" (fondamentalmente, swap sul posto), come si può dimostrare che ciò sta facendo? Spieghi semplicemente che utilizza internamente std :: iter_swap <>, ripetendo fino al punto medio del buffer da entrambi gli endpoint? Inoltre, OP ha chiesto sia C che C ++, questo è solo per C ++ (possiamo solo sperare che <string.h> abbia il metodo strrev ()?)
HidekiAI

21

Nota che la bellezza di std :: reverse è che funziona con char *stringhe e std::wstrings così come con std::strings

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

1
Da un lato voglio vomitare perché hai usato il C ++ ma dall'altro è una cosa bellissima, bellissima, assolutamente bellissima vedere qualcuno usare il C ++ che non lo mette *per il tipo e piuttosto lo chiama per nome. Meraviglioso. Devo ammettere di essere un purista, ma rabbrividisco ogni volta che vedo un codice simile char* str;.
Pryftan,

11

Se stai cercando di invertire i buffer terminati NULL, la maggior parte delle soluzioni pubblicate qui sono OK. Ma, come ha già sottolineato Tim Farley, questi algoritmi funzioneranno solo se è valido supporre che una stringa sia semanticamente una matrice di byte (ovvero stringhe a byte singolo), il che è un presupposto errato, credo.

Prendiamo ad esempio la stringa "año" (anno in spagnolo).

I punti di codice Unicode sono 0x61, 0xf1, 0x6f.

Considera alcune delle codifiche più utilizzate:

Latin1 / iso-8859-1 (codifica a byte singolo, 1 carattere è 1 byte e viceversa):

Originale:

0x61, 0xf1, 0x6f, 0x00

Inversione:

0x6f, 0xf1, 0x61, 0x00

Il risultato è OK

UTF-8:

Originale:

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

Inversione:

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

Il risultato è incomprensibile e una sequenza UTF-8 illegale

UTF-16 Big Endian:

Originale:

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

Il primo byte verrà trattato come un terminatore NUL. Non si verificherà alcuna inversione.

UTF-16 Little Endian:

Originale:

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

Il secondo byte verrà trattato come un terminatore NUL. Il risultato sarà 0x61, 0x00, una stringa contenente il carattere 'a'.


std :: reverse funzionerà con tipi di unicode a due byte, purché tu stia usando wstring.
Eclipse,

Non ho molta familiarità con C ++, ma la mia ipotesi è che qualsiasi funzione di libreria standard rispettabile che si occupa di stringhe sarà in grado di gestire codifiche diverse, quindi sono d'accordo con te. Con "questi algoritmi" intendevo le funzioni inverse ad hoc pubblicate qui.
Juan Pablo Califano,

Sfortunatamente, nel C ++ standard non esiste una "funzione rispettabile che si occupa delle stringhe".
Jem

@Eclipse Se inverte una coppia surrogata, il risultato non sarà più corretto. Unicode non è in realtà un set di caratteri a larghezza fissa
phuclv

Quello che mi piace di questa risposta è che mostra l'ordinamento effettivo dei byte (anche se l'endianness potrebbe essere qualcosa - ah, vedo che l'hai davvero preso in considerazione) e come sia corretto o errato. Ma penso che la risposta sarebbe migliorata se incorporassi del codice che lo dimostra.
Pryftan,

11

Nell'interesse della completezza, si dovrebbe sottolineare che ci sono rappresentazioni di stringhe su varie piattaforme in cui il numero di byte per carattere varia a seconda del carattere. I programmatori della vecchia scuola si riferirebbero a questo come DBCS (Double Byte Character Set) . I programmatori moderni lo incontrano più comunemente in UTF-8 (così come in UTF-16 e altri). Esistono anche altre codifiche simili.

In uno qualsiasi di questi schemi di codifica a larghezza variabile, i semplici algoritmi pubblicati qui ( male , non male o altro ) non funzionerebbero affatto correttamente! In effetti, potrebbero persino rendere la stringa illeggibile o addirittura una stringa illegale in quello schema di codifica. Vedi la risposta di Juan Pablo Califano per alcuni buoni esempi.

std :: reverse () potenzialmente funzionerebbe comunque in questo caso, fintanto che l'implementazione della tua piattaforma C ++ Library standard (in particolare, iteratori di stringhe) lo terrà correttamente in considerazione.


6
std :: reverse NON ne tiene conto. Inverte value_type's. Nel caso std :: string, inverte il carattere di char. Non personaggi.
MSalters il

Diciamo piuttosto che noi programmatori della vecchia scuola conosciamo DBCS ma anche UTF-8: perché sappiamo tutti che i programmatori sono proprio come tossicodipendenti quando dicono "un'altra riga e me ne andrò!" Sono sicuro che alcuni programmatori alla fine lasceranno, ma francamente la programmazione è davvero una dipendenza per me; Ricevo prelievi dal non programmare. È un buon punto che aggiungi qui. Non mi piace il C ++ (ho provato davvero tanto a farmi piacere anche se ne scrivevo un bel po ', ma per me è ancora esteticamente poco attraente per non dire altro) quindi non posso commentare lì ma tu fai comunque un buon punto quindi avere un +1.
Pryftan,

5

Un altro modo C ++ (anche se probabilmente userei std :: reverse () me stesso :) come più espressivo e più veloce)

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

Nel modo C (più o meno :)) e, per favore, stai attento al trucco XOR per lo scambio, i compilatori a volte non possono ottimizzarlo.

In tal caso, di solito è molto più 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

Userei strlenper trovare la fine della stringa, se è potenzialmente lunga. Una buona implementazione della libreria utilizzerà i vettori SIMD per eseguire ricerche più veloci di 1 byte per iterazione. Ma per stringhe molto brevi, while (*++end);verrà eseguito prima che inizi una ricerca della funzione di libreria.
Peter Cordes,

@PeterCordes bene, d'accordo, strlen dovrebbe essere usato comunque per leggibilità. Per stringhe più lunghe dovresti comunque sempre mantenere la lunghezza in una varialbe. strlen su SIMD è di solito dato come esempio con questo disclaimer, che non è un'applicazione di vita reale, o almeno 5 anni fa, quando il codice è stato scritto. ;)
pprzemek,

1
Se volessi che questo funzionasse velocemente su CPU reali, avresti usato i shuffle SIMD per fare il contrario in blocchi da 16B. : P es. Su x86, _mm_shuffle_epi8(PSHUFB) può invertire l'ordine di un vettore 16B, dato il giusto vettore di controllo shuffle. Probabilmente può funzionare a velocità quasi memcpy con un'attenta ottimizzazione, specialmente con AVX2.
Peter Cordes,

char* beg = s-1ha un comportamento indefinito (almeno se spunta al primo elemento di un array, che è il caso più comune). while (*++end);ha un comportamento indefinito se sè una stringa vuota.
melpomene,

@pprzemek Bene, stai affermando che s-1ha definito il comportamento anche se spunta al primo elemento di un array, quindi sei tu che dovresti essere in grado di citare lo standard nel supporto.
melpomene,

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

Questo codice produce questo output:

gnitset
a
cba

2
@uvote, non usare strcpy. Mai. Se devi usare qualcosa come strcpy usa strncpy. strcpy è pericoloso. A proposito C e C ++ sono due lingue separate con strutture separate. Penso che tu stia utilizzando i file di intestazione disponibili solo in C ++, quindi hai davvero bisogno di una risposta in C?
Onorio Catenacci,

6
strcpy è perfettamente sicuro se il programmatore è in grado di tenere traccia della dimensione dei suoi array, molti sostengono che strncpy è meno sicuro poiché non garantisce che la stringa risultante sia chiusa da null. In ogni caso, non c'è niente di sbagliato nell'uso di strcpy da parte di uvote.
Robert Gamble,

1
@Onorio Catenacci, strcpy non è pericoloso se sai che la stringa di origine si adatterà all'interno del buffer di destinazione, come nei casi indicati nel codice sopra. Inoltre, strncpy azzera fino al numero di caratteri specificato nel parametro size se c'è spazio residuo, che potrebbe non essere desiderato.
Chris Young,

3
Chi non può usare strcpy correttamente non dovrebbe programmare in C.
Robert Gamble il

2
@Robert Gamble, sono d'accordo. Tuttavia, poiché non conosco alcun modo per impedire alle persone di programmare in C, indipendentemente dalla loro competenza, di solito sconsiglio.
Onorio Catenacci,


3

Mi piace la risposta K&R di Evgeny. Tuttavia, è bello vedere una versione usando i puntatori. Altrimenti, è essenzialmente lo stesso:

#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

Funzione ricorsiva per invertire una stringa in atto (nessun buffer aggiuntivo, malloc).

Codice breve e sexy. Cattivo, cattivo utilizzo dello stack.

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

1
È una soluzione abbastanza divertente, dovresti aggiungere qualche traccia come printf ("% * s> [% d] reverse_r ('% c',% p = \"% s \ ",% p = \"% s \ ") \ n ", profondità," ", profondità, val, s, (s? s:" null "), n, (n? n:" null ")); all'inizio e <alla fine.
Benoît,

Spingere ciascuno charsulla pila non conta come "sul posto". Soprattutto quando stai effettivamente spingendo 4 * 8B per personaggio (su una macchina a 64 bit: 3 arg + un indirizzo di ritorno).
Peter Cordes,

La domanda originale è "Come invertire una stringa in C o C ++ senza richiedere un buffer separato per contenere la stringa invertita?" - non era necessario scambiare "sul posto". Inoltre, questa soluzione menziona il cattivo utilizzo dello stack dall'inizio. Sono stato votato in basso a causa della scarsa comprensione della lettura degli altri?
Simon Peverett,

1
Non lo definirei "sexy", ma direi che è dimostrativo e istruttivo. Se la ricorsione viene usata correttamente, può essere molto preziosa. Tuttavia, va sottolineato che - lo sapevo per ultimo - C non richiede nemmeno uno stack di per sé; tuttavia fa ricorsione. In entrambi i casi è un esempio di ricorsione che, se usato correttamente, può essere molto utile e prezioso. Non penso di averlo mai visto usato per invertire una stringa.
Pryftan,


1

Condividi il mio codice. Come studente C ++, come opzione per usare swap (), chiedo umilmente commenti.

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


0

Ancora un altro:

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

}

Questo dimostra l'aritmetica del puntatore, proprio come la mia risposta, ma la combina con Swap. Credo che questa risposta aggiunga molto, in realtà. Dovresti essere in grado di comprendere questo tipo di codice prima di aggiungere un miliardo di librerie come dipendenze solo per ottenere una semplice casella di testo (qualcosa che vedo troppo spesso nelle applicazioni moderne con cui riesco a lavorare)
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");
}

0

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

0

La mia risposta sarebbe simile alla maggior parte di loro, ma per favore trova il mio codice qui.

//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

Penso che ci sia un altro modo per invertire la stringa. ottenere l'input dall'utente e invertirlo.

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

Vero, ma questo stampa solo l'ordine inverso, giusto? (Non uso C ++ quindi forse .put () non fa quello che penso faccia).
Pryftan,

-1

Se non è necessario memorizzarlo, è possibile ridurre il tempo trascorso in questo modo:

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

Mi sembra di essere l'unica risposta che non ha un buffer o una variabile temporanea. Uso la lunghezza della corda, ma le altre che lo fanno aggiungono un'altra per la testa (vs coda). Suppongo che la funzione inversa standard memorizzi la variabile, tramite uno scambio o qualcosa del genere. Pertanto, ho l'impressione, supponendo che la matematica dei puntatori e il tipo UTF siano allineati, che questa è probabilmente l'unica risposta che risponde effettivamente alla domanda. Gli printf () aggiunti possono essere eliminati, l'ho fatto solo per sembrare più bello per il risultato. Ho scritto questo per la velocità. Nessuna allocazione o variazione extra. Probabilmente l'algoritmo più veloce per la visualizzazione di reverse str ()
Stephen J,

-3

Ecco la mia opinione in C. L'ho fatto per la pratica e ho cercato di essere il più conciso possibile! Si immette una stringa tramite la riga di comando, ad es. Nome_programma / "inserire la stringa qui"

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

1
È un pasticcio illeggibile, ma apparentemente non stai cercando il codice più breve possibile ( code golf ) perché alcuni nomi di variabili sono più di un carattere.
Peter Cordes,

-4

Ma penso che l'algoritmo di scambio XOR sia il migliore ...

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

Una chiamata a strlen()nella condizione di loop e nel corpo del loop potrebbe non essere ottimizzata.
Peter Cordes,

-5

Ecco il modo più pulito, più sicuro e più semplice per invertire una stringa in C ++ (secondo me):

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

}

Un'alternativa è usare std::swap, ma mi piace definire le mie funzioni: è un esercizio interessante e non hai bisogno di includenulla in più.


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

Questo è un codice ottimizzato nel linguaggio C per invertire una stringa ... Ed è semplice; basta usare un semplice puntatore per fare il lavoro ...


Questo stampa la stringa un carattere alla volta. Non lo inverte sul posto. Aspetta anche l'input dell'utente senza motivo.
Peter Cordes,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.