Wie kann eine Zeichenfolge in C oder C++ umgekehrt werden, ohne dass ein separater Puffer für die umgekehrte Zeichenfolge erforderlich ist?
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.)
#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;
}
Beispiele:
$ ./strrev Räksmörgås ░▒▓○◔◑◕●
░▒▓○◔◑◕● ●◕◑◔○▓▒░
Räksmörgås sågrömskäR
./strrev verrts/.
#include <algorithm>
std::reverse(str.begin(), str.end());
Dies ist der einfachste Weg in C++.
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;
}
}
Eine Zeichenfolge umkehren (Visualisierung):
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--;
}
}
Sie verwenden den std::reverse
- Algorithmus aus der C++ - Standardbibliothek.
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);
Verwenden Sie die Methode std :: reverse aus STL :
std::reverse(str.begin(), str.end());
Sie müssen die "algorithm" -Bibliothek #include<algorithm>
einschließen.
Beachten Sie, dass die Besonderheit von std :: reverse darin besteht, dass es mit char *
-Zeichenfolgen und std::wstring
s genauso gut funktioniert wie mit std::string
s
void strrev(char *str)
{
if (str == NULL)
return;
std::reverse(str, str + strlen(str));
}
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.
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.
#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
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
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;
}
Falls Sie GLib verwenden, hat es zwei Funktionen dafür: g_strreverse () und g_utf8_strreverse ()
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;
}
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--);
}
Wenn Sie ATL/MFC CString
verwenden, rufen Sie einfach CString::MakeReverse()
auf.
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;
};
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);
}
}
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);
}
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;
}
#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");
}