2014-12-19 6 views
0

필자는 원하는만큼 문자를 그려야합니다. 그래서 나는 그 목적을 위해 함수를 쓴 : 그것은 어떤 경고를 완벽하게 구축되지 오류 것strcat가 충돌 프로그램을 만듭니다 (0xc0000005)

80로 정의

void fDrawLine(int length) 
{ 
    int i; 
    char * compLine = (char *) malloc(WINDOW_WIDTH + 2); 

    for(i = 0; i < length; i++) 
     strcat(compLine, "-"); 

    fDrawSpacedMessage(compLine, -1, TRUE); 
} 

WINDOW_WIDTH, fDrawSpacedMessage 다른 텍스트를 인쇄하는 기능을 중심으로 등이다. 그러나 런타임에서는 모든 것이 작동하지만 fDrawLine이 실행되면 프로그램이 충돌하고 오류 코드 0xc0000005가 발생합니다. 메모리 할당에 대해서는 알고 있지만 이미 compLine 문자열을 초기화했습니다.

나는 두 가지를 시도했다. 나는 다른 기능이 그것을 일으켜서 내가 fDrawLine을 고립 시켰다고 생각했지만 계속 충돌했다. compLine[0] = 0;, compLine[WINDOW_WIDTH] = {0};으로 초기화를 변경해도 도움이되지 않았습니다.

우분투가 최신 gcc로 실행되는 다른 컴퓨터에서도 잘 작동하지만 Windows에서 Code :: Blocks (MinGW)를 사용하면 충돌이 계속 발생합니다.

이 코드의 잘못된 점은 무엇입니까?

+1

fDrawSpacedMessage에 '-'? 또한 '길이'의 가치는 무엇입니까? – i486

+0

학교 프로젝트이므로 코드 작성을 배우는 것 같습니다. 다른 것들은 제쳐두고, 당신의 함수를보고 다음 질문에 대답 : 무엇 전화 'fDrawLine (WINDOW_WIDTH * 2);'실제로합니까? 방어 프로그래밍을 배우십시오 – kdopen

+0

1) '길이'가 너무 크지 않도록 보장해야합니다. 'assert (length <(WINDOW_WIDTH + 1));를 추가하십시오. 2)'2'는 여기에있는 매직 넘버입니다. 2에 대한 세부 정보를 제공 하시겠습니까? ('fDrawSpacedMessage()'가 81 개의 "---...--"를 표시하려고 실패 할 수 있습니까?) – chux

답변

1

할당 된 메모리가 가비지를 포함하기 시작합니다. compLine를 선언 첫째, 당신은 것을 필요로하지 않기 때문에, 포인터로

compLine[0] = '\0'; 
선언하지 마십시오
+1

그는 이것이 도움이되지 않는다고 말했습니다. – i486

+2

다른 오류가있을 수 있습니다. 아직까지도 문제를 보여주는 완벽하고도 최소한의 예는 보지 못했기 때문에 말하기는 어렵습니다. –

1

compLine을, 실제로 당신은 당신의 기능에서 메모리 누수가이 같은 예를 들어, 빈 문자열로 설정 이 방법

char compLine[1 + WINDOW_WIDTH] = {0}; // strings need an extra byte at the end to mark the end. 

는 t 확인 과정이

memset(compLine, '-', length); 

처럼 '-' 문자를 설정 memset를 사용 모자 length <= WINDOW_WIDTH.

은 함수가 고정되어, 그래서 당신은, 당신이이

char *compLine = malloc(1 + length); // the last extra '\0' byte. 
if (compLine == NULL) // malloc returns NULL on failure to allocate memory 
    return; // so we must abort this function in that case. 
for(i = 0; i < length; i++) 
    compLine[i] = '-'; 
compLine[length] = '\0'; 

fDrawSpacedMessage(compLine, -1, TRUE); 
free(compLine); 

당신은 또한에 memset을 사용할 수 있습니다 할 수있는 방법입니다 나쁜 생각을 strcat을 사용하는 외에 그것을

void fDrawLine(int length) 
{ 
    char compLine[1 + WINDOW_WIDTH] = {0}; // initialized so that last byte is '\0'. 
    if (length > WINDOW_WIDTH) 
     length = WINDOW_WIDTH; 
    memset(compLine, '-', length);   
    fDrawSpacedMessage(compLine, -1, TRUE); 
} 

을 시도 할 수 있습니다 이 경우 실제로 더 좋습니다.

+1

큰 성능 차이는 없지만 전체 배열을 '0'으로 초기화하는 대신 첫 번째 예제에서'compLine [length]'를'\ 0'으로 수동 설정하는 것이 좋습니다. – HolyBlackCat

+1

아마, 새로운 프로그래머가 이런 식으로 초기화하는 것이 좋은 습관인데, 왜냐하면 그들은 종종 '\ 0'을 종료하는 것을 잊어 버렸기 때문에 내가 본 가장 흔한 실수이다. 물론 틀릴 ​​수도 있습니다. 어떤 사람들은이 문제를 피하기 위해'calloc'에 익숙해 있을지도 모릅니다. –

+3

'\ 0'이 끝나는 것을 잊어 버린 경우 전체 배열을 초기화하는 것을 잊어 버리게됩니다. 얼마나 많은 개발자가 큰 버퍼를 초기화 할 때 사이클을 낭비하는지 바로 다음 라인에로드하는 것이 놀랍습니다. –

0

는 음의 길이가 아무 의미로 length 매개 변수가 적어도 unsigned int해야한다,

void fDrawLine(int length) 
{ 
    int i; 
    char * compLine = (char *) malloc(WINDOW_WIDTH + 2); 

    for(i = 0; i < length; i++) 
     strcat(compLine, "-"); 

    fDrawSpacedMessage(compLine, -1, TRUE); 
} 

먼저 아래 코드와 몇 가지 문제가 있습니다. 이상적으로는 size_t을 사용해야합니다. i도 마찬가지입니다.

다음으로 length의 유효하지 않은 값으로부터 보호하지 못합니다. 암시 적 계약은 0 < = length < = WINDOW_WIDTH입니다. 명시 적으로 지정하십시오.

동적으로 할당 된 메모리를 사용하면 fDrawSpacedMessage()을 호출 한 후에 메모리를 해제하지 않으므로 메모리 누수가 발생합니다.

마지막으로 strcat은 하나의 문자를 추가하는 데 과도합니다.

이 모든 것을 종합하면 다음과 같은 대체 구현이 가능합니다. 내가 fDrawSpacedMessage 같은데요로 내가 WINDOW_WIDTH+2에서 compline을 떠 났어요

void fDrawLine(size_t length) 
{ 
    size_t actual_length = length <= WINDOW_WIDTH ? length : WINDOW_WIDTH; 
    char compLine[WINDOW_WIDTH+2]; 

    memset(compLine, '-', actual_length); 
    compline[actual_length] = '\0'; 
    fDrawSpacedMessage(compLine, -1, TRUE); 
} 

는 줄 바꿈을 추가합니다. 여전히 충돌하는 경우 당신이 채우기 위해`memset`를 사용하지 않는 이유는

문제가