programing

이 문자열 반전 C 코드가 세그먼트 오류를 일으키는 이유는 무엇입니까?

topblog 2023. 10. 20. 13:23
반응형

이 문자열 반전 C 코드가 세그먼트 오류를 일으키는 이유는 무엇입니까?

문자열을 제자리에 되돌리기 위해 코드를 작성하려고 하는데(C 프로그래밍 및 포인터 조작을 더 잘하려고 할 뿐입니다), 왜 분할 오류가 발생하는지 알 수 없습니다.

#include <string.h>

void reverse(char *s);

int main() {
    char* s = "teststring";
    reverse(s);

    return 0;
}

void reverse(char *s) {
    int i, j;
    char temp;

    for (i=0,j = (strlen(s)-1); i < j; i++, j--) {
        temp = *(s+i);     //line 1
        *(s+i) = *(s+j);   //line 2
        *(s+j) = temp;     //line 3
    }
}

세그멘테이션 폴트의 원인이 되는 것은 2호선과 3호선입니다.더 나은 방법이 있을 수도 있다는 것은 이해하지만, 제 코드에 구체적으로 무엇이 세그멘테이션 오류를 야기하는지 알고 싶습니다.

업데이트: 요청하신 대로 통화 기능을 포함하였습니다.

그 코드만 가지고는 말할 수 없습니다.잘못된 메모리, 수정할 수 없는 메모리 또는 여기서 처리하는 방식으로는 처리할 수 없는 다른 종류의 메모리를 가리키는 포인터를 보내고 있을 가능성이 높습니다.

함수를 어떻게 부르십니까?

Added: 문자열 리터럴에 포인터를 전달하고 있습니다.문자열 리터럴은 수정할 수 없습니다.문자열 리터럴은 되돌릴 수 없습니다.

대신 포인터를 수정 가능한 문자열로 전달

char s[] = "teststring";
reverse(s); 

이것은 이미 여기서 죽을 정도로 설명이 되어 있습니다."teststring"문자열 리터럴입니다.문자열 리터럴 자체가 수정할 수 없는 개체입니다.실제로 컴파일러는 읽기 전용 메모리에 그것을 넣을 수 있습니다.이렇게 포인터를 초기화할 때

char *s = "teststring";

포인터가 문자열 리터럴의 처음을 직접 가리킵니다.무엇을 수정하려는 시도가s는 일반적인 경우에 실패한 것으로 간주됩니다.읽을 수는 있지만 쓸 수는 없습니다.이러한 이유로 포인터-투-콘스트 변수만 있는 문자열 리터럴을 가리키는 것이 매우 권장됩니다.

const char *s = "teststring";

하지만 당신이 당신의 것을 선언할 때.s~하듯이

char s[] = "teststring";

완전히 독립적인 배열을 얻을 수 있습니다.s문자열 리터럴로 초기화된 보통의 수정 가능한 메모리에 위치합니다.이것은 그 독립적인 수정 가능한 배열이s문자열 리터럴에서 초기 값을 복사합니다.그 후 당신의sarray와 문자열 리터럴은 완전히 독립적인 개체로 계속 존재합니다.리터럴은 여전히 수정할 수 없습니다.s배열은 수정 가능합니다.

기본적으로 후자의 선언은 기능적으로 다음과 같습니다.

char s[11];
strcpy(s, "teststring");

여러 가지 이유로 코드가 segfault일 수 있습니다.여기에 떠오르는 것들이 있습니다.

  1. s는 NULL
  2. s는 읽기 전용 메모리에 저장된 제약 문자열을 가리킵니다.
  3. s가 NULL이 종료되지 않았습니다.

2번이 가장 유력한 것 같습니다.리버스의 콜 사이트를 보여줄 수 있습니까?

편집

당신의 샘플 #2를 보면 확실히 답이 됩니다.C/C++의 문자열 리터럴은 수정할 수 없습니다.적절한 유형은 사실.const char* 안 돼요.char*. 수정 가능한 문자열을 해당 버퍼에 전달해야 합니다.

간단한 예:

char* pStr = strdup("foobar");
reverse(pStr);
free(pStr);

이런 거 테스트하는 거예요?

int main() {
    char * str = "foobar";
    reverse(str);
    printf("%s\n", str);
}

이렇게 하면 문자열이 문자 그대로 사용되므로 편집할 수 없습니다(segfaults).정의할 경우char * str = strdup(foobar)잘 될 겁니다.

귀하의 선언은 완전히 잘못된 것입니다.

char* s = "teststring";

"teststring"은 코드와 마찬가지로 읽기 전용인 코드 세그먼트에 저장됩니다.그리고 s는 "teststring"에 대한 포인터이며 동시에 읽기 전용 메모리 범위의 값을 변경하려고 합니다.따라서 분할 오류가 발생합니다.

그러나 사용:

char s[] = "teststring";

s는 "teststring"으로 초기화되며, 물론 코드 세그먼트에 있지만 이 경우 스택에 대한 추가 복사 작업이 진행됩니다.

C FAQ 목록의 질문 1.32 참조:

이러한 초기화의 차이점은 무엇입니까?

char a[] = "string literal";
char *p  = "string literal";

새 값을 할당하려고 하면 프로그램이 충돌합니다.p[i].

답변:

문자열 리터럴(C 소스에서 큰 따옴표가 달린 문자열의 공식 용어)은 다음과 같은 두 가지 방식으로 사용할 수 있습니다.

다음의 선언과 같이 char 배열의 이니셜라이저로서char a[], 배열에 있는 문자의 초기 값(및 필요한 경우 크기)을 지정합니다.

다른 곳에서는 이름 없는 정적 문자 배열로 바뀌고, 이 이름 없는 배열은 읽기 전용 메모리에 저장될 수 있으므로 반드시 수정할 수는 없습니다.식 컨텍스트에서 배열은 평소와 같이 포인터로 한 번에 변환되므로(섹션 6 참조), 두 번째 선언은 초기화됩니다.p이름 없는 배열의 첫 번째 요소를 가리킵니다.

어떤 컴파일러들은 (오래된 코드를 컴파일하기 위해) 문자열 리터럴이 쓰기 가능한지 아닌지를 제어하는 스위치를 가지고 있고, 어떤 컴파일러들은 문자열 리터럴이 공식적으로 배열로 취급되도록 하는 옵션을 가지고 있을 수 있습니다.const char(오류를 더 잘 잡기 위해).

(emphasis 광산)

Joel의 Back to Basics도 참조하십시오.

어떤 컴파일러와 디버거를 사용하고 계십니까?gcc와 gdb를 이용하여 -g 플래그로 코드를 컴파일한 후 gdb에서 실행합니다.그것이 고장이 났을 때, 나는 그냥 역추적(bt commanding gdb)을 하고 어떤 라인이 문제를 일으키는지 확인할 것입니다.또한 gdb에서 포인터 값을 "감시"하면서 코드를 단계적으로 실행하고 정확하게 어디가 문제인지 알 것입니다.

행운을 빌어요.

위에 제시된 답변 중 일부와 같이 문자열 메모리는 읽기 전용입니다.그러나 일부 컴파일러는 쓰기 가능 문자열로 컴파일하는 옵션을 제공합니다.예를 들어 와 함께gcc, 지원되는 3.x 버전-fwritable-strings하지만 새로운 버전은 그렇지 않습니다.

s가 NULL이 종료되지 않아 작업이 불가능할 것 같습니다.그래서 반복에 대한 당신의 행동은 당신이 기대하는 행동이 아닙니다.strlen의 결과가 길이보다 우수하기 때문에 당신이 있어서는 안 되는 곳에 기억을 남기게 될 것입니다.

또한 읽기 전용 메모리에 의해 유지되는 일정한 문자열을 가리킵니다.수정할 수 없습니다.strlen 예제에서와 같이 gets 함수를 사용하여 init을 시도합니다.

언급URL : https://stackoverflow.com/questions/1614723/why-is-this-string-reversal-c-code-causing-a-segmentation-fault

반응형