反転した文字列を保持するために別のバッファを必要とせずに、CまたはC++で文字列を反転するにはどうすればよいですか?
邪悪な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;
}
(これはXORスワップです。a^ a == 0であるため、selfとのスワップを避ける必要があることに注意してください。)
#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;
}
例:
$ ./strrev Räksmörgås ░▒▓○◔◑◕●
░▒▓○◔◑◕● ●◕◑◔○▓▒░
Räksmörgås sågrömskäR
./strrev verrts/.
#include <algorithm>
std::reverse(str.begin(), str.end());
これは、C++で最も簡単な方法です。
カーニハンとリッチーを読む
#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;
}
}
所定の位置に文字列を反転します(視覚化):
悪意のないC。文字列がnullで終わるchar
配列である一般的なケースを想定しています。
#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--;
}
}
C++標準ライブラリの std::reverse
アルゴリズムを使用します。
しばらく経ち、どのアルゴリズムがこのアルゴリズムを教えてくれたか覚えていませんが、非常に独創的で理解しやすいと思いました。
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);
STL のstd :: reverseメソッドを使用します。
std::reverse(str.begin(), str.end());
「アルゴリズム」ライブラリ#include<algorithm>
を含める必要があります。
Std :: reverseの美しさは、char *
sと同様にstd::wstring
文字列とstd::string
sで動作することです。
void strrev(char *str)
{
if (str == NULL)
return;
std::reverse(str, str + strlen(str));
}
完全を期すために、文字ごとのバイト数varies文字に応じて。昔ながらのプログラマーはこれを DBCS(Double Byte Character Set) と呼んでいたでしょう。現代のプログラマは、より一般的に TF-8 (および TF-16 など)でこれに遭遇します。他にもこのようなエンコーディングがあります。
これらの可変幅エンコーディングスキームのいずれにおいても、ここに掲載されている単純なアルゴリズム( evil 、 non-evil または otherwise )は、すべて!実際、これらのコード体系では、文字列が判読不能になったり、不正な文字列になったりする可能性さえあります。良い例については、 Juan Pablo Califanoの答え をご覧ください。
プラットフォームの標準C++ライブラリ(特に文字列イテレータ)の実装がこれを適切に考慮している限り、std :: reverse()はこの場合でも潜在的に機能します。
NULLで終端されたバッファの反転を探している場合、ここに投稿されているほとんどのソリューションは問題ありません。しかし、ティム・ファーリーがすでに指摘したように、これらのアルゴリズムは、文字列が意味的にバイトの配列(つまりシングルバイト文字列)であると仮定することが有効である場合にのみ機能します。
たとえば、文字列「año」(スペイン語の年)を考えます。
Unicodeコードポイントは0x61、0xf1、0x6fです。
最も使用されているエンコードのいくつかを検討してください。
Latin1/iso-8859-1(シングルバイトエンコーディング、1文字は1バイト、逆も同様):
元の:
0x61、0xf1、0x6f、0x00
逆:
0x6f、0xf1、0x61、0x00
結果はOKです
TF-8:
元の:
0x61、0xc3、0xb1、0x6f、0x00
逆:
0x6f、0xb1、0xc3、0x61、0x00
結果は意味不明で不正なUTF-8シーケンスです
TF-16ビッグエンディアン:
元の:
0x00、0x61、0x00、0xf1、0x00、0x6f、0x00、0x00
最初のバイトはNULターミネータとして扱われます。反転は行われません。
TF-16リトルエンディアン:
元の:
0x61、0x00、0xf1、0x00、0x6f、0x00、0x00、0x00
2番目のバイトはNULターミネータとして扱われます。結果は0x61、0x00、「a」文字を含む文字列になります。
#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;
}
このコードは次の出力を生成します。
gnitset
a
cba
別のC++の方法(私はおそらくstd :: reverse()を自分で使用しますが、より表現力があり、高速であるため)
str = std::string(str.rbegin(), str.rend());
Cの方法(多かれ少なかれ:))そして、スワッピングのXORトリックに注意してください、コンパイラーは時々それを最適化できません。
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
EvgenyのK&Rの回答が好きです。ただし、ポインターを使用したバージョンを見るのは素晴らしいことです。それ以外は、基本的に同じです:
#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;
}
GLibを使用している場合、そのための2つの関数、 g_strreverse() と g_utf8_strreverse() があります。
文字列を所定の位置に反転させる再帰関数(追加のバッファーなし、malloc)。
短く、セクシーなコード。悪い、悪いスタックの使用。
#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;
}
コードを共有します。 C++学習者として、swap()を使用するオプションとして、私は謙虚にコメントを求めています。
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--);
}
ATL/MFC CString
を使用している場合は、単にCString::MakeReverse()
を呼び出します。
C++ラムダの場合:
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;
};
文字列を逆にする別の方法があると思います。ユーザーから入力を取得し、それを逆にします。
void Rev()
{
char ch;
cin.get(ch);
if (ch != '\n')
{
Rev();
cout.put(ch);
}
}
さらに別の:
#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);
}
私の答えはそれらのほとんどに似ていますが、ここで私のコードを見つけてください。
//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");
}