Question

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

Était-ce utile?

La solution

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

(Ceci est une opération d'échange XOR. Prenez soin de noter que vous devez éviter l'échange avec vous-même, car a ^ a == 0.)

Ok, bien, corrigeons les caractères 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;
}
  • Pourquoi, oui, si l'entrée est masquée, elle sera agréablement échangée en dehors de l'endroit.
  • Lien utile en cas de vandalisme dans UNICODE: http://www.macchiato.com/unicode/chart /
  • De plus, UTF-8 sur 0x10000 n’a pas été testé (car je ne semble pas avoir de police pour cela, ni la patience d’utiliser un éditeur de texte)

Exemples:

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

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

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

./strrev verrts/.

Autres conseils

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

C’est la méthode la plus simple en C ++.

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

Inverser une chaîne en place (visualisation):

Inverser une chaîne en place

C non-diabolique, en supposant le cas habituel où la chaîne est un char tableau à zéro terminal:

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

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

Cela faisait longtemps et je ne me souvenais plus du livre qui m'avait appris cet algorithme, mais je pensais qu'il é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);

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

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

Vous devrez inclure le " algorithme " bibliothèque, #include<algorithm>.

Notez que la beauté de std :: reverse réside dans le fait qu’il fonctionne avec les chaînes char * et std::wstring aussi bien que std::string s

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

Si vous recherchez une inversion des mémoires tampon terminées par NULL, la plupart des solutions publiées ici sont correctes. Mais, comme Tim Farley l’a déjà fait remarquer, 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 hypothèse erronée, à mon avis.

Prenons par exemple la chaîne & "a" & # 241; 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 correspond à 1 octet et inversement):

  

Original:

     

0x61, 0xf1, 0x6f, 0x00

     

Inverser:

     

0x6f, 0xf1, 0x61, 0x00

     

Le résultat est correct

UTF-8:

  

Original:

     

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

     

Inverser:

     

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

     

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

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".

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

Dans l’un de ces schémas de codage à largeur variable, les algorithmes simples publiés ici ( mal , non-diabolique ou sinon ) ne fonctionnerait pas du tout correctement! En fait, ils pourraient même rendre la chaîne illisible ou même illégale dans ce schéma de codage. Voir réponse de Juan Pablo Califano pour quelques bons exemples.

std :: reverse () pourrait éventuellement encore fonctionner dans ce cas, à condition que l'implémentation de la bibliothèque Standard C ++ de votre plate-forme (en particulier les itérateurs de chaînes) en tienne dûment compte.

#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

Un autre moyen C ++ (bien que j'utiliserais probablement std :: reverse () moi-même :) comme étant plus expressif et plus rapide)

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

La voie 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

Si vous utilisez GLib, il a deux fonctions, g_strreverse () et g_utf8_strreverse ()

J'aime bien la réponse K & et R de 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;
}

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

Code court et sexy. Mauvaise, 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;
}

Utilisez std::reverse()

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

Et c'est tout.

Partagez mon code. En tant qu'apprenant C ++, pour pouvoir 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--);
}

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

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

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

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

Ma réponse serait semblable à la plupart d'entre elles, mais retrouvez 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;
}

Je pense qu’il existe un autre moyen d’inverser la chaîne. obtenir la contribution de l'utilisateur et l'inverser.

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

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

Voici mon point de vue sur C. Je l’ai fait pour s’entraîner et pour être aussi concis que possible! Vous entrez une chaîne via la ligne de commande, c'est-à-dire ./nom_programme & "Entrez la chaîne ici &";

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

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;
}
#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 un code optimisé en langage C pour inverser une chaîne ... Et c’est simple; utilisez simplement un pointeur pour faire le travail ...

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 bien définir mes propres fonctions. C'est un exercice intéressant et vous n'avez pas besoin de include rien d'extra.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top