2010-11-18 6 views
2

을 삭제 내 코드입니다.
두 번째 줄은 문자열 길이가
인 새로운 문자 배열 (c-string)을 만듭니다. 세 번째 줄은 문자열을 읽습니다. (파일에서 읽음)
네 번째 줄은 끝에 NULL을 추가합니다.
다섯 번째 줄은 C 문자열에서 std :: string을 만듭니다.
여섯 번째 줄은 C 문자열을 삭제합니다 (힙 손상은 여기에 있습니다)
7 번째 줄은 문자열을 반환하지만 오류로 인해이 지점에 도달하지 않습니다.힙 손상 문자열 여기

6 번째 줄에서 힙 손상 오류가 발생했습니다. CRT가 응용 프로그램이 힙 버퍼의 끝 뒤에 메모리에 쓴 것을 감지했습니다.

제 질문은 분명 할 수 있지만 왜 힙 손상이 발생합니까? std :: string을 만들면 문자열을 복사해야하므로 C 문자열을 삭제해도 안전합니다.

현재 std :: string은 삭제 한 후 C 문자열에 액세스하려고합니다.

아이디어가 있으십니까?

+0

코드에 [delete]가 있습니다. 따라서 코드가 잘못되었습니다. 'std :: vector' 또는 무엇인가를 사용하거나 심지어 문자열을 직접 읽어 들일 수도 있습니다. – GManNickG

+0

@GMan : 내가 게시하기 전에 귀하의 의견조차 보지 못했습니다 : 그것은 너무 코드를 단순화하는 방법은 놀라운 일입니다 ... –

답변

4

변경 :

char* rawString = new char[strLen]; 

에 : 당신이 크기 strLen의 배열을 만든 다음 위치 strLen에 0을 배치 할 때

배열은 C++로 0에 연동되어 있기 때문에
char* rawString = new char[strLen + 1]; 
+0

고마워. 나는 그런 것을 간과했다고 믿을 수 없다. 나는 C++을 잠시 사용하고있다 :). 이것에 도움을 게시 한 다른 모든 사람들에게 감사드립니다! – Brad

2

int strLen = Read<int>()아마 만이 아닌 null로 끝나는 문자열의 길이를 반환하고 문자열로 \0 바이트를 작성하려고 할 때 버퍼 오버 플로우 문제로 실행합니다.

당신은 strLen이 무엇인지 확인해야하고, 중 당신에게 가장 가능성은 다음과 같이 할당 할 필요가 :

char *rawString = new char[strlen+1]; 

을 또는이 같은 std::string(const char *, size_t n)의 오버로드 된 생성자 사용

std::string retVal(rawString, strlen); 
8

당신은 액세스하는을 문자열의 예약 된 바이트를 지나서. strLen 문자를 예약했지만 strLen 문자로 \0을 넣었습니다. 0에서 C 배열로 계산하면 문자 strLenstrLen + 1 위치에 있으므로 문자열의 예약 공간 밖에 값을 넣을 수 있습니다. 코드가 작동하려면 main의 두 번째 줄에 strLen + 1을 예약해야합니다.

1

, 당신이 할당 한 배열의 끝에서 0을 쓰는 것입니다.

0
rawString[strLen] = '\0'; 

할당 한 공간의 끝 부분에서 NUL을 씁니다.

strLen이 10이면 10자를위한 공간을 할당하고 10자를 읽고 11의 위치에 NUL을 씁니다.Ooops

1

지금까지 많은 권고 사항이 있지만 예외 안전 문제를 해결하지 못했습니다. 어떻게 잠재적 메모리 누수를 제거 할 수 있습니까?

new으로 할당하는 것을 피하기 위해 (따라서 메모리 누수가 발생하는) 두 가지 방법이 있습니다. , datastring 당신이 G 맨에 (덕분에 액세스 할 수있는 내부 버퍼를 가지고 : 첫 번째는 매우 간단하고 가변 길이 배열에 대한 VLA로 알려진 컴파일러 확장을 사용합니다 :

std::string readString() 
{ 
    int strLen = Read<int>(); 
    char rawString[strLen+1]; // VLA: the length is determined at runtime 
          // but the array is nonetheless on the stack 
    Read(rawString, strLen); 
    rawString[strLen] = '\0'; 

    std::string retVal(rawString); 
    return retVal; 
} 

다른 표준을 준수 올바른 액세스 방법이 아닙니다.

std::string readString() 
{ 
    int strLen = Read<int>(); 

    std::string retVal(strLen, '\0'); // no need to allocate extra space 

    Read(&retVal[0], strLen);  // &retVal[0] gives access to the buffer 

    return retVal; 
} 

나는 지난 버전이 훨씬 더 좋다고 생각합니다. 더 이상 복사가 필요하지 않습니다.

+0

전자는 실제로 비표준 C++입니다. 두 번째는 const 액세스 만 제공합니다. : S 당신은'vector'를 읽거나 문자열을 예약하고'& retVal [0]'을 읽어 들여서 연속적인 버퍼를 뱉어 버리고 싶습니다. 오, 그리고 당신은 "매우 간단하게"합니다. :) – GManNickG

+0

@GMan : 쓰레기, 나는 두 가지 버전의'data'가 있다고 생각했다. 나는 이전이 비표준 적이라는 것을 정확히 했었는데, 나는 그것이 컴파일러 확장 (그리고 좋은 것 ...) –