이 문자열 반전 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
문자열 리터럴에서 초기 값을 복사합니다.그 후 당신의s
array와 문자열 리터럴은 완전히 독립적인 개체로 계속 존재합니다.리터럴은 여전히 수정할 수 없습니다.s
배열은 수정 가능합니다.
기본적으로 후자의 선언은 기능적으로 다음과 같습니다.
char s[11];
strcpy(s, "teststring");
여러 가지 이유로 코드가 segfault일 수 있습니다.여기에 떠오르는 것들이 있습니다.
- s는 NULL
- s는 읽기 전용 메모리에 저장된 제약 문자열을 가리킵니다.
- 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
'programing' 카테고리의 다른 글
커널 프로그래밍에서 서명되지 않은 int 대신 u8 u16 u32 u64가 사용되는 이유는 무엇입니까? (0) | 2023.10.20 |
---|---|
C++에 오버로드 기능이 추가된 이유는 무엇입니까? (0) | 2023.10.20 |
여러 문자열을 한 번에 바꾸기 (0) | 2023.10.20 |
SQL 쿼리를 통해 모든 제품, 카테고리 및 메타데이터 우커머스/워드프레스를 얻을 수 있습니다. (0) | 2023.10.20 |
GCC의 __thread는 어떻게 구현됩니까? (0) | 2023.10.20 |