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 firstfor(; head < tail;++head,--tail){// walk pointers inwards until they meet or cross in the middlechar 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);return0;}
Algoritma yang sama berfungsi untuk array integer dengan panjang yang diketahui, cukup gunakan tail = start + length - 1sebagai 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.)
Ok, baiklah, mari kita perbaiki karakter UTF-8 ...
(Ini adalah XOR-swap. Berhati-hatilah untuk mencatat bahwa Anda harus menghindari bertukar dengan diri sendiri, karena jika *pdan *qberada 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){case0xF:/* U+010000-U+10FFFF: four bytes. */
SWP(*(q-0),*(q-3));
SWP(*(q-1),*(q-2));
q -=3;break;case0xE:/* U+000800-U+00FFFF: three bytes. */
SWP(*(q-0),*(q-2));
q -=2;break;case0xC:/* fall-through */case0xD:/* 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);return0;}
Mengapa, ya, jika inputnya borked, ini akan riang bertukar di luar tempat.
Tidak ada alasan yang baik untuk menggunakan swap XOR di luar kompetisi kode yang dikaburkan.
Chris Conway
28
Anda pikir "di tempat" berarti "tidak ada memori tambahan", bahkan tidak O (1) memori untuk sementara? Bagaimana dengan ruang di stack untuk str dan alamat pengirim?
Chris Conway
55
@ Bill, bukan itu yang dimaksud dengan definisi umum "di tempat". Algoritma in-place dapat menggunakan memori tambahan. Namun, jumlah memori tambahan ini tidak boleh bergantung pada input - yaitu harus konstan. Oleh karena itu, pertukaran nilai menggunakan penyimpanan tambahan benar-benar dilakukan.
Konrad Rudolph
19
Tidak membatalkan ini sampai swap xor hilang.
Adam Rosenfield
34
Swapping XOR lebih lambat daripada swapping melalui register pada prosesor modern out-of-order.
Dalam C ++ string diwakili oleh kelas string. Dia tidak meminta "bintang char" atau "kurung char". Tetap berkelas, C.
jokoon
10
@ fredsbend, versi "sangat panjang" dari jawaban yang dipilih menangani kasus yang jawaban sederhana ini tidak - input UTF-8. Ini menunjukkan pentingnya menentukan masalah secara penuh. Selain itu pertanyaannya adalah tentang kode yang akan bekerja di C juga.
Mark Ransom
5
Jawaban ini tidak menangani kasus ini jika Anda menggunakan kelas string UTF-8 aware (atau mungkin kelas karakter utf-8 dengan std :: basic_string). Selain itu, pertanyaannya adalah "C atau C ++", bukan "C dan C ++". C ++ saja adalah "C atau C ++".
Taywee
161
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;}}
Diuji pada iphone saya ini lebih lambat daripada menggunakan alamat penunjuk mentah sekitar 15%
jjxtra
3
Tidakkah seharusnya variabel "c" menjadi char bukan int?
Lesswire
17
Penting untuk dicatat dalam contoh ini bahwa string sharus 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
user1527227
3
Dengan meminta maaf kepada "The Godfather" .... "Tinggalkan senjatanya, bawa K&R". Sebagai C fanatik, saya akan menggunakan pointer, karena mereka lebih sederhana dan lebih mudah untuk masalah ini, tetapi kode akan lebih portabel untuk C #, Java, dll.
2
@ Eric Ini tidak berjalan dalam waktu O (log (n)). Ini berjalan di O (n) jika Anda mengacu pada jumlah karakter swap kode melakukan, untuk n dari panjang string, maka n swap dilakukan Jika Anda berbicara tentang jumlah loop yang dilakukan maka masih O (n) - meskipun O (n / 2) tetapi Anda menjatuhkan konstanta dalam notasi O Besar.
Bisakah Anda jelaskan ini sedikit sehingga jika tautan gambar mati jawabannya tidak akan sia-sia?
SS Anne
41
Non-evil C, dengan asumsi kasus umum di mana string adalah chararray 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--;}}
Daripada menggunakan loop sementara untuk menemukan pointer akhir, Anda tidak dapat menggunakan sesuatu seperti end_ptr = str + strlen (str); Saya tahu bahwa secara praktis akan melakukan hal yang sama, tetapi saya merasa lebih jelas.
Peter Kühne
Cukup adil. Saya mencoba (dan gagal) untuk menghindari kesalahan satu-per-satu dalam jawaban @ uvote.
Chris Conway
Selain dari kemungkinan peningkatan kinerja dengan int temp, solusi ini terlihat terbaik. +1
chux - Reinstate Monica
@ chux-ReinstateMonica Ya. Cantiknya. Secara pribadi saya akan menghapus () dari !(*str)olah.
Pryftan
@ PeterKühne Ya atau strchr()mencari '\0'. Saya memikirkan keduanya. Tidak perlu loop.
Pryftan
35
Anda menggunakan std::reversealgoritma dari C ++ Standard Library.
Perpustakaan Templat Standar adalah istilah pra-standar. Standar C ++ tidak menyebutkannya, dan komponen STL sebelumnya ada di Perpustakaan Standar C ++.
Nemanja Trifunovic
16
Baik. Saya selalu bertanya-tanya mengapa begitu banyak orang masih menyebutnya "STL" walaupun itu hanya untuk membingungkan masalah ini. Akan lebih bagus jika banyak orang yang seperti Anda dan menyebutnya hanya "C ++ Standard Library" atau STL dan berkata "Standar Perpustakaan" :)
Johannes Schaub - litb
27
Sudah lama dan saya tidak ingat buku mana yang mengajarkan saya algoritma ini, tapi saya pikir itu cukup cerdik dan mudah dimengerti:
#include <algorithm> Saya lupa menulisnya dan kemudian mengedit jawabannya tetapi tidak disimpan, itu sebabnya nama hilang ..
user2628229
Meskipun ini akan menjadi jawaban saya juga, hanya ingin tahu, karena OP bertanya "tanpa penyangga untuk menahan string terbalik" (pada dasarnya, in-place swap), bagaimana seseorang membuktikan bahwa ini melakukannya? Apakah orang hanya menjelaskan bahwa itu menggunakan internal std :: iter_swap <>, iterasi hingga titik tengah buffer dari kedua titik akhir? Juga, OP bertanya untuk C dan C ++, ini hanya untuk C ++ (dapatkah kita berharap <string.h> memiliki metode strrev ()?)
HidekiAI
21
Perhatikan bahwa keindahan std :: reverse adalah ia bekerja dengan char *string dan std::wstrings sama baiknya dengan std::strings
Di satu sisi saya ingin muntah karena Anda menggunakan C ++ tetapi di sisi lain itu adalah hal yang indah, indah, benar-benar indah untuk melihat seseorang menggunakan C ++ yang tidak *menggunakan tipe dan memasukkannya dengan nama. Hebat. Saya akui saya seorang purist tapi saya merasa ngeri setiap kali saya melihat kode char* str;.
Pryftan
11
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'.
std :: reverse akan bekerja untuk tipe unicode dua-byte, selama Anda menggunakan wstring.
Eclipse
Saya tidak terlalu akrab dengan C ++, tetapi dugaan saya adalah bahwa setiap fungsi perpustakaan standar terhormat yang berurusan dengan string akan dapat menangani pengkodean yang berbeda, jadi saya setuju dengan Anda. Dengan "algoritme ini", maksud saya adalah fungsi terbalik ad-hoc yang diposting di sini.
Juan Pablo Califano
Sayangnya, tidak ada yang namanya "fungsi terhormat berurusan dengan string" dalam standar C ++.
Jem
@Eclipse Jika itu membalikkan pasangan pengganti, hasilnya tidak akan benar lagi. Unicode sebenarnya bukan charset dengan lebar tetap
phuclv
Apa yang saya sukai dari jawaban ini adalah bahwa ia menunjukkan urutan byte yang sebenarnya (meskipun endianness mungkin sesuatu - ah, saya melihat Anda memang mempertimbangkannya) dan bagaimana hal itu benar atau salah. Tapi saya pikir jawabannya akan ditingkatkan jika Anda memasukkan beberapa kode yang menunjukkan ini.
Pryftan
11
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.
std :: reverse TIDAK memperhitungkan ini. Ini membalikkan value_type. Dalam std :: string case, ini membalik karakter char. Bukan karakter.
MSalters
Katakan lebih baik bahwa kita para programmer sekolah lama tahu tentang DBCS tetapi juga tahu tentang UTF-8: karena kita semua tahu bahwa programmer seperti pecandu ketika mereka mengatakan 'satu baris lagi dan saya akan berhenti!' Saya yakin beberapa programmer akhirnya berhenti tetapi terus terang pemrograman benar-benar seperti kecanduan bagi saya; Saya mendapatkan penarikan dari tidak pemrograman. Ini poin bagus yang Anda tambahkan di sini. Saya tidak suka C ++ (saya berusaha sangat keras untuk menyukainya bahkan menulis cukup sedikit tetapi masih bagi saya secara estetika tidak menarik untuk sedikitnya) jadi saya tidak bisa berkomentar di sana tetapi Anda tetap membuat poin yang bagus jadi punya +1.
Pryftan
5
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.
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
Saya akan gunakan strlenuntuk 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.
Peter Cordes
@PeterCordes setuju, setuju, strlen harus digunakan untuk keterbacaan. Untuk string yang lebih panjang, Anda harus selalu menjaga panjangnya dalam sebuah varialbe. strlen pada SIMD biasanya diberikan sebagai contoh dengan penafian ini, itu bukan aplikasi kehidupan nyata, atau setidaknya itu 5 tahun yang lalu, ketika kode itu ditulis. ;)
pprzemek
1
Jika Anda ingin ini berjalan cepat pada CPU nyata, Anda akan menggunakan SIMD shuffles untuk melakukan kebalikan dalam potongan 16B. : P misal pada x86, _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.
Peter Cordes
char* beg = s-1memiliki perilaku yang tidak terdefinisi (setidaknya jika smenunjuk ke elemen pertama array, yang merupakan kasus paling umum). while (*++end);memiliki perilaku tidak terdefinisi jika sstring kosong.
melpomene
@ pprzemek Ya, Anda membuat klaim yang s-1telah mendefinisikan perilaku bahkan jika smenunjuk ke elemen pertama array, jadi Andalah yang seharusnya dapat mengutip standar dalam dukungan.
@uvote, Jangan gunakan strcpy. Pernah. Jika Anda harus menggunakan sesuatu seperti strcpy gunakan strncpy. strcpy berbahaya. Omong-omong C dan C ++ adalah dua bahasa terpisah dengan fasilitas terpisah. Saya pikir Anda menggunakan file header hanya tersedia di C ++ jadi apakah Anda benar-benar membutuhkan jawaban dalam C?
Onorio Catenacci
6
strcpy benar-benar aman jika programmer dapat melacak ukuran array-nya, banyak yang berpendapat bahwa strncpy kurang aman karena tidak menjamin string yang dihasilkan nol diakhiri. Bagaimanapun, tidak ada yang salah dengan penggunaan strcpy di sini.
Robert Gamble
1
@Onorio Catenacci, strcpy tidak berbahaya jika Anda tahu bahwa string sumber akan muat di dalam buffer tujuan, seperti dalam kasus yang diberikan dalam kode di atas. Juga, strncpy nol-mengisi hingga jumlah karakter yang ditentukan dalam parameter ukuran jika ada ruang sisa, yang mungkin tidak diinginkan.
Chris Young
3
Siapa pun yang tidak dapat menggunakan strcpy dengan benar tidak boleh pemrograman dalam C.
Robert Gamble
2
@ Robert Gamble, saya setuju. Namun, karena saya tidak tahu cara apa pun untuk menjaga orang dari pemrograman di C tidak peduli apa kompetensi mereka, saya biasanya merekomendasikan ini.
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");return0;}
aString = argv[1];
printf("String to reverse: %s\n", aString );
reverse_r(*aString, aString, aString+1);
printf("Reversed String: %s\n", aString );return0;}
Itu solusi yang cukup menyenangkan, Anda harus menambahkan beberapa penelusuran seperti printf ("% * s> [% d] reverse_r ('% c',% p = \"% s \ ",% p = \"% s \ ") \ n ", depth," ", depth, val, s, (s? s:" null "), n, (n? n:" null ")); di awal dan <di akhir.
Benoît
Mendorong masing-masing charke 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).
Peter Cordes
Pertanyaan aslinya adalah "Bagaimana Anda membalik string dalam C atau C ++ tanpa memerlukan buffer terpisah untuk menahan string yang dibalik?" - tidak ada persyaratan untuk menukar 'di tempat'. Juga, solusi ini menyebutkan penggunaan tumpukan yang buruk sejak awal. Apakah saya tidak dipilih karena kurangnya kemampuan membaca orang lain?
Simon Peverett
1
Saya tidak akan menyebutnya 'seksi' tetapi saya akan mengatakan bahwa itu demonstratif dan instruksional. Jika rekursi digunakan dengan benar, itu bisa sangat berharga. Namun harus ditunjukkan bahwa - terakhir yang saya tahu - C bahkan tidak memerlukan setumpuk per se; Namun itu memang rekursi. Either way itu contoh rekursi yang jika digunakan dengan benar bisa sangat berguna dan berharga. Saya tidak berpikir saya pernah melihatnya membalik string.
Ini menunjukkan aritmatika pointer, seperti jawaban saya, tetapi menggabungkannya dengan Swap. Saya yakin jawaban ini menambahkan banyak, sebenarnya. Anda harus dapat memahami jenis kode ini sebelum menambahkan satu miliar pustaka sebagai dependensi hanya untuk mendapatkan beberapa kotak teks sederhana (sesuatu yang saya lihat terlalu sering dalam aplikasi modern yang dapat saya gunakan untuk bekerja)
Benar tapi ini hanya mencetak urutan terbalik, kan? (Saya tidak menggunakan C ++ jadi mungkin .put () tidak melakukan apa yang saya pikir).
Pryftan
-1
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 memoryfor(; length >0; length--){
printf("%c",*(s+ length-1));}
printf("\n");}
Saya tampaknya menjadi satu-satunya jawaban yang tidak memiliki buffer, atau variabel temp. Saya menggunakan panjang string, tetapi yang lain melakukan ini menambahkan satu lagi untuk kepala (vs ekor). Saya mengasumsikan fungsi reverse standar menyimpan variabel, melalui swap atau sesuatu. Jadi, saya mendapat kesan, dengan asumsi pointer matematika dan tipe UTF berbaris, bahwa ini mungkin satu-satunya jawaban yang benar-benar menjawab pertanyaan. Printf () yang ditambahkan dapat dihapus, saya hanya melakukannya agar terlihat lebih bagus untuk hasilnya. Saya menulis ini untuk kecepatan. Tidak ada alokasi atau vars tambahan. Mungkin algoritma tercepat untuk menampilkan reverse str ()
Stephen J
-3
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"
Ini adalah kekacauan yang tidak dapat dibaca, tetapi Anda tampaknya tidak mencari kode yang sesingkat mungkin ( golf code ) karena beberapa nama variabel lebih dari satu karakter.
Peter Cordes
-4
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;}
Panggilan ke strlen()dalam kondisi loop dan di tubuh loop mungkin tidak dioptimalkan.
Peter Cordes
-5
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 includeapa pun tambahan.
Ini adalah kode yang dioptimalkan dalam bahasa C untuk membalikkan string ... Dan itu sederhana; cukup gunakan pointer sederhana untuk melakukan pekerjaan ...
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).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.)
Ok, baiklah, mari kita perbaiki karakter UTF-8 ...
(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.
Contoh:
sumber
Ini adalah cara paling sederhana di C ++.
sumber
Baca Kernighan dan Ritchie
sumber
s
harus dideklarasikan dalam bentuk array. Dengan kata lain,char s[] = "this is ok"
alih-alihchar *s="cannot do this"
karena yang terakhir menghasilkan konstanta string yang tidak dapat dimodifikasiMembalikkan string pada tempatnya (visualisasi):
sumber
Non-evil C, dengan asumsi kasus umum di mana string adalah
char
array null-dihentikan :sumber
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.sumber
Sudah lama dan saya tidak ingat buku mana yang mengajarkan saya algoritma ini, tapi saya pikir itu cukup cerdik dan mudah dimengerti:
sumber
size_t
sekalipun.Gunakan metode std :: reverse dari STL :
Anda harus memasukkan pustaka "algoritma"
#include<algorithm>
,.sumber
Perhatikan bahwa keindahan std :: reverse adalah ia bekerja dengan
char *
string danstd::wstring
s sama baiknya denganstd::string
ssumber
*
menggunakan tipe dan memasukkannya dengan nama. Hebat. Saya akui saya seorang purist tapi saya merasa ngeri setiap kali saya melihat kodechar* 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):
UTF-8:
UTF-16 Big Endian:
UTF-16 Little Endian:
sumber
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.
sumber
Cara C ++ lainnya (walaupun saya mungkin akan menggunakan std :: reverse () sendiri :) sebagai lebih ekspresif dan lebih cepat)
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.
sumber
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 jikas
menunjuk ke elemen pertama array, yang merupakan kasus paling umum).while (*++end);
memiliki perilaku tidak terdefinisi jikas
string kosong.s-1
telah mendefinisikan perilaku bahkan jikas
menunjuk ke elemen pertama array, jadi Andalah yang seharusnya dapat mengutip standar dalam dukungan.Kode ini menghasilkan output ini:
sumber
Jika Anda menggunakan GLib, ia memiliki dua fungsi untuk itu, g_strreverse () dan g_utf8_strreverse ()
sumber
Saya suka jawaban K&R Evgeny. Namun, senang melihat versi menggunakan pointer. Kalau tidak, pada dasarnya sama:
sumber
Fungsi rekursif untuk membalikkan string pada tempatnya (tanpa buffer tambahan, malloc).
Kode pendek dan seksi. Buruk, penggunaan tumpukan buruk.
sumber
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).Menggunakan
std::reverse()
reverse(begin(str), end(str));
Dan itu saja.
sumber
Bagikan kode saya. Sebagai pelajar C ++, sebagai opsi untuk menggunakan swap (), saya dengan rendah hati meminta komentar.
sumber
Jika Anda menggunakan ATL / MFC
CString
, cukup hubungiCString::MakeReverse()
.sumber
Dan lagi:
sumber
sumber
Dengan C ++ lambda:
sumber
Jawaban saya akan mirip dengan kebanyakan dari mereka, tetapi tolong temukan kode saya di sini.
sumber
Saya pikir ada cara lain untuk membalikkan string. dapatkan input dari pengguna dan balikkan.
sumber
Jika Anda tidak perlu menyimpannya, Anda dapat mengurangi waktu yang dihabiskan seperti ini:
sumber
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"
sumber
Tapi saya pikir algoritma swap XOR adalah yang terbaik ...
sumber
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):
Alternatifnya adalah menggunakan
std::swap
, tapi saya suka mendefinisikan fungsi saya sendiri - ini adalah latihan yang menarik dan Anda tidak perlu melakukaninclude
apa pun tambahan.sumber
Ini adalah kode yang dioptimalkan dalam bahasa C untuk membalikkan string ... Dan itu sederhana; cukup gunakan pointer sederhana untuk melakukan pekerjaan ...
sumber