이 간단한 문자열 할당 segfault가 왜 있습니까?
-
03-07-2019 - |
문제
다음 코드가 있습니다.
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char* b = "bar";
a = b;
cout << a << ", " << b << endl;
return 0;
}
이것은 컴파일하고 작동합니다. 인쇄물 bar,
bar
. 이제 여기서 일어나는 일은 문자열을 복사하지 않는다는 것을 보여주고 싶습니다. 나는 바꾸고 싶다 b
그리고 그것을 보여줍니다 a
또한 변경됩니다. 이 간단한 코드를 생각해 냈습니다.
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char* b = "bar";
a = b;
b[1] = 'u'; // ← just this line added
cout << a << ", " << b << endl;
return 0;
}
… 그러나 그것은 segfaults. 왜요? 흥미로운 점은 다음 수정이 잘 실행된다는 것입니다.
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char b[] = "bar"; // ← declaration changed here
a = b;
b[1] = 'u';
cout << a << ", " << b << endl;
return 0;
}
왜 이전 것과 같이 segfault가 아닌가? 포인터 스타일과 배열 스타일 문자열 초기화 사이의 중요한 차이가 누락 된 것 같습니다.
해결책
문자열 상수를 변경할 수 없습니다. 첫 번째 코드 샘플에서와 같이 포인터 투리어 문자 구문을 사용할 때 얻을 수 있습니다.
이 질문도 참조하십시오. C ++의 문자열 문자가 정적 메모리로 생성됩니까?.
다른 팁
이것을 쓸 때 :
char *b = "bar";
컴파일러는 익명 (이름이없는) 메모리 영역을 할당하여 문자열 문자 "막대"를 저장합니다. 문자열 리터럴을 수정할 수 없으므로 컴파일러 (링커 및 운영 체제의 도움으로)는 문자열을 쓰기로 보호되는 실행 프로그램의 메모리 공간의 일부에 문자열을 놓습니다. 이를 수정하려고하면 운영 체제가이를 잡아 프로그램을 세분화 오류로 만듭니다.
(코드는 C가 아닌 C ++이지만이 질문과 관련이 없습니다.)
당신이 쓸 때 :
char *foo = "bar";
실제로 발생하는 것은 "막대"가 메모리의 읽기 전용 세그먼트에 저장된다는 것입니다. 그러므로 그것은 불변입니다. 읽기 전용 세그먼트를 수정하려고하므로 segfault를 얻습니다.
또한 포인터의 값을 인쇄하여 'A'가 변경되었음을 보여줄 수 있습니다.
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char* b = "bar";
a = b;
cout << (void*)a << ", " << (void*)b << endl;
}
이것은 'a'와 'b'가 지적한 주소를 인쇄합니다.
연산자 <<이 'char*'에 과부하되어 다른 포인터가 주소를 인쇄 할 수 있도록 'char*'가 과부하되므로 'void*'로 캐스트해야합니다.
이론적으로 문자열 문자는 숯*에 할당 할 수 없으며 'const char*'만 할당 할 수 없어야합니다. 그런 다음 Seg Faulting 코드를 작성하기 전에 컴파일러가 중지됩니다.
이 차이는 아마도 컴파일러에 따라 다릅니다. 포인트를 시연하려면 Malloc을 사용하여 버퍼를 할당 한 다음이 버퍼에 문자열을 복사하고 더 이상 문자열이 필요하지 않을 때 무료 사용을 잊지 마십시오.