Bagaimana Anda membalikkan string di C atau C ++?

173

Bagaimana Anda membalikkan string dalam C atau C ++ tanpa memerlukan buffer terpisah untuk menahan string yang dibalik?

Coding Mash
sumber
17
Kode dalam jawaban yang diterima sangat salah . Lihat stackoverflow.com/a/21263068/88656 untuk detailnya.
Eric Lippert

Jawaban:

123

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 - 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 ) {
    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;
}
  • Mengapa, ya, jika inputnya borked, ini akan riang bertukar di luar tempat.
  • Tautan yang berguna saat melakukan vandalisasi di UNICODE: http://www.macchiato.com/unicode/chart/
  • Juga, UTF-8 lebih dari 0x10000 tidak diuji (karena saya tampaknya tidak memiliki font untuk itu, atau kesabaran untuk menggunakan hexeditor)

Contoh:

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

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

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

./strrev verrts/.
Anders Eurenius
sumber
162
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.
Patrick Schlüter
465
#include <algorithm>
std::reverse(str.begin(), str.end());

Ini adalah cara paling sederhana di C ++.

Greg Rogers
sumber
6
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;
    }
}
Eric Leschinski
sumber
8
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.
Stephen Fox
62

Membalikkan string pada tempatnya (visualisasi):

Membalikkan string di tempatnya

slashdottir
sumber
Keren! Apa yang Anda gunakan untuk membuat ini? Saya pikir jawabannya akan ditingkatkan dengan memasukkan tautan ke sana.
Pryftan
Implementasi dari algoritma ini sebenarnya ada dalam jawaban ini .
karlphillip
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--;
  }
}
Chris Conway
sumber
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.

Nemanja Trifunovic
sumber
14
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:

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);
karlphillip
sumber
Variasi yang menarik ya. Secara teknis seharusnya menjadi size_tsekalipun.
Pryftan
24

Gunakan metode std :: reverse dari STL :

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

Anda harus memasukkan pustaka "algoritma" #include<algorithm>,.

pengguna2628229
sumber
1
Perpustakaan mana yang perlu dimasukkan?
Don Cruickshank
#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

void strrev(char *str)
{
    if (str == NULL)
        return;
    std::reverse(str, str + strlen(str));
}
Gerhana
sumber
1
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'.

Juan Pablo Califano
sumber
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.

Tim Farley
sumber
6
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.

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
pprzemek
sumber
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.
melpomene
4
#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

sumber
2
@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.
Onorio Catenacci
3

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;
}
rampok
sumber
3

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;
}
Simon Peverett
sumber
1
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.
Pryftan
1

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--);
}
Spektral
sumber
1

Jika Anda menggunakan ATL / MFC CString, cukup hubungi CString::MakeReverse().

Michael Haephrati
sumber
0

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);

}
Mike Marrotte
sumber
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)
Stephen J
0
#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");
}
masakielastik
sumber
0

Dengan 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;
   };
adem
sumber
0

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;
}
GANESH BK
sumber
0

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);
    }
}
Alok
sumber
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 memory
    for (; length > 0; length--)
    {
        printf("%c", *(s+ length-1) );
    }
    printf("\n");
}
Stephen J
sumber
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"

#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);
}
Kevin Heffernan
sumber
1
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;
}
Hasenbeck
sumber
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.

Oleksiy
sumber
-5
#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 ...

Nit kt
sumber
Ini mencetak string satu karakter sekaligus. Itu tidak membalikkannya di tempat. Itu juga menunggu input pengguna tanpa alasan.
Peter Cordes