답변:
표준 알고리즘은 시작 / 끝에 대한 포인터를 사용하여 중간에서 만나거나 교차 할 때까지 안쪽으로 걷습니다. 당신이 갈 때 스왑.
역 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 루프 바디가 얼마나 복잡한 지 확인할 수 있습니다 .)
(이 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;
}
예 :
$ ./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;
}
}
s
은 배열 형식으로 선언해야합니다. 다시 말해서, 후자는 문자열 상수를 수정할 수 없기 때문에 char s[] = "this is ok"
오히려 char *s="cannot do this"
수정할 수 없습니다.
문자열이 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--;
}
}
int temp
솔루션이 가장 좋습니다. +1
!(*str)
.
strchr()
검색 중 '\0'
. 나는 둘 다 생각했다. 루프가 필요하지 않습니다.
std::reverse
C ++ 표준 라이브러리의 알고리즘을 사용 합니다.
오랜 시간이 지났는데 어떤 알고리즘이 저에게이 알고리즘을 가르쳐 주 었는지 기억이 나지 않지만 이해하기가 매우 독창적이고 간단하다고 생각했습니다.
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
.
STL 의 std :: 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));
}
*
하여 유형별로 넣지 않고 오히려 이름으로 넣는 것을 보는 것은 아름답고 아름답고 절대적으로 아름다운 것 입니다. 훌륭한. 나는 내가 순수 주의자라는 것을 인정하지만 같은 코드를 볼 때마다 울었다 char* 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
strlen
잠재적으로 긴 경우 문자열의 끝을 찾는 데 사용 합니다. 좋은 라이브러리 구현은 SIMD 벡터를 사용하여 반복 당 1 바이트보다 빠르게 검색합니다. 그러나 매우 짧은 문자열의 while (*++end);
경우 라이브러리 함수 호출이 검색을 시작하기 전에 수행됩니다.
_mm_shuffle_epi8
(PSHUFB)는 오른쪽 셔플 제어 벡터가 주어지면 16B 벡터의 순서를 반대로 할 수 있습니다. 특히 AVX2에서 신중하게 최적화하면 거의 memcpy 속도로 실행될 수 있습니다.
char* beg = s-1
정의되지 않은 동작이 있습니다 (적어도 s
가장 일반적인 경우는 배열의 첫 번째 요소를 가리키는 경우). 빈 문자열 인 while (*++end);
경우 정의되지 않은 동작 s
이 있습니다.
s-1
도 동작을 정의한 주장을 하고 s
있으므로 표준을지지 할 수 있어야합니다.
#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;
}
char
을 스택에 밀어 넣는 것은 "정 위치"로 계산되지 않습니다. 실제로 실제로 문자 당 4 * 8B (64 비트 시스템 : 3 args + return address)를 푸시 할 때는 아닙니다.
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");
}
내 대답은 대부분과 비슷하지만 여기에서 내 코드를 찾으십시오.
//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 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;
}
strlen()
루프 조건 및 루프 본문에서 호출하면 최적화되지 않을 수 있습니다.
다음은 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
추가 작업이 필요하지 않습니다 .
#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 언어로 최적화 된 코드입니다 ... 그리고 간단합니다. 간단한 포인터를 사용하여 작업을 수행하십시오 ...