programing

C에서 문자열 반전

magicmemo 2023. 7. 25. 20:50
반응형

C에서 문자열 반전

저는 역 문자열 프로그램을 개발했습니다.더 나은 방법이 있는지, 그리고 제 코드에 잠재적인 문제가 있는지 궁금합니다.저는 C의 몇 가지 고급 기능을 연습하려고 합니다.

char* reverse_string(char *str)
{
    char temp;
    size_t len = strlen(str) - 1;
    size_t i;
    size_t k = len;

    for(i = 0; i < len; i++)
    {
        temp = str[k];
        str[k] = str[i];
        str[i] = temp;
        k--;

        /* As 2 characters are changing place for each cycle of the loop
           only traverse half the array of characters */
        if(k == (len / 2))
        {
            break;
        }
    }
}

C의 고급 기능을 연습하고 싶다면 포인터는 어떻습니까?우리는 재미로 매크로를 던지고 xor-swap도 할 수 있습니다!

#include <string.h> // for strlen()

// reverse the given null-terminated string in place
void inplace_reverse(char * str)
{
  if (str)
  {
    char * end = str + strlen(str) - 1;

    // swap the values in the two given variables
    // XXX: fails when a and b refer to same memory location
#   define XOR_SWAP(a,b) do\
    {\
      a ^= b;\
      b ^= a;\
      a ^= b;\
    } while (0)

    // walk inwards from both ends of the string, 
    // swapping until we get to the middle
    while (str < end)
    {
      XOR_SWAP(*str, *end);
      str++;
      end--;
    }
#   undef XOR_SWAP
  }
}

포인터(예:char *에 대한 포인터로 오른쪽에서 왼쪽으로 읽음)은 다른 값의 메모리에 있는 위치를 나타내는 데 사용되는 C의 데이터 유형입니다.이 경우, 다음과 같은 위치에서char저장됩니다.포인터 앞에 다음과 같이 추가하여 포인터의 참조를 해제할 수 있습니다.*그 위치에 저장된 값을 얻을 수 있습니다. 그서저장값에 된 값.str이라*str.

우리는 포인터로 간단한 산술을 할 수 있습니다.포인터를 증분(또는 감소)할 때 해당 유형의 값에 대한 다음(또는 이전) 메모리 위치를 참조하도록 포인터를 이동합니다.다른 유형의 포인터를 증가시키면 C에서 다른 값의 바이트 크기가 다르기 때문에 포인터가 다른 바이트 수만큼 이동할 수 있습니다.

여기서 하나의 포인터를 사용하여 처리되지 않은 첫 번째 포인터를 참조합니다.char문열자(열자()str 및()을 또 것()end . 합니다.*str그리고.*end), 을 클릭하고 포인터를 문자열 중간 안쪽으로 이동합니다.한번만str >= end다 둘 다 같 가 나 거 키 리 것 을 은 거 키 나 가 ▁either 리 ▁they ▁to ▁point▁the 둘char, 원래 가운데 줄의 길이가 그말우원그를끈길이이중상간한이래다의니것미합을고있는었다가지리고의리은를그▁which▁an▁had▁middle▁(▁our다▁the▁length)라는 뜻입니다.char뒤집을 필요는 없습니다.) 또는 모든 것을 처리했습니다.

스왑을 수행하기 위해 매크로를 정의했습니다.매크로는 C 전처리기에 의해 수행되는 텍스트 대체입니다.그것들은 기능과 매우 다르며, 그 차이를 아는 것이 중요합니다.함수를 호출하면 해당 함수는 사용자가 지정한 값의 복사본에서 작동합니다.매크로를 호출하면 단순히 텍스트 대체를 수행하므로 매크로에 지정된 인수가 직접 사용됩니다.

제가 이거만 썼으니까.XOR_SWAP매크로를 정의하는 것은 아마도 과잉 살상이었을 것입니다. 하지만 그것은 제가 무엇을 하고 있는지 더 명확하게 했습니다.C 전처리기가 매크로를 확장하면 while 루프는 다음과 같습니다.

    while (str < end)
    {
      do { *str ^= *end; *end ^= *str; *str ^= *end; } while (0);
      str++;
      end--;
    }

매크로 인수는 매크로 정의에서 사용될 때마다 한 번씩 표시됩니다.이것은 매우 유용할 수 있지만 잘못 사용할 경우 코드가 손상될 수도 있습니다.예를 들어, 증분/감소 명령과 매크로 호출을 다음과 같이 한 줄로 압축한 경우

      XOR_SWAP(*str++, *end--);

그러면 다음으로 확장됩니다.

      do { *str++ ^= *end--; *end-- ^= *str++; *str++ ^= *end--; } while (0);

이는 증가/감소 작업을 배로 늘렸지만 실제로는 스왑 작업을 수행하지 않습니다.

우리가 그 주제에 대해 이야기하는 동안, 당신은 x 또는 (^는 의미합니다.)은 의미합니다.그것은 덧셈, 뺄셈, 곱셈, 나눗셈과 같은 기본적인 산술 연산입니다. 보통 초등학교에서 가르치지 않는 것을 제외하고는요.그것은 두 정수를 조금씩 더하는 것처럼 결합하지만, 우리는 이월에 대해 신경 쓰지 않습니다.1^1 = 0,1^0 = 1,0^1 = 1,0^0 = 0.

잘 알려진 방법은 xor를 사용하여 두 값을 스왑하는 것입니다.세 인 특성 합니다: 이 xor 또는 지 기 본 속 성 때 작 에 합 동 니 문 다 의 는 세 가 ▁this 합 니 작 다 동 or 때 이 ▁because 속 tiesx ^ 0 = x,x ^ x = 0그리고.x ^ y = y ^ x 값에 x그리고.y두 가지 변수가 있다고 가정해 보겠습니다.a그리고.b에 두 의 값을 은 처 두 값 저 는 경 우 하va그리고.vb.

처음에는:a == vab == vba ^= b;now: aa == vb ^ vb^= a;b == vb ^ (va ^ vb)== v ^ (vabb ^ v)== v ^ 0a== ava ^= b;이제: a == (va ^ vb) ^ va== (va ^ va) ^ vb== 0 ^ vb== bv

그래서 값이 바뀝니다.이것은 한 가지 버그를 가지고 있습니다 - 언제.a그리고.b변수가 동일합니다.

처음에는:a == vaa ^= a;now: aa == va ^ v//        == 0a ^= a;now: a == 0 ^ 0//        == 0a ^= a;now: a == 0 ^ 0//        == 0

가 희가저 부터.str < end위 코드에서는 이런 일이 절대 일어나지 않기 때문에, 우리는 괜찮습니다.

정확성에 대해 걱정하는 동안 가장자리 케이스를 확인해야 합니다.if (str)라인은 우리에게 주어지지 않았는지 확인해야 합니다.NULL문자열 포인터입니다. 문자열 빈자열은문?은▁the열▁about▁empty는?"" ㅠㅠstrlen("") == 0그래서 우리는 초기화할 것입니다.end~하듯이str - 1그 말은 즉,while (str < end)조건은 절대 사실이 아니기 때문에 우리는 아무것도 하지 않습니다.맞는 말입니다.

탐험해야 할 C가 많습니다.재미있게 놀아요!

업데이트: mmw는 좋은 점을 제시하는데, 이것은 제자리에서 작동하기 때문에 당신이 어떻게 이것을 호출하는지 약간 조심해야 한다는 것입니다.

 char stack_string[] = "This string is copied onto the stack.";
 inplace_reverse(stack_string);

이것은 잘 작동합니다, 왜냐하면stack_string내용이 지정된 문자열 상수로 초기화되는 배열입니다.

 char * string_literal = "This string is part of the executable.";
 inplace_reverse(string_literal);

실행 시 코드에 불꽃이 발생하여 소멸합니다.ㅠㅠㅠstring_literal일반적으로 OS에서 편집할 수 없는 메모리인 실행 파일의 일부로 저장된 문자열만 가리킵니다.더 행복한 세상에서, 당신의 컴파일러는 이것을 알고, 당신이 컴파일을 시도할 때 오류를 기침하고, 당신에게 말합니다.string_literal이 유이어합니이어야 .char const *내용을 수정할 수 없기 때문입니다.하지만, 이것은 제 컴파일러가 살고 있는 세상이 아닙니다.

일부 메모리가 스택이나 힙에 있는지 확인하기 위해 시도할 수 있는 몇 가지 해킹이 있지만(따라서 편집할 수 있음), 이러한 해킹은 반드시 이식 가능한 것은 아니며 상당히 위험할 수 있습니다.하지만 저는 이에 대한 책임을 함수 호출자에게 떠넘기는 것이 무엇보다 기쁩니다.저는 그들에게 이 기능이 제 자리에서 메모리 조작을 한다고 말했습니다. 그것을 가능하게 하는 주장을 하는 것은 그들의 책임입니다.

재배치와 안전 점검뿐입니다.사용하지 않은 반품 유형도 제거했습니다.저는 이것이 안전하고 깨끗하다고 생각합니다.

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

void reverse_string(char *str)
{
    /* skip null */
    if (str == 0)
    {
        return;
    }

    /* skip empty string */
    if (*str == 0)
    {
        return;
    }

    /* get range */
    char *start = str;
    char *end = start + strlen(str) - 1; /* -1 for \0 */
    char temp;

    /* reverse */
    while (end > start)
    {
        /* swap */
        temp = *start;
        *start = *end;
        *end = temp;

        /* move */
        ++start;
        --end;
    }
}


int main(void)
{
    char s1[] = "Reverse me!";
    char s2[] = "abc";
    char s3[] = "ab";
    char s4[] = "a";
    char s5[] = "";

    reverse_string(0);

    reverse_string(s1);
    reverse_string(s2);
    reverse_string(s3);
    reverse_string(s4);
    reverse_string(s5);

    printf("%s\n", s1);
    printf("%s\n", s2);
    printf("%s\n", s3);
    printf("%s\n", s4);
    printf("%s\n", s5);

    return 0;
}

strlen이 0일 때 끝이 불량 메모리 위치를 가리키지 않도록 편집되었습니다.

당신은 당신의 것을 넣을 수 있습니다.(len/2)루프에서 테스트:

for(i = 0,k=len-1 ; i < (len/2); i++,k--)
{
        temp = str[k];
        str[k] = str[i];
        str[i] = temp;

}

이 완전한 프로그램은 제가 어떻게 해야 하는지 보여줍니다.제가 C를 쓰고 있었다는 것을 기억하세요. 대부분의 위퍼들이 어머니의 눈에 반짝거렸기 때문에 그것은 구식이고, 직업을 하고, 긴-바-이름은 수영을 위한 것입니다.당신이 원한다면 수정하세요, 저는 코드의 정확성에 더 관심이 있습니다.

NULL, 빈 문자열 및 모든 문자열 크기를 처리합니다.최대 사이즈(max(size_t))의 스트링으로 테스트를 해본 적은 없지만 작동해야 하고, 그렇게 큰 스트링을 다루고 있다면 어쨌든 당신은 미쳤어요 :-)

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

char *revStr (char *str) {
    char tmp, *src, *dst;
    size_t len;
    if (str != NULL)
    {
        len = strlen (str);
        if (len > 1) {
            src = str;
            dst = src + len - 1;
            while (src < dst) {
                tmp = *src;
                *src++ = *dst;
                *dst-- = tmp;
            }
        }
    }
    return str;
}

char *str[] = {"", "a", "ab", "abc", "abcd", "abcde"};

int main(int argc, char *argv[]) {
    int i;
    char s[10000];
    for (i=0; i < sizeof(str)/sizeof(str[0]); i++) {
        strcpy (s, str[i]);
        printf ("'%s' -> '%s'\n", str[i], revStr(s));
    }
    return 0;
}

그 결과는 다음과 같습니다.

'' -> ''
'a' -> 'a'
'ab' -> 'ba'
'abc' -> 'cba'
'abcd' -> 'dcba'
'abcde' -> 'edcba'

사용해 보십시오.

reverse_string(NULL);
reverse_string("");

for 루프 선언을 변경하여 코드를 더 짧게 만들 수 있습니다.

char* reverse_string(char *str)
{
    char temp;
    size_t len = strlen(str) - 1;
    size_t stop = len/2;
    size_t i,k;

    for(i = 0, k = len; i < stop; i++, k--)
    {
        temp = str[k];
        str[k] = str[i];
        str[i] = temp;
    }
    return str;
}

이제 아무도 포인터를 사용하지 않나요?

void inplace_rev( char * s ) {
  char t, *e = s + strlen(s);
  while ( --e > s ) { t = *s;*s++=*e;*e=t; }
}

편집: 죄송합니다. 방금 위의 XOR 예제를 확인했습니다.

void reverse(char *s)
{
  char *end,temp;
  end = s;
  while(*end != '\0'){
    end++;
  }
  end--;  //end points to last letter now
  for(;s<end;s++,end--){
    temp = *end;
    *end = *s;
    *s = temp; 
  }
}

반환문이 보이지 않고 입력 문자열을 변경하는 중입니다. 프로그래머에게 문제가 될 수 있습니다.입력 문자열을 변경할 수 없습니다.

또한, 이것은 까다로울 수 있지만, len/2는 IMO 한 번만 계산해야 합니다.

그 외에는 로스패브릭에서 언급한 문제 사례만 처리하면 됩니다.

rev {
int len = strlen(str)-1;
for ( int i =0; i< len/2 ; i++ ) {
        char t = str[i];
        str[i] = str[len-i];
        str[len-i] = t;
        }

}
/* Author: Siken Dongol */
#include <stdio.h>

int strLength(char *input) {
    int i = 0;
    while(input[i++]!='\0');
    return --i;
}

int main()
{
    char input[] = "Siken Man Singh Dongol";

    int len = strLength(input);
    char output[len];

    int index = 0;
    while(len >= 0) {
        output[index++] = input[--len];
    }

    printf("%s\n",input);
    printf("%s\n",output);
    return 0;
}

코드가 불필요하게 복잡해 보입니다.내 버전은 다음과 같습니다.

void strrev(char* str) { 
    size_t len = strlen(str);
    char buf[len]; 

    for (size_t i = 0; i < len; i++) { 
        buf[i] = str[len - 1 - i]; 
    }; 

    for (size_t i = 0; i < len; i++) { 
        str[i] = buf[i]; 
    }
}

여기 제 주사가 있습니다.표준을 사용하는 것만으로 스와핑을 피할 수 있습니다.strcpy패턴:

char *string_reverse(char *dst, const char *src)
{
    if (src == NULL) return NULL;

    const char *src_start = src;
    char *dst_end = dst + strlen(src);
    *dst_end = '\0';

    while ((*--dst_end = *src_start++)) { ; }

    return dst;
}

그리고 여기 실행 중인 예가 있습니다.

bool reverse_string(char* str) {
    if(str == NULL){
        return false;
    }
    if(strlen(str) < 2){
        return false;
    }
    
    char* first = str;
    char* last = str + strlen(str) - 1; // Minus 1 accounts for Index offset
    char temp;

    do{
        temp = *first;
        *first = *last;
        *last = temp;
    }
    while (++first < --last); // Update Pointer Addresses and check for equality

    return true;
}

이 솔루션은 몇 가지 수정 사항이 있는 GManNickG의 게시물을 기반으로 합니다.strlen 연산 전에!str을 평가하지 않으면 초기 논리문이 위험할 수 있습니다(NULL ptr의 경우).내 컴파일러는 그렇지 않았습니다.저는 이 코드를 추가하려고 생각했습니다. 왜냐하면 이 코드는 do-while 루프의 좋은 예이기 때문입니다.

당신이 화려해지고 싶다고 말했기 때문에, 아마도 당신은 XOR 스왑을 사용하여 당신의 캐릭터를 교환하고 싶을 것입니다.

중간에 돌파하기보다는 단순히 루프를 단축해야 합니다.

size_t length = strlen(str);
size_t i;

for (i = 0; i < (length / 2); i++)
{
    char temp = str[length - i - 1];
    str[length - i - 1] = str[i];
    str[i] = temp;
}
#include <stdio.h>
#include <string.h>

int main() 
{
    char *data = "hello world";
    int length=strlen(data);
    char bytes[length];
    int n=0;
    while(n<=length)
    {
       bytes[n] = data[length-n-1];
       n++;
    }
    printf("%s\n", bytes);
    return 0;   
}
#include <stdio.h>

int main()    
{

    char string[100];
    int i;

    printf("Enter a string:\n");
    gets(string);
    printf("\n");
    for(i=strlen(string)-1;i>-1;i--)

    printf("%c",string[i]);
}
Here is my shot which will handle all the cases 
char *p ="KDLAKDADKADAD"
char p[] = "lammdlamldaldladadada"
also empty string 

#include<stdio.h>
#include<string.h>enter code here
#include<stdlib.h>
char *string_reverse(char *p);
int main()
{

        char *p = " Deepak@klkaldkaldkakdoroorerr";
        char *temp = string_reverse(p);
        printf("%s", temp);
}
char *  string_reverse( char *p )
{

        if(*p == '\0')
        {
                printf("No charecters are present \n");
                return 0;
        }
        int count = strlen(p)+1;
        int mid = strlen(p)/2;
        char *q  = (char *)malloc(count * sizeof(char));
        if( q )
        {
                strcpy(q,p);
                char *begin,*end,temp;
                begin = q ;
                end = q+strlen(p)-1  ;
                int i = 0;
                while( i < mid/2 )
                {
                        temp = *end;
                        *end = *begin;
                        *begin = temp;
                        begin++;
                        end--;
                        i++;
                }
                return q;
        }
        else
        {

                printf("Memory Not allocated ");
        }
        free(q);
}

쉽고 간단한 코드 xD

void strrev (char s[]) {

int i;
int dim = strlen (s);
char l;

for (i = 0; i < dim / 2; i++) {
    l = s[i];
    s[i] = s[dim-i-1];
    s[dim-i-1] = l;
    }

}

다음 포인터 산술을 시도할 수 있습니다.

void revString(char *s)
{
  char *e = s; while(*e){ e++; } e--;
  while(e > s){ *s ^= *e; *e ^= *s; *s++ ^= *e--; }
}

내 2센트야.

/* Reverses n characters of a string and adds a '\0' at the end */
void strnrev (char *txt, size_t len) {
    size_t idx;
    for (idx = len >> 1; idx > 0; idx--) {
        txt[len] = txt[idx - 1];
        txt[idx - 1] = txt[len - idx];
        txt[len - idx] = txt[len];
    }
    txt[len] = '\0';
}

/* Reverses a null-terminated string */
void strrev (char *txt) {
    size_t len = 0;
    while (txt[len++]);
    strnrev(txt, --len);
}

테스트 #1strrev():

char string[] = "Hello world!";
strrev(string);
printf("%s\n", string); // Displays "!dlrow olleH"

테스트 #2strnrev():

char string[] = "Hello world!";
strnrev(string, 5);
printf("%s\n", string); // Displays "olleH"

실제로 다음과 같은 작업을 수행할 수 있습니다.

#include <string.h>

void reverse(char *);

int main(void){
 char name[7] = "walter";
 reverse(name);
 printf("%s", name);
}

void reverse(char *s) {
  size_t len = strlen(s);
  char *a = s;
  char *b = &s[(int)len - 1];
  char tmp;
  for (; a < b; ++a, --b) {
    tmp = *a;
    *a = *b;
    *b = tmp;
  }
}

다음을 달성하는 작은 프로그램을 만들었습니다.

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

int main()
{
    char str[8192] = "string"; // string
    size_t len = strlen(str)-1; // get string length and reduce 1

    while(len+1 > 0) // Loop for every character on string
    {
        printf("%c",str[len--]); // Print string reversed and reducing len by one
    }
    return 0; // Quit program

}

설명:
문자열의 길이를 측정한 다음 인덱스 0 종료 프로그램에 도달할 때까지 마지막 위치로 루프하기 시작합니다.

포인터의 도움으로 다음과 같은 간단한 단계를 쉽게 수행할 수 있습니다.

  1. 먼저 포인터를 문자열의 마지막 문자로 가리킵니다.

  2. 포인터가 가리키는 내용을 역순으로 읽습니다.

    #http <stdio.#filen <string.h>

         int main()
         {
             char str[] = "This is an example";
             char *p = str + strlen(str); /* point to the end of the string */
             p--; /* points to the last char of the string */
    
             for (int i = 0; i < strlen(str); i++, p--)
             {
                printf("%c", *p);
             }
    
             return 0;
         }
    

2009년의 좋은 질문입니다.독립 실행형 기능을 사용하여 문자열을 반전시킬 수 있습니다.코드는...

#include <stdio.h>
#define MAX_CHARACTERS 99

int main( void );
int strlen( char __str );

int main() {
    char *str[ MAX_CHARACTERS ];
    char *new_string[ MAX_CHARACTERS ];
    int i, j;

    printf( "enter string: " );
    gets( *str );

    for( i = 0; j = ( strlen( *str ) - 1 ); i < strlen( *str ), j > -1; i++, j-- ) {
        *str[ i ] = *new_string[ j ];
    }
    printf( "Reverse string is: %s", *new_string" );
    return ( 0 );
}

int strlen( char __str[] ) {
    int count;
    for( int i = 0; __str[ i ] != '\0'; i++ ) {
         ++count;
    }
    return ( count );
}

가장 쉬운 방법은 이 기능을 사용하면 됩니다. 사용법을 참조하십시오.함수:

char *reversed(char *string) {
    int len = strlen(string);
    char newstr[256];
    for (int i = 0; i <= len-1; i++) {
        newstr[i] = string[(len-1)-i];
    }
    string = newstr;
    return string;
}

사용법 :

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


char *reversed(char *string);
int main()
{
    char test[] = "test";
    char *res = reversed(test);
    printf("%s\n", res);

    return 0;
}
char *reversed(char *string) {
    int len = strlen(string);
    char newstr[256];
    for (int i = 0; i <= len-1; i++) {
        newstr[i] = string[(len-1)-i];
    }
    string = newstr;
    return string;
}

포인터에 할당하는 것을 잊지 마십시오. char *res = reversed(test)

언급URL : https://stackoverflow.com/questions/784417/reversing-a-string-in-c

반응형