Bagaimana Anda membalikkan string dalam C atau C ++ tanpa memerlukan buffer terpisah untuk menahan string yang dibalik?
Bagaimana Anda membalikkan string dalam C atau C ++ tanpa memerlukan buffer terpisah untuk menahan string yang dibalik?
Jawaban:
Algoritma standar adalah dengan menggunakan pointer ke awal / akhir, dan berjalan ke dalam sampai bertemu atau menyeberang di tengah. Tukar saat Anda pergi.
Membalikkan string ASCII, yaitu array yang diakhiri 0 di mana setiap karakter cocok dalam 1 char
. (Atau set karakter non-multibyte lainnya).
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;
}
Algoritma yang sama berfungsi untuk array integer dengan panjang yang diketahui, cukup gunakan tail = start + length - 1
sebagai ganti dari loop penemuan akhir.
(Catatan Editor: jawaban ini awalnya juga menggunakan XOR-swap untuk versi sederhana ini. Diperbaiki untuk kepentingan pembaca masa depan dari pertanyaan populer ini. XOR-swap sangat tidak disarankan ; sulit dibaca dan membuat kompilasi kode Anda kurang efisien. Anda dapat melihat pada Godbolt compiler explorer seberapa rumit body loop asm ketika xor-swap dikompilasi untuk x86-64 dengan gcc -O3.)
(Ini adalah XOR-swap. Berhati-hatilah untuk mencatat bahwa Anda harus menghindari bertukar dengan diri sendiri, karena jika *p
dan *q
berada di lokasi yang sama Anda akan nol dengan ^ a == 0. XOR-swap tergantung pada memiliki dua lokasi yang berbeda, menggunakannya masing-masing sebagai penyimpanan sementara.)
Catatan editor: Anda dapat mengganti SWP dengan fungsi inline aman menggunakan variabel 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;
}
Contoh:
$ ./strrev Räksmörgås ░▒▓○◔◑◕●
░▒▓○◔◑◕● ●◕◑◔○▓▒░
Räksmörgås sågrömskäR
./strrev verrts/.
#include <algorithm>
std::reverse(str.begin(), str.end());
Ini adalah cara paling sederhana di C ++.
Baca Kernighan dan 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;
}
}
s
harus dideklarasikan dalam bentuk array. Dengan kata lain, char s[] = "this is ok"
alih-alih char *s="cannot do this"
karena yang terakhir menghasilkan konstanta string yang tidak dapat dimodifikasi
Membalikkan string pada tempatnya (visualisasi):
Non-evil C, dengan asumsi kasus umum di mana string adalah char
array null-dihentikan :
#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--;
}
}
int temp
, solusi ini terlihat terbaik. +1
!(*str)
olah.
strchr()
mencari '\0'
. Saya memikirkan keduanya. Tidak perlu loop.
Anda menggunakan std::reverse
algoritma dari C ++ Standard Library.
Sudah lama dan saya tidak ingat buku mana yang mengajarkan saya algoritma ini, tapi saya pikir itu cukup cerdik dan mudah dimengerti:
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);
size_t
sekalipun.
Gunakan metode std :: reverse dari STL :
std::reverse(str.begin(), str.end());
Anda harus memasukkan pustaka "algoritma" #include<algorithm>
,.
Perhatikan bahwa keindahan std :: reverse adalah ia bekerja dengan char *
string dan std::wstring
s sama baiknya dengan std::string
s
void strrev(char *str)
{
if (str == NULL)
return;
std::reverse(str, str + strlen(str));
}
*
menggunakan tipe dan memasukkannya dengan nama. Hebat. Saya akui saya seorang purist tapi saya merasa ngeri setiap kali saya melihat kode char* str;
.
Jika Anda mencari untuk membalikkan buffer NULL yang dihentikan, sebagian besar solusi yang diposting di sini OK. Tetapi, seperti yang ditunjukkan Tim Farley, algoritma ini hanya akan berfungsi jika valid untuk mengasumsikan bahwa string adalah semantik array byte (yaitu string byte tunggal), yang merupakan asumsi yang salah, saya pikir.
Ambil contoh, string "año" (tahun dalam bahasa Spanyol).
Poin kode Unicode adalah 0x61, 0xf1, 0x6f.
Pertimbangkan beberapa pengkodean yang paling sering digunakan:
Latin1 / iso-8859-1 (pengodean byte tunggal, 1 karakter 1 byte dan sebaliknya):
Asli:
0x61, 0xf1, 0x6f, 0x00
Balik:
0x6f, 0xf1, 0x61, 0x00
Hasilnya OK
UTF-8:
Asli:
0x61, 0xc3, 0xb1, 0x6f, 0x00
Balik:
0x6f, 0xb1, 0xc3, 0x61, 0x00
Hasilnya adalah omong kosong dan urutan UTF-8 ilegal
UTF-16 Big Endian:
Asli:
0x00, 0x61, 0x00, 0xf1, 0x00, 0x6f, 0x00, 0x00
Byte pertama akan diperlakukan sebagai terminator NUL. Tidak akan terjadi pembalikan.
UTF-16 Little Endian:
Asli:
0x61, 0x00, 0xf1, 0x00, 0x6f, 0x00, 0x00, 0x00
Byte kedua akan diperlakukan sebagai NUL-terminator. Hasilnya adalah 0x61, 0x00, string yang berisi karakter 'a'.
Untuk kepentingan kelengkapan, harus ditunjukkan bahwa ada representasi string pada berbagai platform di mana jumlah byte per karakter bervariasi tergantung pada karakter. Pemrogram lama akan menyebutnya sebagai DBCS (Double Byte Character Set) . Programmer modern lebih sering menemukan ini di UTF-8 (serta UTF-16 dan lainnya). Ada pengkodean seperti itu juga.
Dalam skema pengodean lebar variabel mana pun, algoritme sederhana yang diposkan di sini ( jahat , tidak-jahat, atau sebaliknya ) tidak akan berfungsi dengan benar sama sekali! Bahkan, mereka bahkan dapat menyebabkan string menjadi tidak terbaca atau bahkan string ilegal dalam skema pengkodean itu. Lihat jawaban Juan Pablo Califano untuk beberapa contoh yang bagus.
std :: reverse () berpotensi masih akan bekerja dalam kasus ini, selama implementasi platform Anda dari Pustaka C ++ Standar (khususnya, string iterators) dengan benar mempertimbangkan hal ini.
Cara C ++ lainnya (walaupun saya mungkin akan menggunakan std :: reverse () sendiri :) sebagai lebih ekspresif dan lebih cepat)
str = std::string(str.rbegin(), str.rend());
Cara C (kurang lebih :)) dan tolong, hati-hati tentang trik XOR untuk bertukar, kompiler kadang-kadang tidak dapat mengoptimalkan itu.
Dalam kasus seperti itu biasanya jauh lebih lambat.
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
strlen
untuk menemukan ujung string, jika berpotensi panjang. Implementasi perpustakaan yang baik akan menggunakan vektor SIMD untuk mencari lebih cepat dari 1 byte per iterasi. Tetapi untuk string yang sangat singkat, while (*++end);
akan dilakukan sebelum panggilan fungsi perpustakaan mulai mencari.
_mm_shuffle_epi8
(PSHUFB) dapat membalik urutan vektor 16B, mengingat vektor kendali acak yang tepat. Itu mungkin dapat berjalan pada kecepatan hampir memcpy dengan beberapa optimasi hati-hati, terutama dengan AVX2.
char* beg = s-1
memiliki perilaku yang tidak terdefinisi (setidaknya jika s
menunjuk ke elemen pertama array, yang merupakan kasus paling umum). while (*++end);
memiliki perilaku tidak terdefinisi jika s
string kosong.
s-1
telah mendefinisikan perilaku bahkan jika s
menunjuk ke elemen pertama array, jadi Andalah yang seharusnya dapat mengutip standar dalam dukungan.
#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;
}
Kode ini menghasilkan output ini:
gnitset
a
cba
Jika Anda menggunakan GLib, ia memiliki dua fungsi untuk itu, g_strreverse () dan g_utf8_strreverse ()
Saya suka jawaban K&R Evgeny. Namun, senang melihat versi menggunakan pointer. Kalau tidak, pada dasarnya sama:
#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;
}
Fungsi rekursif untuk membalikkan string pada tempatnya (tanpa buffer tambahan, malloc).
Kode pendek dan seksi. Buruk, penggunaan tumpukan buruk.
#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;
}
char
ke tumpukan tidak dihitung sebagai "di tempat". Terutama tidak ketika Anda benar-benar mendorong 4 * 8B per karakter (pada mesin 64-bit: 3 args + alamat pengirim).
Bagikan kode saya. Sebagai pelajar C ++, sebagai opsi untuk menggunakan swap (), saya dengan rendah hati meminta komentar.
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--);
}
Jika Anda menggunakan ATL / MFC CString
, cukup hubungi CString::MakeReverse()
.
Dan lagi:
#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");
}
Jawaban saya akan mirip dengan kebanyakan dari mereka, tetapi tolong temukan kode saya di sini.
//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;
}
Saya pikir ada cara lain untuk membalikkan string. dapatkan input dari pengguna dan balikkan.
void Rev() {
char ch;
cin.get(ch);
if(ch != '\n') {
Rev();
cout.put(ch);
}
}
Jika Anda tidak perlu menyimpannya, Anda dapat mengurangi waktu yang dihabiskan seperti ini:
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");
}
Inilah pendapat saya tentang hal itu dalam C. Melakukannya untuk latihan dan berusaha sesingkat mungkin! Anda memasukkan string melalui baris perintah, yaitu ./program_name "masukkan string di sini"
#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);
}
Tapi saya pikir algoritma swap XOR adalah yang terbaik ...
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;
}
strlen()
dalam kondisi loop dan di tubuh loop mungkin tidak dioptimalkan.
Berikut ini cara paling bersih, teraman, dan termudah untuk membalikkan string dalam C ++ (menurut saya):
#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);
}
Alternatifnya adalah menggunakan std::swap
, tapi saya suka mendefinisikan fungsi saya sendiri - ini adalah latihan yang menarik dan Anda tidak perlu melakukan include
apa pun tambahan.
#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;
}
Ini adalah kode yang dioptimalkan dalam bahasa C untuk membalikkan string ... Dan itu sederhana; cukup gunakan pointer sederhana untuk melakukan pekerjaan ...