development

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

big-blog 2020. 5. 26. 18:59
반응형

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


반전 된 문자열을 유지하기 위해 별도의 버퍼가 필요없이 C 또는 C ++에서 문자열을 어떻게 뒤집습니까?


이블 C :

#include <stdio.h>

void strrev(char *p)
{
  char *q = p;
  while(q && *q) ++q;
  for(--q; p < q; ++p, --q)
    *p = *p ^ *q,
    *q = *p ^ *q,
    *p = *p ^ *q;
}

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

(이것은 XOR 스왑입니다. a ^ a == 0이므로 self와의 스왑을 피해야합니다 .)


좋아, UTF-8 문자를 고쳐 보자 ...

#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/.

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

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


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

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

줄을 제자리로 뒤집기


문자열이 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--;
  }
}

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


오랜 시간이 지났는데 어떤 알고리즘이 저에게이 알고리즘을 가르쳐 주 었는지 기억이 나지 않지만 이해하기가 매우 독창적이고 간단하다고 생각했습니다.

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

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

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

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


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

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

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이됩니다.


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

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

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


또 다른 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

#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

GLib을 사용하는 경우 g_strreverse ()g_utf8_strreverse ()의 두 가지 기능이 있습니다.


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

문자열을 제자리로 되 돌리는 재귀 함수 (추가 버퍼, 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;
}

사용하다 std::reverse()

reverse(begin(str), end(str));

그리고 그게 다야.


내 코드를 공유하십시오. 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--);
}

ATL / MFC를 사용하는 경우 CString전화하십시오 CString::MakeReverse().


또 다른 :

#include <stdio.h>
#include <strings.h>

int main(int argc, char **argv) {

  char *reverse = argv[argc-1];
  char *left = reverse;
  int length = strlen(reverse);
  char *right = reverse+length-1;
  char temp;

  while(right-left>=1){

    temp=*left;
    *left=*right;
    *right=temp;
    ++left;
    --right;

  }

  printf("%s\n", reverse);

}

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

unsigned char * utf8_reverse(const unsigned char *, int);
void assert_true(bool);

int main(void)
{
    unsigned char str[] = "mañana mañana";
    unsigned char *ret = utf8_reverse(str,  strlen((const char *) str) + 1);

    printf("%s\n", ret);
    assert_true(0 == strncmp((const char *) ret, "anãnam anañam", strlen("anãnam anañam") + 1));

    free(ret);

    return EXIT_SUCCESS;
}

unsigned char * utf8_reverse(const unsigned char *str, int size)
{
    unsigned char *ret = calloc(size, sizeof(unsigned char*));
    int ret_size = 0;
    int pos = size - 2;
    int char_size = 0;

    if (str ==  NULL) {
        fprintf(stderr, "failed to allocate memory.\n");
        exit(EXIT_FAILURE);
    }

    while (pos > -1) {

        if (str[pos] < 0x80) {
            char_size = 1;
        } else if (pos > 0 && str[pos - 1] > 0xC1 && str[pos - 1] < 0xE0) {
            char_size = 2;
        } else if (pos > 1 && str[pos - 2] > 0xDF && str[pos - 2] < 0xF0) {
            char_size = 3;
        } else if (pos > 2 && str[pos - 3] > 0xEF && str[pos - 3] < 0xF5) {
            char_size = 4;
        } else {
            char_size = 1;
        }

        pos -= char_size;
        memcpy(ret + ret_size, str + pos + 1, char_size);
        ret_size += char_size;
    }    

    ret[ret_size] = '\0';

    return ret;
}

void assert_true(bool boolean)
{
    puts(boolean == true ? "true" : "false");
}

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

내 대답은 대부분과 비슷하지만 여기에서 내 코드를 찾으십시오.

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

문자열을 뒤집는 다른 방법이 있다고 생각합니다. 사용자로부터 입력을 받아서 뒤집으십시오.

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

저장할 필요가 없으면 다음과 같이 시간을 줄일 수 있습니다.

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

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

그러나 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;
}

#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 언어로 최적화 된 코드입니다. 간단한 포인터를 사용하여 작업을 수행하십시오 ...


다음은 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추가 할 필요가 없습니다 .

참고 URL : https://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c

반응형