C 또는 C ++에서 문자열을 어떻게 뒤집습니까?


답변:


123

표준 알고리즘은 시작 / 끝에 대한 포인터를 사용하여 중간에서 만나거나 교차 할 때까지 안쪽으로 걷습니다. 당신이 갈 때 스왑.


역 ASCII 문자열, 즉 모든 문자가 1에 맞는 0으로 끝나는 배열 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 컴파일러 탐색기에서 xor-swap이 x86-64 용으로 gcc -O3로 컴파일 될 때 asm 루프 바디가 얼마나 복잡한 지 확인할 수 있습니다 .)


좋아, UTF-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 이상의 UTF-8은 테스트되지 않았습니다 (글꼴이 없거나 hexeditor를 사용하는 인내심이 없기 때문에)

예 :

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

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

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

./strrev verrts/.

162
코드 혼동을 피하기 위해 XOR 스왑을 사용해야 할 이유가 없습니다.
Chris Conway

28
"in-place"는 "추가 메모리 없음"을 의미한다고 생각합니다. 심지어 임시 메모리도 O (1) 메모리가 아닙니다. str과 반환 주소를위한 스택의 공간은 어떻습니까?
Chris Conway

55
@Bill, "in-place"의 일반적인 정의가 아닙니다. 내부 알고리즘 추가 메모리를 사용할 있습니다. 그러나이 추가 메모리의 양은 입력에 의존해서는 안됩니다. 즉 일정해야합니다. 따라서 추가 스토리지를 사용하여 값을 교체하는 작업이 완전히 완료되었습니다.
Konrad Rudolph

19
xor 스왑이 사라질 때까지 이것을지지하지 않습니다.
Adam Rosenfield

34
XOR 스와핑은 최신 비 순차적 프로세서의 레지스터를 통한 스와핑보다 느립니다.
Patrick Schlüter

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

이것이 C ++에서 가장 간단한 방법입니다.


6
C ++에서 문자열은 문자열 클래스로 표시됩니다. 그는 "char star"나 "char brackets"를 요구하지 않았다. 품위 있고 C.
jokoon

10
선택된 답변의 "엄청나게 긴"버전 @fredsbend는이 간단한 답변이 UTF-8 입력이 아닌 경우를 처리합니다. 문제를 완전히 지정하는 것의 중요성을 보여줍니다. 질문은 C에서도 작동하는 코드에 관한 것입니다.
Mark Ransom

5
이 답변은 UTF-8 인식 문자열 클래스 (또는 std :: basic_string이있는 utf-8 문자 클래스)를 사용하는 경우를 처리합니다. 게다가, 질문은 "C와 C ++"가 아니라 "C 또는 C ++"라고 말했다. C ++는 "C 또는 C ++"입니다.
Taywee

161

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

8
내 아이폰에서 테스트 한 결과 이것은 약 15 %까지 원시 포인터 주소를 사용하는 것보다 느리다
jjxtra

3
변수 "c"는 int 대신 char이 아니어야합니까?
Lesswire

17
이 예제에서 문자열 s은 배열 형식으로 선언해야합니다. 다시 말해서, 후자는 문자열 상수를 수정할 수 없기 때문에 char s[] = "this is ok"오히려 char *s="cannot do this"수정할 수 없습니다.
user1527227

3
"대부"에게 사과하면서 .... "총을두고 K & R을 가져 가십시오". C bigot로서, 나는이 문제에 대해 더 단순하고 더 직관적이기 때문에 포인터를 사용할 것이지만, 코드는 C #, Java 등에 이식성이 떨어질 것이다.

2
@Eric O (log (n)) 시간에는 실행되지 않습니다. 코드가 수행하는 문자 스왑 수를 나타내는 경우 O (n)에서 실행됩니다 .n 개의 문자열 길이에 대해 n 스왑이 수행됩니다. 우리가 수행 한 루프의 양에 대해 이야기하고 있다면 여전히 O (n)이지만 O (n / 2)이지만 상수는 Big O 표기법으로 삭제합니다.
Stephen Fox

62

현을 뒤집습니다 (시각화) :

줄을 제자리로 뒤집기


멋있는! 이것을 만들기 위해 무엇을 사용 했습니까? 나는 그것에 대한 링크를 포함시킴으로써 대답이 향상 될 것이라고 생각합니다.
Pryftan

이 알고리즘의 구현은 실제로이 답변에 있습니다.
karlphillip

이미지 링크가 죽으면 대답이 쓸모 없을 것입니다.
SS Anne

41

문자열이 null로 끝나는 char배열 인 경우를 가정하면 비악 한 C :

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

while 루프를 사용하여 끝 포인터를 찾는 대신 end_ptr = str + strlen (str); 나는 그것이 실제로 똑같은 일을 할 것이라는 것을 알고 있지만 더 명확합니다.
피터 쿠네

그럴 수 있지. @uvote의 답변에서 하나의 오류를 피하려고 노력했습니다.
Chris Conway

어쩌면 로 잠재적 인 성능 향상 외에도이 int temp솔루션이 가장 좋습니다. +1
chux-복원 모니카

@ chux-ReinstateMonica 예. 아름답습니다. 개인적으로 나는 ()를 제거합니다 !(*str).
Pryftan

@ PeterKühne 예 또는 strchr()검색 중 '\0'. 나는 둘 다 생각했다. 루프가 필요하지 않습니다.
Pryftan

35

std::reverseC ++ 표준 라이브러리의 알고리즘을 사용 합니다.


14
표준 템플릿 라이브러리는 사전 표준 용어입니다. C ++ 표준에서는 언급하지 않았으며 이전 STL 구성 요소는 C ++ 표준 라이브러리에 있습니다.
Nemanja Trifunovic

16
권리. 나는 단지 왜 많은 사람들이 그 문제를 혼란스럽게하는데 여전히 "STL"이라고 부르는지 궁금합니다. 더 많은 사람들이 당신과 같고 그냥 "C ++ 표준 라이브러리"또는 STL이라고 부르고 "표준 라이브러리"라고 말하면 더 좋을 것입니다 :)
Johannes Schaub-litb

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.
Pryftan

24

STLstd :: reverse 메소드를 사용하십시오 .

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

"알고리즘"라이브러리를 포함해야합니다 #include<algorithm>.


1
어떤 라이브러리를 포함해야합니까?
Don Cruickshank

#include <algorithm> 나는 그것을 쓰는 것을 잊었다가 답을 편집했지만 답변이 저장되지
않아서

OP가 "리버스 된 문자열을 유지할 버퍼없이"(기본적으로 내부 스왑)를 요청했기 때문에 이것이 내 대답 일 수도 있지만 궁금한 점은 무엇입니까? 내부적으로 std :: iter_swap <>을 사용하여 양쪽 끝점에서 버퍼의 중간 지점까지 반복한다고 설명합니까? 또한 OP는 C와 C ++ 모두에 대해 물었습니다. 이것은 C ++에만 해당됩니다 (<string.h>에 strrev () 메서드가 있기를 바랍니다)?
HidekiAI

21

표준 : 역의 아름다움이 함께 작동하는 것을 참고 char *문자열과 std::wstring같은 단지뿐만 아니라이야 std::string

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

1
한편으로는 C ++을 사용했기 때문에 구토를하고 싶지만 다른 한편으로는 누군가가 C ++을 사용 *하여 유형별로 넣지 않고 오히려 이름으로 넣는 것을 보는 것은 아름답고 아름답고 절대적으로 아름다운 것 입니다. 훌륭한. 나는 내가 순수 주의자라는 것을 인정하지만 같은 코드를 볼 때마다 울었다 char* str;.
프리프 탄

11

NULL로 종료 된 버퍼를 되돌리려면 여기에 게시 된 대부분의 솔루션이 정상입니다. 그러나 Tim Farley가 이미 지적 했듯이이 알고리즘은 문자열이 의미 론적으로 바이트 배열 (즉, 단일 바이트 문자열)이라고 가정하는 것이 유효한 경우에만 작동하며 이는 잘못된 가정이라고 생각합니다.

예를 들어 문자열 "año"(스페인어 연도)를 예로 들어 보겠습니다.

유니 코드 코드 포인트는 0x61, 0xf1, 0x6f입니다.

가장 많이 사용되는 인코딩을 고려하십시오.

Latin1 / iso-8859-1 (1 바이트 인코딩, 1 문자는 1 바이트, 그 반대) :

실물:

0x61, 0xf1, 0x6f, 0x00

역전:

0x6f, 0xf1, 0x61, 0x00

결과는 OK

UTF-8 :

실물:

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

역전:

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

결과는 횡설수설이며 잘못된 UTF-8 시퀀스입니다.

UTF-16 빅 엔디안 :

실물:

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

첫 번째 바이트는 NUL 종료 자로 취급됩니다. 반전은 일어나지 않습니다.

UTF-16 리틀 엔디안 :

실물:

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

두 번째 바이트는 NUL 종료 자로 취급됩니다. 결과는 'a'문자를 포함하는 문자열 0x61, 0x00이됩니다.


std :: reverse는 wstring을 사용하는 한 2 바이트 유니 코드 유형에서 작동합니다.
Eclipse

나는 C ++에 익숙하지 않지만 문자열을 다루는 존경받는 표준 라이브러리 함수는 다른 인코딩을 처리 할 수 ​​있으므로 동의합니다. "이 알고리즘들"이란 여기에 게시 된 임시 역함수를 의미했습니다.
Juan Pablo Califano

불행히도 표준 C ++에는 "문자열을 다루는 각각의 함수"와 같은 것은 없습니다.
Jem

@Eclipse 대리 쌍을 반대로하면 더 이상 결과가 정확하지 않습니다. 유니 코드는 실제로 고정 너비 문자 집합이 아닙니다
phuclv

이 답변에서 내가 좋아하는 것은 바이트의 실제 순서를 보여줍니다 (엔디안은 무언가가 될 수 있습니다-아, 실제로 그것을 고려한 것을 볼 수 있습니다). 그러나 이것을 보여주는 코드를 통합하면 대답이 향상 될 것이라고 생각합니다.
Pryftan

11

완전성을 위해, 문자 마다 바이트 수가 문자에 따라 달라지는 다양한 플랫폼에 문자열 표현이 있음을 지적해야합니다 . 구식 프로그래머는 이것을 DBCS (Double Byte Character Set) 라고 부릅니다 . 현대 프로그래머는 UTF-8 ( UTF-16 및 기타) 에서 더 자주 발생합니다 . 다른 인코딩도 있습니다.

이러한 가변 너비 인코딩 체계에서 여기에 게시 된 간단한 알고리즘 ( evil , non-evil 또는 else )은 전혀 올바르게 작동하지 않습니다! 실제로, 해당 인코딩 체계에서 문자열을 읽을 수 없거나 잘못된 문자열로 만들 수도 있습니다. 좋은 예는 Juan Pablo Califano의 답변 을 참조하십시오 .

std :: reverse ()는 플랫폼의 표준 C ++ 라이브러리 구현 (특히 문자열 반복자)이이를 올바르게 고려한다면이 경우에도 여전히 작동합니다.


6
std :: reverse는 이것을 고려하지 않습니다. value_type과 반대입니다. std :: string 경우에는 char를 뒤집습니다. 문자가 아닙니다.
MSalters

오히려 우리의 구식 프로그래머는 DBCS를 알고 있지만 UTF-8도 알고 있다고 말하십시오. 우리 모두는 프로그래머가 '한 줄 더 있고 끝내겠다' 라고 말할 때 중독자와 같습니다 . 나는 어떤 프로그래머들은 결국 그만 두었다고 확신하지만 솔직하게 프로그래밍하는 것은 정말로 중독과 같다. 프로그래밍하지 않으면 철회합니다. 여기에 추가하는 것이 좋습니다. 나는 C ++을 좋아하지 않는다. (나는 그것을 작성하는 것을 좋아하기 위해 정말로 열심히 노력했지만 여전히 미적으로 매력적이지 않다.) +1이 있습니다.
Pryftan

5

또 다른 C ++ 방법 (아마도 std :: reverse () 내 자신을 더 표현력 있고 빠르지 만)

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

C 방식 (더 많거나 적음) : 스와핑을위한 XOR 트릭에주의하십시오. 컴파일러는 때로는 최적화 할 수 없습니다.

이러한 경우 일반적으로 속도가 훨씬 느립니다.

char* reverse(char* s)
{
    char* beg = s, *end = s, tmp;
    while (*end) end++;
    while (end-- > beg)
    { 
        tmp  = *beg; 
        *beg++ = *end;  
        *end =  tmp;
    }
    return s;
} // fixed: check history for details, as those are interesting ones

strlen잠재적으로 긴 경우 문자열의 끝을 찾는 데 사용 합니다. 좋은 라이브러리 구현은 SIMD 벡터를 사용하여 반복 당 1 바이트보다 빠르게 검색합니다. 그러나 매우 짧은 문자열의 while (*++end);경우 라이브러리 함수 호출이 검색을 시작하기 전에 수행됩니다.
Peter Cordes

@PeterCordes는 가독성을 위해 어쨌든 strlen을 사용해야한다고 동의했습니다. 더 긴 문자열의 경우 항상 길이를 varialbe로 유지해야합니다. SIMD에 대한 strlen은 일반적으로이 면책 조항으로 제시되며, 이는 실제 응용 프로그램이 아니거나 코드가 작성된 5 년 전이었습니다. ;)
pprzemek

1
실제 CPU에서이 기능을 빠르게 실행하려면 SIMD 셔플을 사용하여 16B 청크에서 반대로 수행하십시오. : 예를 들어 x86에서 _mm_shuffle_epi8(PSHUFB)는 오른쪽 셔플 제어 벡터가 주어지면 16B 벡터의 순서를 반대로 할 수 있습니다. 특히 AVX2에서 신중하게 최적화하면 거의 memcpy 속도로 실행될 수 있습니다.
Peter Cordes

char* beg = s-1정의되지 않은 동작이 있습니다 (적어도 s가장 일반적인 경우는 배열의 첫 번째 요소를 가리키는 경우). 빈 문자열 인 while (*++end);경우 정의되지 않은 동작 s이 있습니다.
melpomene

@pprzemek 글쎄, 배열의 첫 번째 요소를 가리켜 s-1도 동작을 정의한 주장을 하고 s있으므로 표준을지지 할 수 있어야합니다.
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;
}

이 코드는 다음과 같은 출력을 생성합니다.

gnitset
a
cba

2
@uvote, strcpy를 사용하지 마십시오. 이제까지. strcpy와 같은 것을 사용해야하는 경우 strncpy를 사용하십시오. strcpy는 위험합니다. 그런데 C와 C ++는 별도의 기능을 가진 두 개의 별도 언어입니다. C ++에서만 사용할 수있는 헤더 파일을 사용하고 있다고 생각하므로 실제로 C로 대답해야합니까?
Onorio Catenacci

6
strcpy는 프로그래머가 배열의 크기를 추적 할 수 있다면 완벽하게 안전합니다. 많은 사람들은 strncpy가 결과 문자열이 null로 끝나는 것을 보장하지 않기 때문에 덜 안전하다고 주장합니다. 어쨌든, uvote의 strcpy 사용에 아무런 문제가 없습니다.
Robert Gamble

1
@Onorio Catenacci, strcpy는 위의 코드에서 주어진 것처럼 소스 문자열이 대상 버퍼 안에 들어가는 것을 알고 있다면 위험하지 않습니다. 또한 공간이 남아있을 경우 strncpy는 size 매개 변수에 지정된 문자 수까지 0을 채 웁니다.
Chris Young

3
제대로 strcpy를 사용할 수 없습니다 사람은 C로 프로그래밍되어서는 안된다
로버트 갬블에게

2
@Robert Gamble, 동의합니다. 그러나 사람들이 C의 프로그래밍 능력을 막는 방법을 알지 못하기 때문에 일반적으로 이것을 반대하는 것이 좋습니다.
Onorio Catenacci


3

나는 Evgeny의 K & R 답변을 좋아합니다. 그러나 포인터를 사용하여 버전을 보는 것이 좋습니다. 그렇지 않으면 본질적으로 동일합니다.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *reverse(char *str) {
    if( str == NULL || !(*str) ) return NULL;
    int i, j = strlen(str)-1;
    char *sallocd;
    sallocd = malloc(sizeof(char) * (j+1));
    for(i=0; j>=0; i++, j--) {
        *(sallocd+i) = *(str+j);
    }
    return sallocd;
}

int main(void) {
    char *s = "a man a plan a canal panama";
    char *sret = reverse(s);
    printf("%s\n", reverse(sret));
    free(sret);
    return 0;
}

3

문자열을 제자리로 되 돌리는 재귀 함수 (추가 버퍼, malloc 없음).

짧고 섹시한 코드. 스택 사용량이 잘못되었습니다.

#include <stdio.h>

/* Store the each value and move to next char going down
 * the stack. Assign value to start ptr and increment 
 * when coming back up the stack (return).
 * Neat code, horrible stack usage.
 *
 * val - value of current pointer.
 * s - start pointer
 * n - next char pointer in string.
 */
char *reverse_r(char val, char *s, char *n)
{
    if (*n)
        s = reverse_r(*n, s, n+1);
   *s = val;
   return s+1;
}

/*
 * expect the string to be passed as argv[1]
 */
int main(int argc, char *argv[])
{
    char *aString;

    if (argc < 2)
    {
        printf("Usage: RSIP <string>\n");
        return 0;
    }

    aString = argv[1];
    printf("String to reverse: %s\n", aString );

    reverse_r(*aString, aString, aString+1); 
    printf("Reversed String:   %s\n", aString );

    return 0;
}

1
이것은 매우 재미있는 해결책입니다. printf ( "% * s> [% d] reverse_r ( '% c', % p = \"% s \ ", % p = \"% s \ ")와 같은 추적을 추가해야합니다. \ n ", 깊이," ", 깊이, val, s, (s → s :"null "), n, (n → n :"null "); 시작과 끝에 <.
Benoît

각각 char을 스택에 밀어 넣는 것은 "정 위치"로 계산되지 않습니다. 실제로 실제로 문자 당 4 * 8B (64 비트 시스템 : 3 args + return address)를 푸시 할 때는 아닙니다.
Peter Cordes

원래 질문은 "역전 된 문자열을 유지하기 위해 별도의 버퍼를 요구하지 않고 C 또는 C ++에서 문자열을 어떻게 반전합니까?"입니다. - 'in place'를 교체 할 필요가 없었습니다. 또한이 솔루션은 처음부터 잘못된 스택 사용량을 언급합니다. 다른 사람들의 독해력 부족으로 인해 투표권이 떨어 졌습니까?
Simon Peverett

1
나는 그것을 '섹시한'이라고 부르지는 않지만 그것을 설명하고 교훈적이라고 말할 것입니다. 재귀를 올바르게 사용하면 매우 유용 할 수 있습니다. 그러나 내가 아는 마지막으로 C는 스택 자체를 필요로하지 않는다는 것을 지적해야한다. 그러나 재귀를 수행합니다. 어느 쪽이든 그것은 재귀의 예이며 올바르게 사용된다면 매우 유용하고 가치가 있습니다. 나는 그것이 문자열을 뒤집는 데 사용 된 것을 본 적이 있다고 생각하지 않습니다.
Pryftan


1

내 코드를 공유하십시오. C ++ 학습자 인 swap ()을 사용하는 옵션으로 겸손하게 의견을 묻습니다.

void reverse(char* str) {
    int length = strlen(str);
    char* str_head = str;
    char* str_tail = &str[length-1];
    while (str_head < str_tail) 
        swap(*str_head++, *str_tail--);
}


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

}

이것은 내 대답과 마찬가지로 포인터 산술을 보여 주지만 스왑과 결합합니다. 나는이 답변이 실제로 많은 것을 추가한다고 믿습니다. 종속 단지 (내가 함께 작업에 도착 나는 현대적인 응용 프로그램에서 너무 자주 방법 참조 뭔가) 간단한 텍스트 상자를 얻을 수대로 억 라이브러리를 추가하기 전에 코드의 유형을 이해할 수 있어야
스티븐 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");
}

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 ()이 내가 생각하는대로 작동하지 않을 수 있습니다).
Pryftan

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

버퍼 또는 임시 변수가없는 유일한 대답 인 것 같습니다. 나는 문자열의 길이를 사용하지만이를 수행하는 다른 사람들은 머리에 다른 것을 추가합니다 (vs 꼬리). 표준 리버스 펑크가 변수를 스왑 또는 무언가를 통해 저장한다고 가정합니다. 따라서 포인터 수학과 UTF 유형이 일치한다고 가정하면 이것이 실제로 질문에 대답하는 유일한 대답 일 것입니다. 추가 된 printf ()를 제거 할 수 있습니다. 결과를 더 좋게 보이기 위해 방금했습니다. 나는 이것을 속도로 썼다. 추가 할당이나 변수가 없습니다. 아마도 역 str ()를 표시하는 가장 빠른 알고리즘
Stephen J

-3

여기 C로 작성했습니다. 실습을 위해 최대한 간결하게 노력했습니다! 명령 행을 통해 문자열을 입력하십시오 (예 : ./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
읽을 수없는 혼란이지만 일부 변수 이름이 하나 이상의 문자이기 때문에 가능한 가장 짧은 코드 ( code golf )를 사용 하지 않을 것입니다 .
Peter Cordes

-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()루프 조건 및 루프 본문에서 호출하면 최적화되지 않을 수 있습니다.
Peter Cordes

-5

다음은 C ++에서 문자열을 뒤집는 가장 깨끗하고 안전하며 쉬운 방법입니다 (제 생각에는).

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

이것은 문자열을 뒤집기 위해 C 언어로 최적화 된 코드입니다 ... 그리고 간단합니다. 간단한 포인터를 사용하여 작업을 수행하십시오 ...


문자열을 한 번에 한 문자 씩 인쇄합니다. 원래 위치로 되 돌리지 않습니다. 또한 아무 이유없이 사용자 입력을 기다립니다.
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.