이 문자열 반전 C 코드가 분할 오류를 일으키는 이유는 무엇입니까?[복제하다]

StackOverflow https://stackoverflow.com/questions/1614723

  •  06-07-2019
  •  | 
  •  

문제

문자열을 제자리에서 뒤집는 코드를 작성하려고 합니다(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입니다.이 작업을 수행하는 더 좋은 방법이 있을 수 있다는 것을 이해하지만 구체적으로 무엇인지 알아보고 싶습니다. 내 코드에서 분할 오류가 발생하고 있습니다.

업데이트:요청하신 대로 호출 기능을 포함시켰습니다.

도움이 되었습니까?

해결책

그 코드만으로는 말할 방법이 없습니다.아마도 유효하지 않은 메모리, 수정할 수 없는 메모리 또는 여기에서 처리하는 방식으로 처리할 수 없는 다른 종류의 메모리를 가리키는 포인터를 전달하고 있을 가능성이 높습니다.

함수를 어떻게 호출하나요?

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

대신 수정 가능한 문자열에 대한 포인터를 전달하세요.

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

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

char *s = "teststring";

포인터는 문자열 리터럴의 시작 부분을 직접 가리킵니다.무엇을 수정하려는 시도 s 일반적인 경우 실패로 간주된다는 점을 지적하고 있습니다.읽을 수는 있지만 쓸 수는 없습니다.이러한 이유로 포인터-상수 변수만 사용하여 문자열 리터럴을 가리키는 것이 좋습니다.

const char *s = "teststring";

하지만 당신이 선언할 때 s ~처럼

char s[] = "teststring";

완전히 독립적인 배열을 얻습니다. s 일반 수정 가능한 메모리에 위치합니다. 초기화됨 문자열 리터럴로.이는 독립적인 수정 가능한 배열을 의미합니다. s 초기값을 얻게 됩니다 복사됨 문자열 리터럴에서.그 후에는 당신의 s 배열과 문자열 리터럴은 완전히 독립적인 개체로 계속 존재합니다.리터럴은 여전히 ​​수정할 수 없지만 s 배열은 수정 가능합니다.

기본적으로 후자의 선언은 기능적으로 다음과 동일합니다.

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

다른 팁

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

  1. s는 null입니다
  2. s는 읽기 전용 메모리에서 고정 된 const 문자열을 가리 킵니다.
  3. s는 널 종료되지 않습니다

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

이것은 str을 문자 그대로 만들고 아마도 그것을 편집 할 수 없을 것입니다 (segfaults). 당신이 정의하는 경우 char * str = strdup(foobar) 잘 작동해야합니다 (나를 위해).

귀하의 선언은 완전히 잘못되었습니다.

char* s = "teststring";

"TestString"은 코드 세그먼트에 저장되며 코드와 같이 읽기 전용입니다. 그리고 S는 "TestString"에 대한 포인터이며 동시에 읽기 전용 메모리 범위의 값을 변경하려고합니다. 따라서 분할 결함.

하지만 함께:

char s[] = "teststring";

S는 물론 코드 세그먼트에있는 "TestString"으로 초기화되지만이 경우 스택에는 추가 사본 작업이 진행됩니다.

어떤 컴파일러 및 디버거를 사용하고 있습니까? GCC 및 GDB를 사용하여 -G 플래그로 코드를 컴파일 한 다음 GDB로 실행합니다. Segfaults에서, 나는 단지 뒤에서 (GDB의 BT 명령)를 수행하고 문제를 일으키는 문제를 해결하는 선을 보게 될 것입니다. 또한 GDB의 포인터 값을 "시청"하면서 코드를 단계별로 실행하고 문제가 정확히 어디에 있는지 알 수 있습니다.

행운을 빕니다.

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

보다 질문 1.32 C FAQ 목록에서:

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

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

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

답변:

문자열 리터럴(C 소스에서 큰따옴표로 묶인 문자열에 대한 공식 용어)은 두 가지 약간 다른 방식으로 사용될 수 있습니다.

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

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

일부 컴파일러에는 문자열 리터럴의 쓰기 가능 여부(이전 코드 컴파일용)를 제어하는 ​​스위치가 있고, 일부 컴파일러에는 문자열 리터럴이 공식적으로 배열로 처리되도록 하는 옵션이 있을 수 있습니다. const char (더 나은 오류 잡기를 위해).

(내 강조)

또한보십시오 기본으로 돌아가기 ~에 의해 조엘.

제 생각에는 strlen S가 종료되지 않으므로 작동 할 수 없습니다. 따라서 반복을위한 행동은 당신이 기대하는 행동이 아닙니다. strlen의 결과는 S 길이보다 우수하기 때문에 당신은 당신이하지 말아야 할 곳에 메모리에 쓸 것입니다.

또한 S는 읽기 전용 메모리에 의해 일정한 문자열을 가리 킵니다. 수정할 수 없습니다. gets 함수를 사용하여 S에서 시작하려고 노력하십시오. Strlen 예시

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top