आप C या C ++ में एक स्ट्रिंग को कैसे उल्टा करते हैं?


173

आप उल्टे स्ट्रिंग को पकड़ने के लिए एक अलग बफर की आवश्यकता के बिना C या C ++ में एक स्ट्रिंग को कैसे रिवर्स करते हैं?


17
स्वीकृत उत्तर में कोड गलत है । देखें stackoverflow.com/a/21263068/88656 जानकारी के लिए।
एरिक लिपर्ट

जवाबों:


123

मानक एल्गोरिथ्म प्रारंभ / अंत तक पॉइंटर्स का उपयोग करना है, और जब तक वे बीच में मिलते हैं या पार नहीं करते हैं, तब तक वे अंदर की ओर चलते हैं। जाते ही स्वैप करें।


ASCII स्ट्रिंग, यानी 0-टर्मिनेटेड ऐरे जहां प्रत्येक वर्ण 1 में फिट बैठता है char। (या अन्य गैर-मल्टीबैट चरित्र सेट)।

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

एक ही एल्गोरिथ्म ज्ञात लंबाई के साथ पूर्णांक सरणियों के लिए काम करता है, बस उपयोग करें tail = start + length - 1 अंत-खोज लूप के बजाय ।

(संपादक का ध्यान दें: इस उत्तर ने मूल रूप से इस साधारण संस्करण के लिए भी XOR- स्वैप का उपयोग किया है, इस लोकप्रिय प्रश्न के भविष्य के पाठकों के लाभ के लिए निश्चित है। XOR- स्वैप की अत्यधिक अनुशंसा नहीं की जाती है ; अपने कोड को कम कुशलता से पढ़ने और बनाने में मुश्किल है। आप Godbolt कंपाइलर एक्सप्लोरर पर देख सकते हैं कि asm लूप बॉडी कितना अधिक जटिल है जब x86-64 के लिए gcc -O3 के साथ xor- स्वैप संकलित किया जाता है।)


ठीक है, ठीक है, चलो यूटीएफ -8 चार्ट को ठीक करें ...

(यह XOR-स्वैप बात है। टिप्पणी करने के लिए ध्यान रखना है कि आप से बचना चाहिए स्वयं के साथ अदला-बदली, अगर क्योंकि *pऔर *qएक ही स्थान हैं आप एक ^ एक == 0। XOR-स्वैप दो अलग-अलग स्थानों पर निर्भर करता साथ यह शून्य होगा, अस्थायी भंडारण के रूप में प्रत्येक का उपयोग करना।)

संपादक का नोट: आप एक tmp वैरिएबल का उपयोग करके SWP को एक सुरक्षित इनलाइन फ़ंक्शन से बदल सकते हैं।

#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;
}
  • क्यों, हाँ, अगर इनपुट बोर्क किया गया है, तो यह जगह के बाहर झूल जाएगा।
  • उपयोगी लिंक जब UNICODE में बर्बरता कर रहा है: http://www.macchiato.com/unicode/chart/
  • इसके अलावा, 0x10000 से अधिक यूटीएफ -8 अप्रयुक्त है (जैसा कि मुझे इसके लिए कोई फॉन्ट नहीं लगता है, न ही हेक्सिडिटर का उपयोग करने का धैर्य है)

उदाहरण:

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

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

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

./strrev verrts/.

162
एक मोटे कोड प्रतियोगिता के बाहर XOR स्वैप का उपयोग करने का कोई अच्छा कारण नहीं है।
क्रिस कॉनवे

28
आपको लगता है कि "इन-प्लेस" का अर्थ है "नो एक्स्ट्रा मेमोरी", टेम्परेरी के लिए O (1) मेमोरी भी नहीं? स्टैक और वापसी पते के लिए स्टैक पर जगह के बारे में क्या?
क्रिस कॉनवे

55
@ बिल, यह "इन-प्लेस" की सामान्य परिभाषा का मतलब नहीं है। इन-प्लेस एल्गोरिदम अतिरिक्त मेमोरी का उपयोग कर सकते हैं। हालाँकि, इस अतिरिक्त मेमोरी की मात्रा इनपुट पर निर्भर नहीं होनी चाहिए - अर्थात यह स्थिर होनी चाहिए। इसलिए, अतिरिक्त संग्रहण का उपयोग करके मानों की अदला-बदली पूरी तरह से है।
कोनराड रुडोल्फ

19
जब तक ज़ोर की अदला-बदली नहीं हो जाती, तब तक इसे न उतारा जाए।
एडम रोसेनफील्ड

34
XOR स्वैपिंग आधुनिक आउट-ऑफ-ऑर्डर प्रोसेसर पर रजिस्टर के माध्यम से स्वैप करने की तुलना में धीमी है।
पैट्रिक श्ल्टर

465
#include <algorithm>
std::reverse(str.begin(), str.end());

C ++ में यह सबसे सरल तरीका है।


6
C ++ में स्ट्रिंग क्लास द्वारा एक स्ट्रिंग का प्रतिनिधित्व किया जाता है। उन्होंने "चार सितारा" या "चार कोष्ठक" के लिए नहीं कहा। उत्तम दर्जे का रहें, सी।
जोकून

10
@fredsbend, चयनित उत्तर के "हास्यास्पद रूप से लंबा" संस्करण एक ऐसे मामले को संभालता है जो यह सरल उत्तर नहीं देता है - UTF-8 इनपुट। यह समस्या को पूरी तरह से निर्दिष्ट करने के महत्व को दर्शाता है। इसके अलावा सवाल कोड के बारे में था जो सी में भी काम करेगा।
मार्क रैनसम

5
यदि आप UTF-8 जागरूक स्ट्रिंग वर्ग का उपयोग करते हैं (या संभवतः std :: basic_string के साथ utf-8 वर्ण वर्ग) तो यह उत्तर मामले को संभालता है। इसके अलावा, सवाल ने कहा "सी या सी ++", "सी और सी ++" नहीं। C ++ केवल "C या C ++" है।
तैवे

161

कर्निघन और रिची पढ़ें

#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;
    }
}

8
मेरे iPhone पर परीक्षण किया गया यह लगभग 15% कच्चे सूचक पते का उपयोग करने की तुलना में धीमा है
jjxtra

3
क्या चर "c" को int के बजाय char नहीं होना चाहिए?
लेस्वर

17
इस उदाहरण में यह नोट करना महत्वपूर्ण है कि स्ट्रिंग sको एक सरणी रूप में घोषित किया जाना चाहिए। दूसरे शब्दों में, char s[] = "this is ok"बजाय इसके char *s="cannot do this"कि एक स्ट्रिंग स्थिरांक में बाद के परिणाम संशोधित नहीं किए जा सकते हैं
user1527227

3
"द गॉडफादर" के लिए माफी माँगने के साथ .... "बंदूकें छोड़ो, के एंड आर लाओ"। एक सी बिगोट के रूप में, मैं पॉइंटर्स का उपयोग करूँगा, क्योंकि वे इस समस्या के लिए सरल और अधिक सीधे-आगे हैं, लेकिन कोड सी #, जावा, आदि के लिए कम पोर्टेबल होगा

2
@ यह O (लॉग (n)) समय में नहीं चलता है। यह O (n) में चलता है यदि आप वर्ण की संख्या की बात करते हैं तो कोड प्रदर्शन स्वैप करता है, स्ट्रिंग लंबाई के n के लिए, फिर n स्वैप किए जाते हैं। यदि हम आपके द्वारा प्रदर्शन किए गए लूप की मात्रा के बारे में बात कर रहे हैं तो इसके O (n) - यद्यपि O (n / 2) हैं लेकिन आप बिग O संकेतन में स्थिरांक छोड़ते हैं।
स्टीफन फॉक्स

62

जगह में एक स्ट्रिंग उल्टा (दृश्य):

जगह में एक स्ट्रिंग उल्टा


ठंडा! इसे बनाने के लिए आपने क्या इस्तेमाल किया? मुझे लगता है कि इसका उत्तर एक लिंक को शामिल करके बेहतर होगा।
प्रीफटन

इस एल्गोरिदम का कार्यान्वयन वास्तव में इस उत्तर में है
कार्लफिलिप

क्या आप इसे थोड़ा सा समझा सकते हैं अगर छवि लिंक मर जाता है तो उत्तर बेकार नहीं होगा?
एसएस ऐनी

41

गैर-बुराई सी, जहां सामान्य मामला है जहां स्ट्रिंग एक शून्य-समाप्त 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--;
  }
}

एंड पॉइंटर को खोजने के लिए थोड़ी देर के लूप का उपयोग करने के बजाय, क्या आप कुछ का उपयोग नहीं कर सकते जैसे end_ptr = str + strlen (str); मुझे पता है कि व्यावहारिक रूप से वही काम करेगा, लेकिन मुझे यह स्पष्ट है।
पीटर कुहने

काफी उचित। मैं @ uvote के उत्तर में ऑफ-बाय-वन त्रुटि से बचने के लिए (और असफल) कोशिश कर रहा था।
क्रिस कॉनवे

एक संभावित प्रदर्शन में सुधार के साथ शायद int temp, यह समाधान सबसे अच्छा लग रहा है। +1
chux -

@ chux-ReinstateMonica हाँ। यह खूबसूरत है। !(*str)हालांकि मैं व्यक्तिगत रूप से () को हटा दूंगा।
प्रीफटन

@ पीटरकुन्ने हाँ या strchr()खोज रहा है '\0'। मैंने दोनों के बारे में सोचा। लूप की जरूरत नहीं।
प्रियेफ़टन

35

आप std::reverseC ++ मानक लाइब्रेरी से एल्गोरिथ्म का उपयोग करते हैं ।


14
मानक टेम्पलेट लाइब्रेरी एक पूर्व-मानक शब्द है। C ++ मानक इसका उल्लेख नहीं करता है, और पूर्व STL घटक C ++ मानक लाइब्रेरी में हैं।
नागेज़ा ट्रिफ़ुनोविक

16
सही। मुझे हमेशा आश्चर्य होता है कि इतने सारे लोग अभी भी इसे "एसटीएल" क्यों कहते हैं, भले ही यह इस मामले को भ्रमित करने का काम करता हो। यदि आपके जैसे और लोग हैं तो इसे "सी ++ स्टैण्डर्ड लाइब्रेरी" या एसटीएल कहेंगे और "स्टैण्डर्ड लाइब्रेरी" कहेंगे
जोहान्स

27

कुछ समय हो गया है और मुझे याद नहीं है कि किस पुस्तक ने मुझे यह एल्गोरिथम सिखाया है, लेकिन मुझे लगा कि यह समझने में काफी सरल और सरल था:

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हालांकि होना चाहिए ।
प्रियेफ़टन

24

एसटीएल से एसटीडी :: रिवर्स विधि का उपयोग करें :

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

तुम्हें पता है, "एल्गोरिथ्म" पुस्तकालय शामिल करना होगा #include<algorithm>


1
किस पुस्तकालय को शामिल करने की आवश्यकता है?
डॉन क्रिकेशंक

#include <एल्गोरिथ्म> मैं इसे लिखना भूल गया और फिर उत्तर को संपादित किया, लेकिन इसे सहेजा नहीं गया, यही कारण है कि नाम गायब था ..
user2628229

हालांकि यह मेरा जवाब होगा, बस उत्सुक, क्योंकि ओपी ने पूछा कि "बिना बफर के उलट स्ट्रिंग रखने के लिए" (मूल रूप से, इन-प्लेस स्वैप), कोई यह कैसे साबित करता है कि वह ऐसा कर रहा है? क्या कोई यह समझाता है कि यह आंतरिक रूप से std :: iter_swap <> का उपयोग करता है, जो दोनों अंतिम बिंदुओं से बफर के मध्य-बिंदु तक चलने वाला है? इसके अलावा, ओपी ने C और C ++ दोनों के लिए कहा, यह केवल C ++ के लिए है (क्या हम सिर्फ आशा कर सकते हैं <string.h> में strrev () तरीका है?)
HidekiAI

21

नोट std :: रिवर्स की सुंदरता है कि यह साथ काम करता है कि char *तार और std::wstringके रूप में बस के रूप में अच्छी तरह से एस std::stringएस

void strrev(char *str)
{
    if (str == NULL)
        return;
    std::reverse(str, str + strlen(str));
}

1
एक तरफ मैं उल्टी करना चाहता हूं क्योंकि आपने सी ++ का उपयोग किया है, लेकिन दूसरी तरफ यह एक सुंदर, सुंदर, बिल्कुल सुंदर चीज है किसी को सी ++ का उपयोग करने के लिए देखें जो *टाइप करके नहीं डालते हैं और इसे नाम से डालते हैं। आश्चर्यजनक। मैं मानता हूँ कि मैं एक शुद्धतावादी के बारे में कुछ हूं लेकिन मैं हर बार कोड को देखता हूं जैसे मैं देखता हूं char* str;
प्रियेफ़टन

11

यदि आप NULL टर्मिनेटेड बफ़र्स को उलटने की तलाश कर रहे हैं, तो यहां पोस्ट किए गए अधिकांश समाधान ठीक हैं। लेकिन, जैसा कि टिम फार्ले ने पहले ही बताया था, ये एल्गोरिदम केवल तभी काम करेंगे, जब यह मान लिया जाए कि यह एक स्ट्रिंग है जो शब्दार्थ बाइट्स (यानी सिंगल-बाइट स्ट्रिंग्स) का एक सरणी है, जो एक गलत धारणा है।

उदाहरण के लिए, स्ट्रिंग "año" (स्पेनिश में वर्ष)।

यूनिकोड कोड पॉइंट 0x61, 0xf1, 0x6f हैं।

सबसे अधिक इस्तेमाल किए जाने वाले कुछ एन्कोडिंग पर विचार करें:

लैटिन 1 / iso-8859-1 (एकल बाइट एन्कोडिंग, 1 वर्ण 1 बाइट और इसके विपरीत है):

मूल:

0x61, 0xf1, 0x6f, 0x00

उलटना:

0x6f, 0xf1, 0x61, 0x00

परिणाम ठीक है

UTF-8:

मूल:

0x61, 0xc3, 0xb1, 0x6f, 0x00

उलटना:

0x6f, 0xb1, 0xc3, 0x61, 0x00

परिणाम जिबरिश और एक अवैध UTF-8 अनुक्रम है

UTF-16 बिग एंडियन:

मूल:

0x00, 0x61, 0x00, 0xf1, 0x00, 0x6f, 0x00, 0x00

पहले बाइट को एनयूएल-टर्मिनेटर के रूप में माना जाएगा। कोई उलटफेर नहीं होगा।

UTF-16 लिटिल एंडियन:

मूल:

0x61, 0x00, 0xf1, 0x00, 0x6f, 0x00, 0x00, 0x00

दूसरी बाइट को एनयूएल-टर्मिनेटर के रूप में माना जाएगा। परिणाम 0x61, 0x00, एक स्ट्रिंग होगा जिसमें 'a' वर्ण होगा।


std :: रिवर्स दो-बाइट यूनिकोड प्रकारों के लिए काम करेगा, जब तक आप wstring का उपयोग कर रहे हैं।
ग्रहण

मैं C ++ से बहुत परिचित नहीं हूं, लेकिन मेरा अनुमान है कि स्ट्रिंग्स से निपटने वाला कोई भी सम्मानजनक मानक लाइब्रेरी फ़ंक्शन विभिन्न एन्कोडिंग को संभालने में सक्षम होगा, इसलिए मैं आपसे सहमत हूं। "इन एल्गोरिदम" द्वारा, मेरा मतलब था कि तदर्थ रिवर्स फ़ंक्शन यहां तैनात हैं।
जुआन पाब्लो कैलिफोर्नो

दुर्भाग्य से, मानक C ++ में "सम्मानजनक फ़ंक्शन स्ट्रिंग्स से निपटने" जैसी कोई चीज नहीं है।
जेम

@ ग्रहण यदि यह एक सरोगेट जोड़ी को उलट देता है, तो परिणाम अब सही नहीं होगा। यूनिकोड वास्तव में एक निश्चित-चौड़ाई वाला चारसेट नहीं है
phuclv

इस उत्तर के बारे में मुझे जो पसंद है, वह यह है कि यह बाइट्स के वास्तविक क्रम को दर्शाता है (हालांकि धीरज कुछ हो सकता है - आह, मुझे लगता है कि आपने वास्तव में इस पर विचार किया था) और यह कैसे सही या गलत है। लेकिन मुझे लगता है कि यदि आप कुछ कोड को प्रदर्शित करते हैं तो इसका उत्तर बेहतर होगा।
प्रियेफ़टन

11

पूर्णता के हित में, यह इंगित किया जाना चाहिए कि विभिन्न प्लेटफार्मों पर तार के प्रतिनिधित्व हैं जिसमें चरित्र के आधार पर प्रति चरित्र बाइट्स की संख्या भिन्न होती है । पुराने स्कूल प्रोग्रामर इसे DBCS (डबल बाइट कैरेक्टर सेट) के रूप में संदर्भित करेंगे । आधुनिक प्रोग्रामर आमतौर पर UTF-8 (साथ ही UTF-16 और अन्य) में इसका सामना करते हैं । इस तरह के अन्य एनकोडिंग भी हैं।

इन चर-चौड़ाई वाली एन्कोडिंग योजनाओं में से किसी में भी, यहां पर पोस्ट किए गए सरल एल्गोरिदम ( बुराई , गैर-बुराई या अन्यथा ) सही तरीके से काम नहीं करेंगे! वास्तव में, वे स्ट्रिंग को गैरकानूनी बनाने के लिए या उस एन्कोडिंग योजना में भी अवैध स्ट्रिंग का कारण बन सकते हैं। कुछ अच्छे उदाहरणों के लिए जुआन पाब्लो कैलिफानो का जवाब देखें ।

std :: रिवर्स () संभावित रूप से इस मामले में काम करेगा, जब तक कि आपके प्लेटफ़ॉर्म का मानक C ++ लाइब्रेरी (विशेष रूप से, स्ट्रिंग पुनरावृत्तियों) के कार्यान्वयन ने इसे ठीक से ध्यान में रखा हो।


6
std :: रिवर्स इसे ध्यान में नहीं रखता है। यह value_type का उल्टा करता है। Std :: string case में, यह char's को उलट देता है। पात्र नहीं।
MSalters

इसके बजाय यह कहें कि हम पुराने स्कूल प्रोग्रामर DBCS के बारे में जानते हैं, लेकिन UTF-8 के बारे में भी जानते हैं: क्योंकि हम सभी जानते हैं कि प्रोग्रामर नशेड़ी की तरह हैं जब वे कहते हैं कि 'एक और लाइन और मैं छोड़ दूँगा!' मुझे यकीन है कि कुछ प्रोग्रामर अंततः चले गए लेकिन सच में प्रोग्रामिंग मेरे लिए एक लत की तरह है; मुझे प्रोग्रामिंग से निकासी मिलती है। यह एक अच्छा बिंदु है जिसे आप यहां जोड़ते हैं। मुझे C ++ पसंद नहीं है (मैंने वास्तव में बहुत कठिन कोशिश की है कि इसे लिखना भी बहुत पसंद है लेकिन यह अभी भी मेरे लिए सौंदर्यशास्त्र से कम से कम कहने के लिए अप्रभावित है) इसलिए मैं वहां टिप्पणी नहीं कर सकता, लेकिन आप वैसे भी एक अच्छा बिंदु बनाते हैं एक +1 है।
प्रियेफ़टन

5

एक और सी ++ तरीका (हालांकि मैं शायद एसटीडी का उपयोग करेगा: रिवर्स) () खुद को :) अधिक अभिव्यंजक और तेज होने के रूप में)

str = std::string(str.rbegin(), str.rend());

सी तरीका (अधिक या कम :)) और कृपया, स्वैपिंग के लिए 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

strlenयदि यह संभावित रूप से लंबा है, तो मैं स्ट्रिंग के अंत को खोजने के लिए उपयोग करूंगा । एक अच्छा पुस्तकालय कार्यान्वयन SIMD वैक्टरों का उपयोग प्रति पुनरावृत्ति 1 बाइट से अधिक तेजी से खोजने के लिए करेगा। लेकिन बहुत कम तारों के लिए, while (*++end);एक पुस्तकालय समारोह कॉल की खोज शुरू होने से पहले किया जाएगा।
पीटर कॉर्डेस

@PeterCordes अच्छी तरह से सहमत हैं, स्ट्रैलेन को पठनीयता के लिए वैसे भी उपयोग किया जाना चाहिए। लंबी स्ट्रिंग के लिए आपको हमेशा लंबाई को किसी भी तरह से रखना चाहिए। SIMD पर strlen को आमतौर पर इस अस्वीकरण के साथ एक उदाहरण के रूप में दिया जाता है, यह वास्तविक जीवन अनुप्रयोग नहीं है, या कम से कम 5 साल पहले था, जब कोड लिखा गया था। ;)
pprzemek

1
यदि आप चाहते हैं कि यह वास्तविक सीपीयू पर तेजी से चले, तो आप 16 बी चंक्स में रिवर्स करने के लिए SIMD फेरबदल का उपयोग करेंगे। : P पर x86, _mm_shuffle_epi8(PSHUFB) 16B वेक्टर के क्रम को उल्टा कर सकता है, जिसे सही फेरबदल नियंत्रण वेक्टर दिया जाता है। यह शायद कुछ सावधानी से अनुकूलन के साथ लगभग विशेष रूप से AVX2 के साथ लगभग यादगार गति से चल सकता है।
पीटर कॉर्डेस

char* beg = s-1अपरिभाषित व्यवहार किया है (कम से कम अगर sकिसी सरणी के पहले तत्व को इंगित करता है, जो कि सबसे आम मामला है)। एक खाली स्ट्रिंग है, while (*++end);तो अपरिभाषित व्यवहार sहै।
मेलपोमिन

@pprzemek खैर, आप ऐसा दावा कर रहे हैं जिसने s-1व्यवहार को परिभाषित किया है, भले ही sकिसी सरणी के पहले तत्व को इंगित करता हो, इसलिए यह वह है जो आपको मानक का समर्थन करने में सक्षम होना चाहिए।
मेलपोमेन

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

यह कोड इस आउटपुट का उत्पादन करता है:

gnitset
a
cba

2
@uvote, strcpy का उपयोग न करें। कभी। अगर आपको कुछ ऐसा उपयोग करना है जैसे strcpy का उपयोग करना strncpy। strcpy खतरनाक है। वैसे C और C ++ अलग-अलग सुविधाओं वाली दो अलग-अलग भाषाएं हैं। मुझे लगता है कि आप केवल सी ++ में उपलब्ध हेडर फ़ाइलों का उपयोग कर रहे हैं, तो क्या आपको वास्तव में सी में उत्तर की आवश्यकता है?
ओनोरियो कैटेनेशिया

6
strcpy पूरी तरह से सुरक्षित है अगर प्रोग्रामर अपने सरणियों के आकार का ट्रैक रख सकता है, तो कई का तर्क होगा कि strncpy कम सुरक्षित है क्योंकि यह गारंटी नहीं देता है कि परिणामस्वरूप स्ट्रिंग को समाप्त कर दिया गया है। किसी भी मामले में, यहां स्ट्रॉबेरी के उवोट के उपयोग के साथ कुछ भी गलत नहीं है।
रॉबर्ट गैंबल

1
@Onorio Catenacci, strcpy खतरनाक नहीं है यदि आप जानते हैं कि स्रोत स्ट्रिंग गंतव्य बफर के अंदर फिट होगा, जैसा कि उपरोक्त कोड में दिए गए मामलों में है। इसके अलावा, खुरदरा शून्य शून्य आकार कमरे में निर्दिष्ट चारर की संख्या तक भर जाता है, अगर बायीं ओर कमरा है, जो वांछित नहीं हो सकता है।
क्रिस यंग

3
कोई भी जो ठीक से उपयोग नहीं कर सकता है वह सी। में प्रोग्रामिंग नहीं होनी चाहिए
रॉबर्ट गैंबल

2
@ रोबर्ट गैंबल, मैं सहमत हूं। हालांकि, चूंकि मुझे सी से प्रोग्रामिंग में लोगों को रखने का कोई तरीका नहीं पता है, इसलिए उनकी क्षमता क्या है, मैं आमतौर पर इसके खिलाफ सलाह देता हूं।
ओनोरियो कैटेनेशिया


3

मुझे एवगेनी के के एंड आर जवाब पसंद है। हालाँकि, पॉइंटर्स का उपयोग करके संस्करण देखना अच्छा है। अन्यथा, यह अनिवार्य रूप से समान है:

#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;
}

3

जगह में एक स्ट्रिंग रिवर्स करने के लिए पुनरावर्ती कार्य (कोई अतिरिक्त बफर, मॉलोक) नहीं।

लघु, सेक्सी कोड। खराब, खराब स्टैक का उपयोग।

#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;
}

1
यह एक बहुत ही मजेदार समाधान है, आपको प्रिंटफ ("% * s> [% d] रिवर्स_r ('% c',% p = \"% s \ ",% p = \"% s \ ") जैसे कुछ अनुरेखण जोड़ना चाहिए \ n ", गहराई," ", गहराई, घाटी, s, (s? s:" null "), n, (n! n:" null ")); शुरू में और अंत में <।
बेनोइट

charस्टैक पर प्रत्येक को पुश करने से "जगह" के रूप में गिनती नहीं होती है। विशेष रूप से तब नहीं जब आप वास्तव में 4 * 8B प्रति वर्ण (64-बिट मशीन पर: 3 args + a return address) पर जोर दे रहे हों।
पीटर कॉर्डेस

मूल प्रश्न यह है कि "आप उल्टे तार को पकड़ने के लिए एक अलग बफर की आवश्यकता के बिना C या C ++ में स्ट्रिंग को कैसे रिवर्स करते हैं?" - 'जगह' स्वैप करने की कोई आवश्यकता नहीं थी। साथ ही, यह समाधान प्रारंभ से खराब स्टैक उपयोग का उल्लेख करता है। क्या अन्य लोगों की खराब पढ़ने की समझ के कारण मुझे वोट दिया जा रहा है?
साइमन पेवरेट

1
मैं इसे 'सेक्सी' नहीं कहूंगा लेकिन मैं कहूंगा कि यह प्रदर्शनकारी और निर्देशात्मक है। यदि पुनरावृत्ति का उपयोग ठीक से किया जाता है तो यह बहुत मूल्यवान हो सकता है। हालाँकि यह बताया जाना चाहिए कि - अंतिम मैं जानता था - C को प्रति सेकेण्ड स्टैक की भी आवश्यकता नहीं है; हालाँकि यह पुनरावृत्ति करता है। किसी भी तरह से यह पुनरावृत्ति का एक उदाहरण है जो अगर ठीक से उपयोग किया जाता है तो बहुत उपयोगी और मूल्यवान हो सकता है। मुझे नहीं लगता कि मैंने कभी देखा है कि यह एक स्ट्रिंग को रिवर्स करने के लिए उपयोग किया जाता है।
प्रिएफ्टन


1

मेरा कोड साझा करें सी ++ सीखने वाले के रूप में, स्वैप () का उपयोग करने के विकल्प के रूप में, मैं विनम्रतापूर्वक टिप्पणी के लिए पूछ रहा हूं।

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


0

अभी तक एक और:

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

}

यह सूचक अंकगणितीय प्रदर्शित करता है, बहुत कुछ मेरे जवाब की तरह, लेकिन इसे स्वैप के साथ जोड़ता है। मेरा मानना ​​है कि यह उत्तर वास्तव में बहुत कुछ जोड़ता है। केवल एक साधारण टेक्स्ट बॉक्स पाने के लिए निर्भरता के रूप में एक अरब पुस्तकालयों को जोड़ने से पहले आपको इस प्रकार के कोड को समझने में सक्षम होना चाहिए (कुछ मुझे जिस तरह से अक्सर आधुनिक अनुप्रयोगों में काम करने के लिए मिलता है)
स्टीफन जे

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

0

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

0

मेरा उत्तर उनमें से अधिकांश के समान होगा, लेकिन कृपया यहां मेरा कोड खोजें।

//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;
}

0

मुझे लगता है कि स्ट्रिंग को उल्टा करने का एक और तरीका है। उपयोगकर्ता से इनपुट प्राप्त करें और इसे उल्टा करें।

void Rev() {
    char ch;
    cin.get(ch);
    if(ch != '\n') {
        Rev();
        cout.put(ch);
    }
}

सच है, लेकिन यह केवल उलटा क्रम प्रिंट करता है, है ना? (मैं C ++ का उपयोग नहीं करता हूं इसलिए शायद .put () वह नहीं करता जो मुझे लगता है कि वह करता है)।
प्रियेफ़टन

-1

यदि आपको इसे संग्रहीत करने की आवश्यकता नहीं है, तो आप इस तरह बिताए गए समय को कम कर सकते हैं:

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

मुझे केवल एक ही उत्तर प्रतीत होता है जिसमें बफर या अस्थायी चर नहीं है। मैं स्ट्रिंग की लंबाई का उपयोग करता हूं, लेकिन ऐसा करने वाले अन्य लोग सिर (बनाम पूंछ) के लिए एक और जोड़ते हैं। मैं मान रहा हूं कि मानक रिवर्स फंक वैरिएबल को स्वैप या किसी चीज के जरिए स्टोर करता है। इस प्रकार, मैं इस धारणा के अधीन हूं कि सूचक गणित और UTF टाइप लाइन को मानते हुए, कि यह संभवतः एकमात्र उत्तर है जो वास्तव में प्रश्न का उत्तर देता है। अतिरिक्त प्रिंटफ () का उपयोग किया जा सकता है, मैंने सिर्फ परिणाम के लिए अच्छे लग रहे हैं। मैंने इसे गति के लिए लिखा था। कोई अतिरिक्त आवंटन या संस्करण नहीं। संभवत: रिवर्स str () प्रदर्शित करने के लिए सबसे तेज़ एल्गोरिथम
स्टीफन जे

-3

यहाँ सी। में मेरे लेने पर अभ्यास के लिए किया था और जितना संभव हो उतना संक्षिप्त करने की कोशिश की! आप कमांड लाइन के माध्यम से एक स्ट्रिंग दर्ज करते हैं, अर्थात ./program_name "यहां स्ट्रिंग दर्ज करें"

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

1
यह एक अपठनीय गड़बड़ है, लेकिन आप स्पष्ट रूप से कम से कम संभव कोड ( कोड गोल्फ ) के लिए नहीं जा रहे हैं क्योंकि कुछ चर नाम एक से अधिक वर्ण हैं।
पीटर कॉर्डेस

-4

लेकिन मुझे लगता है कि XOR स्वैप एल्गोरिथ्म सबसे अच्छा है ...

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()लूप कंडीशन में और लूप बॉडी में कॉल दूर नहीं हो सकता है।
पीटर कॉर्डेस

-5

यहाँ सी + + (मेरी राय में) में एक स्ट्रिंग को रिवर्स करने का सबसे साफ, सबसे सुरक्षित, सबसे आसान तरीका है:

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

}

एक विकल्प का उपयोग करना है std::swap, लेकिन मुझे अपने स्वयं के कार्यों को परिभाषित करना पसंद है - यह एक दिलचस्प अभ्यास है और आपको includeकुछ भी अतिरिक्त करने की आवश्यकता नहीं है ।


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

यह स्ट्रिंग को उलटने के लिए सी भाषा में अनुकूलित कोड है ... और यह सरल है; बस काम करने के लिए एक सरल सूचक का उपयोग करें ...


यह एक बार में स्ट्रिंग को चार प्रिंट करता है। यह जगह में इसे उल्टा नहीं करता है। यह बिना किसी कारण के उपयोगकर्ता इनपुट का भी इंतजार करता है।
पीटर कॉर्डेस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.