it-swarm.com.de

Wie kann eine Zeichenfolge in C oder C++ umgekehrt werden?

Wie kann eine Zeichenfolge in C oder C++ umgekehrt werden, ohne dass ein separater Puffer für die umgekehrte Zeichenfolge erforderlich ist?

163
uvote

Böses 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;
}

(Dies ist eine XOR-Swap-Sache. Achten Sie darauf, dass Sie müssen vermeiden mit sich selbst austauschen, da a ^ a == 0 ist.)


Ok, gut, lasst uns die UTF-8-Zeichen korrigieren ...

#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;
}
  • Wenn ja, wenn der Eingang verzerrt ist, wird dieser fröhlich außerhalb des Platzes ausgetauscht.
  • Nützlicher Link zur Vandalisierung im UNICODE: http://www.macchiato.com/unicode/chart/
  • Auch UTF-8 über 0x10000 wurde nicht getestet (da ich anscheinend keine Schriftart dafür habe oder die Geduld, einen Hexeditor zu verwenden).

Beispiele:

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

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

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

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

Dies ist der einfachste Weg in C++.

446
Greg Rogers

Lesen Sie Kernighan und 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;
    }
}
159
Evgeny

Eine Zeichenfolge umkehren (Visualisierung):

Reverse a string in place

56
slashdottir

Nicht-böses C, wenn der übliche Fall angenommen wird, dass die Zeichenfolge ein mit Null abgeschlossenes char-Array ist:

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

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

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

  end_ptr = str + strlen(str) - 1;

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

Sie verwenden den std::reverse - Algorithmus aus der C++ - Standardbibliothek.

34

Es ist eine Weile her und ich kann mich nicht erinnern, welches Buch mir diesen Algorithmus beigebracht hat, aber ich fand es ziemlich genial und einfach zu verstehen:

char input[] = "moc.wolfrevokcats";

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

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

Verwenden Sie die Methode std :: reverse aus STL :

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

Sie müssen die "algorithm" -Bibliothek #include<algorithm> einschließen.

22
user2628229

Beachten Sie, dass die Besonderheit von std :: reverse darin besteht, dass es mit char *-Zeichenfolgen und std::wstrings genauso gut funktioniert wie mit std::strings

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

Der Vollständigkeit halber sei darauf hingewiesen, dass es auf verschiedenen Plattformen Darstellungen von Strings gibt, in denen die Anzahl der Bytes pro Zeichen variiert abhängig vom Zeichen ist. Alte Programmierer würden dies als DBCS (Double Byte Character Set) bezeichnen. Moderne Programmierer treffen dies häufiger in UTF-8 (sowie UTF-16 und anderen). Es gibt auch andere solche Kodierungen.

In jedem dieser Codierungen mit variabler Breite funktionieren die hier beschriebenen einfachen Algorithmen ( evil , non-evil oder ansonsten ) überhaupt nicht richtig! Sie könnten sogar dazu führen, dass die Zeichenfolge unleserlich wird oder sogar eine ungültige Zeichenfolge in diesem Kodierungsschema. Siehe Juan Pablo Califanos Antwort für einige gute Beispiele.

in diesem Fall könnte std :: reverse () möglicherweise weiterhin funktionieren, sofern dies bei der Implementierung der Standard-C++ - Bibliothek der Plattform (insbesondere bei String-Iteratoren) der Fall ist.

11
Tim Farley

Wenn Sie nach NULL-beendeten Puffern stornieren möchten, sind die meisten hier veröffentlichten Lösungen in Ordnung. Wie Tim Farley bereits angedeutet hat, funktionieren diese Algorithmen jedoch nur, wenn angenommen wird, dass eine Zeichenfolge semantisch ein Byte-Array (d. H. Einzelbyte-Zeichenfolgen) ist, was meiner Meinung nach eine falsche Annahme ist. 

Nehmen Sie zum Beispiel die Zeichenfolge "año" (Jahr auf Spanisch).

Die Unicode-Codepunkte sind 0x61, 0xf1, 0x6f.

Beachten Sie einige der am häufigsten verwendeten Kodierungen:

Latin1/iso-8859-1 (Einzelbyte-Kodierung, 1 Zeichen ist 1 Byte und umgekehrt):

Original:

0x61, 0xf1, 0x6f, 0x00

Umkehren:

0x6f, 0xf1, 0x61, 0x00

Das Ergebnis ist OK

UTF-8:

Original:

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

Umkehren:

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

Das Ergebnis ist Kauderwelsch und eine illegale UTF-8-Sequenz

UTF-16 Big Endian:

Original:

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

Das erste Byte wird als NUL-Terminator behandelt. Es erfolgt kein Rücklauf.

UTF-16 Little Endian:

Original:

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

Das zweite Byte wird als NUL-Terminator behandelt. Das Ergebnis ist 0x61, 0x00, eine Zeichenfolge, die das Zeichen 'a' enthält.

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

Dieser Code erzeugt diese Ausgabe:

gnitset
a
cba
4
uvote

Eine andere C++ - Methode (obwohl ich wahrscheinlich std :: reverse () selbst verwenden würde :), da sie ausdrucksvoller und schneller ist.

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

Der C-Weg (mehr oder weniger :)) Bitte seien Sie vorsichtig mit dem XOR -Trick zum Austauschen. Compiler können das manchmal nicht optimieren.

In diesem Fall ist es normalerweise viel langsamer.

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

Ich mag Evgenys K & R-Antwort. Es ist jedoch schön, eine Version mit Zeigern zu sehen. Ansonsten ist es im Wesentlichen dasselbe:

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

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

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

Falls Sie GLib verwenden, hat es zwei Funktionen dafür: g_strreverse () und g_utf8_strreverse ()

3
dmityugov

Verwenden Sie std::reverse()

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

Und das ist es.

2
Andreas DM

Rekursive Funktion zum Umkehren einer Zeichenfolge (kein zusätzlicher Puffer, Malloc).

Kurzer, sexy Code. Schlechte, schlechte Stapelverwendung. 

#include <stdio.h>

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

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

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

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

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

    return 0;
}
2
Simon Peverett

Teilen Sie meinen Code. Als C++ - Lernender frage ich als Option zur Verwendung von swap () demütig nach Kommentaren.

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

Wenn Sie ATL/MFC CString verwenden, rufen Sie einfach CString::MakeReverse() auf.

1

Mit 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
adem

Ich denke, es gibt eine andere Möglichkeit, die Saite umzukehren. Holen Sie sich die Eingabe vom Benutzer und kehren Sie es um.

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

}

0
Alok

Noch ein anderer:

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

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

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

  while(right-left>=1){

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

  }

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

}
0
Mike Marrotte

Meine Antwort wäre den meisten ähnlich, aber bitte finden Sie meinen Code hier.

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

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

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

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

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

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

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

    free(ret);

    return EXIT_SUCCESS;
}

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

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

    while (pos > -1) {

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

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

    ret[ret_size] = '\0';

    return ret;
}

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