Comment inverser une chaîne en place en C ou C ++?

173

Comment inverser une chaîne en C ou C ++ sans avoir besoin d'un tampon séparé pour contenir la chaîne inversée?

Codage Mash
la source
17
Le code de la réponse acceptée est terriblement faux . Voir stackoverflow.com/a/21263068/88656 pour plus de détails.
Eric Lippert

Réponses:

123

L'algorithme standard consiste à utiliser des pointeurs vers le début / la fin et à les guider vers l'intérieur jusqu'à ce qu'ils se rencontrent ou se croisent au milieu. Échangez au fur et à mesure.


Chaîne ASCII inversée, c'est-à-dire un tableau terminé par 0 où chaque caractère tient dans 1 char. (Ou d'autres jeux de caractères non multi-octets).

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

Le même algorithme fonctionne pour les tableaux d'entiers de longueur connue, utilisez simplement à la tail = start + length - 1place de la boucle de recherche de fin.

(Note de l'éditeur: cette réponse utilisait à l'origine l'échange XOR pour cette version simple également. Corrigé pour le bénéfice des futurs lecteurs de cette question populaire. L' échange XOR est fortement déconseillé ; difficile à lire et la compilation de votre code est moins efficace. Vous peut voir sur l'explorateur du compilateur Godbolt à quel point le corps de la boucle asm est plus compliqué lorsque xor-swap est compilé pour x86-64 avec gcc -O3.)


Ok, très bien, corrigeons les caractères UTF-8 ...

(Ceci est une chose de XOR-swap. Prenez soin de noter que vous devez éviter de permuter avec self, car si *pet *qsont le même emplacement, vous le mettrez à zéro avec un ^ a == 0. XOR-swap dépend d'avoir deux emplacements distincts, en les utilisant chacun comme stockage temporaire.)

Note de l'éditeur: vous pouvez remplacer SWP par une fonction en ligne sûre à l'aide d'une variable 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;
}
  • Pourquoi, oui, si l'entrée est bloquée, cela s'échangera joyeusement à l'extérieur de l'endroit.
  • Lien utile en cas de vandalisme dans UNICODE: http://www.macchiato.com/unicode/chart/
  • De plus, UTF-8 sur 0x10000 n'est pas testé (car je ne semble pas avoir de police pour cela, ni la patience d'utiliser un hexeditor)

Exemples:

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

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

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

./strrev verrts/.
Anders Eurenius
la source
162
Il n'y a aucune bonne raison d'utiliser le swap XOR en dehors d'une compétition de code obscurci.
Chris Conway
28
Vous pensez que «en place» signifie «pas de mémoire supplémentaire», pas même de mémoire O (1) pour les temporaires? Qu'en est-il de l'espace sur la pile pour str et l'adresse de retour?
Chris Conway
55
@Bill, ce n'est pas ce que signifie la définition courante de «sur place». Les algorithmes en place peuvent utiliser de la mémoire supplémentaire. Cependant, la quantité de cette mémoire supplémentaire ne doit pas dépendre de l'entrée - c'est-à-dire qu'elle doit être constante. Par conséquent, l'échange de valeurs à l'aide d'un stockage supplémentaire est entièrement en place.
Konrad Rudolph
19
Ne pas voter jusqu'à ce que le swap xor disparaisse.
Adam Rosenfield
34
L'échange XOR est plus lent que l'échange via un registre sur des processeurs modernes en panne.
Patrick Schlüter
465
#include <algorithm>
std::reverse(str.begin(), str.end());

C'est le moyen le plus simple en C ++.

Greg Rogers
la source
6
En C ++, une chaîne est représentée par la classe de chaînes. Il n'a pas demandé "char star" ou "char brackets". Restez classe, C.
jokoon
10
@fredsbend, la version "ridiculement longue" de la réponse sélectionnée gère un cas que cette réponse simple ne fait pas - l'entrée UTF-8. Cela montre l'importance de bien préciser le problème. En outre, la question portait sur le code qui fonctionnerait également en C.
Mark Ransom
5
Cette réponse gère le cas si vous utilisez une classe de chaînes compatible UTF-8 (ou éventuellement une classe de caractères utf-8 avec std :: basic_string). De plus, la question disait "C ou C ++", pas "C et C ++". C ++ est uniquement "C ou C ++".
Taywee
161

Lire Kernighan et 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
la source
8
Testé sur mon iPhone, c'est plus lent que l'utilisation d'adresses de pointeur brutes d'environ 15%
jjxtra
3
La variable "c" ne devrait-elle pas être un char au lieu d'un int?
Lesswire
17
Il est important de noter dans cet exemple que la chaîne sdoit être déclarée sous forme de tableau. En d'autres termes, char s[] = "this is ok"plutôt que char *s="cannot do this"parce que ce dernier produit une constante de chaîne qui ne peut pas être modifiée
user1527227
3
Avec des excuses au "Parrain" .... "Laissez les armes, apportez le K&R". En tant que bigot en C, j'utiliserais des pointeurs, car ils sont plus simples et plus directs pour ce problème, mais le code serait moins portable en C #, Java, etc.
2
@Eric Cela ne s'exécute pas dans le temps O (log (n)). Il s'exécute en O (n) si vous faites référence au nombre de permutations de caractères que le code effectue, pour n de longueur de chaîne, alors n permutations sont effectuées. Si vous parlez de la quantité de boucles effectuées, alors c'est toujours O (n) - bien que O (n / 2) mais vous supprimez les constantes en notation Big O.
Stephen Fox
62

Inverser une chaîne en place (visualisation):

Inverser une chaîne en place

slashdottir
la source
Cool! Qu'avez-vous utilisé pour créer cela? Je pense que la réponse serait améliorée en incluant un lien vers celui-ci.
Pryftan le
L'implémentation de cet algorithme est en fait dans cette réponse .
karlphillip le
Pouvez-vous expliquer cela un peu, si le lien image meurt, la réponse ne sera pas inutile?
SS Anne
41

Non-evil C, en supposant le cas courant où la chaîne est un chartableau terminé par 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--;
  }
}
Chris Conway
la source
Plutôt que d'utiliser une boucle while pour trouver le pointeur de fin, ne pouvez-vous pas utiliser quelque chose comme end_ptr = str + strlen (str); Je sais que cela fera pratiquement la même chose, mais je trouve cela plus clair.
Peter Kühne
C'est suffisant. J'essayais (et j'échouais) d'éviter l'erreur un par un dans la réponse de @ uvote.
Chris Conway
Mis à part une amélioration potentielle des performances avec peut int temp- être , cette solution semble la meilleure. +1
chux - Réintégrer Monica le
@ chux-ReinstateMonica Oui. C'est beau. Personnellement, je supprimerais les () s du !(*str)bien.
Pryftan le
@ PeterKühne Oui ou strchr()recherche '\0'. J'ai pensé aux deux. Pas besoin de boucle.
Pryftan le
35

Vous utilisez l' std::reversealgorithme de la bibliothèque standard C ++.

Nemanja Trifunovic
la source
14
La bibliothèque de modèles standard est un terme pré-standard. Le standard C ++ ne le mentionne pas et les anciens composants STL se trouvent dans la bibliothèque standard C ++.
Nemanja Trifunovic
16
droite. Je me demande toujours pourquoi tant de gens l'appellent encore "STL" même si cela ne fait que semer la confusion. Ce serait plus agréable si plus de gens sont comme vous et l'appellent simplement "C ++ Standard Library" ou STL et disent "STandard Library" :)
Johannes Schaub - litb
27

Cela fait un moment et je ne me souviens plus quel livre m'a appris cet algorithme, mais j'ai trouvé que c'était assez ingénieux et simple à comprendre:

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
la source
C'est une variante intéressante oui. Cela devrait techniquement être un size_targument.
Pryftan le
24

Utilisez la méthode std :: reverse de STL :

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

Vous devrez inclure la bibliothèque « algorithme », #include<algorithm>.

user2628229
la source
1
Quelle bibliothèque doit être incluse?
Don Cruickshank
#include <algorithm> J'ai oublié de l'écrire, puis j'ai modifié la réponse mais elle n'a pas été enregistrée, c'est pourquoi le nom manquait ..
user2628229
Bien que cela aurait également été ma réponse, juste curieuse, parce que l'OP a demandé "sans tampon pour contenir la chaîne inversée" (essentiellement, échange sur place), comment prouver que c'est le cas? Explique-t-on simplement qu'il utilise en interne std :: iter_swap <>, en itérant jusqu'au milieu du tampon à partir des deux extrémités? De plus, OP a demandé à la fois C et C ++, ce n'est que pour C ++ (pouvons-nous juste espérer que <string.h> a la méthode strrev ()?)
HidekiAI
21

Notez que la beauté de std :: reverse est qu'il fonctionne avec les char *chaînes et std::wstrings aussi bien que std::strings

void strrev(char *str)
{
    if (str == NULL)
        return;
    std::reverse(str, str + strlen(str));
}
Éclipse
la source
1
D'un côté j'ai envie de vomir parce que vous avez utilisé C ++ mais de l'autre c'est une chose magnifique, magnifique, absolument magnifique de voir quelqu'un utiliser C ++ qui ne met pas le *par le type et le met plutôt par son nom. Merveilleux. J'avoue que je suis un peu puriste mais je grince des dents à chaque fois que je vois du code comme char* str;.
Pryftan le
11

Si vous recherchez l'inversion des tampons terminés par NULL, la plupart des solutions publiées ici sont OK. Mais, comme Tim Farley l'a déjà souligné, ces algorithmes ne fonctionneront que s'il est valide de supposer qu'une chaîne est sémantiquement un tableau d'octets (c'est-à-dire des chaînes à un octet), ce qui est une fausse hypothèse, je pense.

Prenons par exemple la chaîne "año" (année en espagnol).

Les points de code Unicode sont 0x61, 0xf1, 0x6f.

Considérez certains des encodages les plus utilisés:

Latin1 / iso-8859-1 (codage sur un octet, 1 caractère équivaut à 1 octet et vice versa):

Original:

0x61, 0xf1, 0x6f, 0x00

Inverser:

0x6f, 0xf1, 0x61, 0x00

Le résultat est OK

UTF-8:

Original:

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

Inverser:

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

Le résultat est du charabia et une séquence UTF-8 illégale

UTF-16 Big Endian:

Original:

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

Le premier octet sera traité comme un terminateur NUL. Aucune inversion n'aura lieu.

UTF-16 Little Endian:

Original:

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

Le deuxième octet sera traité comme un terminateur NUL. Le résultat sera 0x61, 0x00, une chaîne contenant le caractère «a».

Juan Pablo Califano
la source
std :: reverse fonctionnera pour les types Unicode à deux octets, tant que vous utilisez wstring.
Eclipse
Je ne suis pas très familier avec C ++, mais je suppose que toute fonction de bibliothèque standard respectable traitant des chaînes sera capable de gérer différents encodages, donc je suis d'accord avec vous. Par «ces algorithmes», j'entendais les fonctions inverses ad hoc postées ici.
Juan Pablo Califano
Malheureusement, il n'existe pas de "fonction respectable traitant des chaînes" dans le C ++ standard.
Jem
@Eclipse S'il inverse une paire de substitution, le résultat ne sera plus correct. Unicode n'est pas réellement un jeu de caractères à largeur fixe
phuclv
Ce que j'aime dans cette réponse, c'est qu'elle montre l'ordre réel des octets (bien que l'endianité puisse être quelque chose - ah, je vois que vous l'avez effectivement considérée) et comment elle est correcte ou incorrecte. Mais je pense que la réponse serait améliorée si vous incorporiez du code démontrant cela.
Pryftan le
11

Dans un souci d'exhaustivité, il convient de souligner qu'il existe des représentations de chaînes sur différentes plateformes dans lesquelles le nombre d'octets par caractère varie en fonction du caractère. Les programmeurs de la vieille école appelleraient cela DBCS (jeu de caractères à deux octets) . Les programmeurs modernes rencontrent plus souvent cela dans UTF-8 (ainsi que UTF-16 et autres). Il existe également d'autres codages de ce type.

Dans n'importe lequel de ces schémas d'encodage à largeur variable, les algorithmes simples affichés ici ( mauvais , non-mal ou autre ) ne fonctionneraient pas du tout correctement! En fait, ils pourraient même rendre la chaîne illisible ou même une chaîne illégale dans ce schéma de codage. Voir la réponse de Juan Pablo Califano pour quelques bons exemples.

std :: reverse () fonctionnerait potentiellement toujours dans ce cas, tant que l'implémentation de votre plate-forme de la bibliothèque C ++ standard (en particulier les itérateurs de chaînes) en prendrait correctement en compte.

Tim Farley
la source
6
std :: reverse ne prend PAS cela en compte. Il inverse la valeur value_type. Dans le cas std :: string, il inverse char. Pas des personnages.
MSalters
Dites plutôt que nous, les programmeurs de la vieille école, connaissons DBCS, mais connaissons également UTF-8: car nous savons tous que les programmeurs sont comme des toxicomanes quand ils disent «encore une ligne et je vais arrêter! Je suis sûr que certains programmeurs ont fini par arrêter mais franchement, la programmation est vraiment comme une dépendance pour moi; Je reçois des retraits de ne pas programmer. C'est un bon point que vous ajoutez ici. Je n'aime pas le C ++ (j'ai essayé vraiment très fort de l'aimer, même en écrivant un peu mais c'est toujours pour moi esthétiquement peu attrayant pour le moins) donc je ne peux pas commenter là-bas mais vous faites quand même un bon point. avoir un +1.
Pryftan le
5

Une autre façon C ++ (même si j'utiliserais probablement std :: reverse () moi-même :) comme étant plus expressif et plus rapide)

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

La manière C (plus ou moins :)) et s'il vous plaît, faites attention à l'astuce XOR pour l'échange, les compilateurs ne peuvent parfois pas optimiser cela.

Dans ce cas, il est généralement beaucoup plus lent.

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
la source
J'utiliserais strlenpour trouver la fin de la chaîne, si elle est potentiellement longue. Une bonne implémentation de bibliothèque utilisera des vecteurs SIMD pour rechercher plus rapidement que 1 octet par itération. Mais pour les chaînes très courtes, while (*++end);sera effectué avant qu'un appel de fonction de bibliothèque ne commence la recherche.
Peter Cordes
@PeterCordes bien, d'accord, strlen doit être utilisé de toute façon pour la lisibilité. Pour une chaîne plus longue, vous devez toujours garder la longueur dans un varialbe de toute façon. strlen sur SIMD est généralement donné à titre d'exemple avec cette clause de non-responsabilité, qui n'est pas une application réelle, ou du moins c'était il y a 5 ans, lorsque le code a été écrit. ;)
pprzemek
1
Si vous vouliez que cela fonctionne rapidement sur de vrais processeurs, vous utiliseriez des shuffles SIMD pour faire l'inverse en morceaux de 16B. : P par exemple sur x86, _mm_shuffle_epi8(PSHUFB) peut inverser l'ordre d'un vecteur 16B, étant donné le bon vecteur de contrôle de lecture aléatoire. Il peut probablement fonctionner à une vitesse presque memcpy avec une optimisation minutieuse, en particulier avec AVX2.
Peter Cordes
char* beg = s-1a un comportement indéfini (du moins s'il spointe vers le premier élément d'un tableau, ce qui est le cas le plus courant). while (*++end);a un comportement indéfini si sest une chaîne vide.
melpomene
@pprzemek Eh bien, vous faites la réclamation qui s-1a défini le comportement même s'il spointe vers le premier élément d'un tableau, c'est donc vous qui devriez être en mesure de citer le standard à l'appui.
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;
}

Ce code produit cette sortie:

gnitset
a
cba

la source
2
@uvote, n'utilisez pas strcpy. Déjà. Si vous devez utiliser quelque chose comme strcpy, utilisez strncpy. strcpy est dangereux. D'ailleurs, C et C ++ sont deux langages distincts avec des fonctionnalités distinctes. Je pense que vous utilisez des fichiers d'en-tête uniquement disponibles en C ++, alors avez-vous vraiment besoin d'une réponse en C?
Onorio Catenacci
6
strcpy est parfaitement sûr si le programmeur peut garder une trace de la taille de ses tableaux, beaucoup diront que strncpy est moins sûr car il ne garantit pas que la chaîne résultante est terminée par null. Dans tous les cas, il n'y a rien de mal à utiliser strcpy par uvote ici.
Robert Gamble
1
@Onorio Catenacci, strcpy n'est pas dangereux si vous savez que la chaîne source rentrera dans le tampon de destination, comme dans les cas donnés dans le code ci-dessus. De plus, strncpy se remplit à zéro jusqu'au nombre de caractères spécifié dans le paramètre size s'il reste de la place, ce qui peut ne pas être souhaité.
Chris Young
3
Quiconque ne peut pas utiliser strcpy correctement ne devrait pas programmer en C.
Robert Gamble
2
@Robert Gamble, je suis d'accord. Cependant, comme je ne connais aucun moyen d'empêcher les gens de programmer en C, quelle que soit leur compétence, je déconseille généralement cela.
Onorio Catenacci
3

J'aime la réponse K&R d'Evgeny. Cependant, il est agréable de voir une version utilisant des pointeurs. Sinon, c'est essentiellement la même chose:

#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;
}
Rob
la source
3

Fonction récursive pour inverser une chaîne en place (pas de tampon supplémentaire, malloc).

Code court et sexy. Mauvaise utilisation de la pile.

#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
la source
1
C'est une solution assez amusante, vous devriez ajouter des traces comme printf ("% * s> [% d] reverse_r ('% c',% p = \"% s \ ",% p = \"% s \ ") \ n ", profondeur," ", profondeur, val, s, (s? s:" nul "), n, (n? n:" nul ")); au début et <à la fin.
Benoît
Pousser chacun charsur la pile ne compte pas comme «en place». Surtout pas quand vous poussez réellement 4 * 8B par caractère (sur une machine 64 bits: 3 arguments + une adresse de retour).
Peter Cordes
La question d'origine est "Comment inverser une chaîne en C ou C ++ sans avoir besoin d'un tampon séparé pour contenir la chaîne inversée?" - il n'y avait aucune obligation de permuter «en place». En outre, cette solution mentionne la mauvaise utilisation de la pile depuis le début. Suis-je en train d'être voté à cause de la mauvaise compréhension de lecture des autres?
Simon Peverett
1
Je n'appellerais pas ça «sexy» mais je dirais que c'est démonstratif et pédagogique. Si la récursivité est utilisée correctement, elle peut être très précieuse. Cependant, il convient de souligner que - la dernière fois que j'ai su - C ne nécessite même pas une pile en soi; cependant il fait récursion. Quoi qu'il en soit, c'est un exemple de récursivité qui, s'il est utilisé correctement, peut être très utile et précieux. Je ne pense pas que je l'ai déjà vu utilisé pour inverser une chaîne.
Pryftan le
1

Partagez mon code. En tant qu'apprenant C ++, comme option pour utiliser swap (), je demande humblement des commentaires.

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--);
}
Spectral
la source
1

Si vous utilisez ATL / MFC CString, appelez simplement CString::MakeReverse().

Michael Haephrati
la source
0

Encore un autre:

#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
la source
Cela démontre l'arithmétique du pointeur, tout comme ma réponse, mais la combine avec Swap. Je pense que cette réponse ajoute beaucoup, en fait. Vous devriez être capable de comprendre ce type de code avant d'ajouter un milliard de bibliothèques en tant que dépendances juste pour obtenir une zone de texte simple (quelque chose que je vois trop souvent dans les applications modernes avec lesquelles je travaille)
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
la source
0

Avec 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
la source
0

Ma réponse serait similaire à la plupart d'entre eux, mais veuillez trouver mon code ici.

//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
la source
0

Je pense qu'il existe une autre façon d'inverser la chaîne. obtenir l'entrée de l'utilisateur et l'inverser.

void Rev() {
    char ch;
    cin.get(ch);
    if(ch != '\n') {
        Rev();
        cout.put(ch);
    }
}
Alok
la source
C'est vrai mais cela n'imprime que l'ordre inversé, non? (Je n'utilise pas C ++ donc peut-être que .put () ne fait pas ce que je pense).
Pryftan le
-1

Si vous n'avez pas besoin de le stocker, vous pouvez réduire le temps passé comme ceci:

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
la source
Je semble être la seule réponse qui n'a pas de tampon ou de variable temporaire. J'utilise la longueur de la chaîne, mais les autres qui font cela en ajoutent une autre pour la tête (vs la queue). Je suppose que la fonction inverse standard stocke la variable, via un échange ou quelque chose. Ainsi, j'ai l'impression, en supposant que les mathématiques du pointeur et le type UTF s'alignent, que c'est peut-être la seule réponse qui répond réellement à la question. Les printf () ajoutés peuvent être retirés, je l'ai juste fait pour mieux voir le résultat. J'ai écrit ceci pour la vitesse. Pas d'allocations ou de vars supplémentaires. Probablement l'algorithme le plus rapide pour afficher str inversé ()
Stephen J
-3

Voici mon point de vue sur C. Je l'ai fait pour la pratique et j'ai essayé d'être aussi concis que possible! Vous entrez une chaîne via la ligne de commande, c'est-à-dire ./program_name "enter string here"

#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
la source
1
C'est un gâchis illisible, mais vous n'allez apparemment pas pour le code le plus court possible ( code golf ) parce que certains noms de variables sont plus d'un caractère.
Peter Cordes
-4

Mais je pense que l'algorithme d'échange XOR est le meilleur ...

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
la source
Un appel à strlen()dans la condition de boucle et dans le corps de la boucle peut ne pas être optimisé.
Peter Cordes
-5

Voici le moyen le plus propre, le plus sûr et le plus simple d'inverser une chaîne en C ++ (à mon avis):

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

}

Une alternative est d'utiliser std::swap, mais j'aime définir mes propres fonctions - c'est un exercice intéressant et vous n'avez besoin de includerien de plus.

Oleksiy
la source
-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;
}

C'est du code optimisé en langage C pour inverser une chaîne ... Et c'est simple; utilisez simplement un simple pointeur pour faire le travail ...

Nit kt
la source
Cela imprime la chaîne un caractère à la fois. Il ne l'inverse pas en place. Il attend également l'entrée de l'utilisateur sans raison.
Peter Cordes