2010-03-05 4 views
2

약간의 배경 지식을 위해 독점적 인 DOS 버전을 실행하는 소형 16 비트 휴대용 컴퓨터의 경우 미터 판독 응용 프로그램을 C로 작성합니다.C의 포인터 문제 - 내가 뭘 잘못 했니?

나는 계량기 정보를 표시하는 화면을 가지고 있으며 사용자가 입력을 요구합니다. 사용자는 장치의 Enter 키를 누르면, 다음 코드를 실행한다 :

/* ... 
* beginning of switch block to check for keystrokes 
* ... 
*/ 
case KEY_ENTER: { 
    /* show what has been entered */ 
    if(needNew == 0) { 
     /* calculate usage for new reading */ 
     double usg = 0; 
     int ret = CalculateNewUsage(vlr, buf, &usg); 
     VerifyReadScreen(vlr, ret, buf, &usg); 
     needRedraw = TRUE; 
    } 
    break; 
} 
/* .... end switch statement */ 

vlr 모든 계정/계량 정보를 보유 구조체에 대한 포인터, buf을위한 숫자 키를 저장하는 데 사용되는 유형 char[21]이며 이 블록 위에 처리되는 판독 값. CalculateNewUsage을 호출하기 전과 후에 모두 내 변수에 유효한 데이터가 들어 있습니다.

그러나 VerifyReadScreen을 입력 한 후 변수 데이터를 다시 검사하면 newread이 메모리에서 임의의 위치를 ​​가리키고 있으며 저작권 고지문이 표시됩니다. 흥미로운 것은 아무런 계정이나 내가 입력 한 내용에 상관없이 newread의 잘못된 데이터가 화면에 VerifyReadScreen에 인쇄되어 있습니다. 나는 CalculateNewUsage과 같은 방식으로 주소를 VerifyReadScreen으로 전달하고 있지만 어쨌든 나는 다른 무엇인가로 끝났습니다. 여기

VerifyReadScreen입니다 :

printf("%s", newread); /* yay! */ 

것은 내가 필요로하지 않았기 때문에 :

BYTE VerifyReadScreen(const VLRREC * vlr, 
         const int status, 
         const char * newread, 
         const double * usage) { 

    /* snip a whole bunch of irrelevant formatting code */ 

    printf("%s", (*newread)); /* prints funky copyright text */ 

    /* snip more irrelevant formatting code */ 
    return TRUE; 
} 

가 실제로 VerifyReadScreennewread를 인쇄하고 코드가 정말 읽어야한다는 지적에 대해 Jefromi에게 감사 printf이 나를 대신하기 때문에 newread을 참조 해제하십시오. 필자는 본질적으로 메모리의 임의의 장소 인 포인터에 포인터를 전달하고있었습니다.

+0

어떻게'buf'와'usg'가 선언 되었습니까? –

+0

"buf가 문자열"이라고 할 때, 이미'char *'를 의미합니까? 그리고 당신은 그것의 주소를'const char *'라고 타이핑하고 있습니까? – Cascabel

+0

@Alokzilla - buf는 키 스트로크를 검사하는 코드의 함수 블록 내에 선언 된'char [21]'유형입니다. usg는'case KEY_ENTER' 블록 내에서 선언됩니다. –

답변

7

는 내가 대답으로이를 게시 할 충분한 확신 생각 : 당신은 문자열 (char*) newread있어

BYTE VerifyReadScreen(const VLRREC * vlr, const int status, const char * newread, const double * usage) { 
... 
    LCD_set_cursor_pos(19 - strlen(newread), 3); 
    printf("%s", (*newread)); /* prints funky copyright text */ 
... 
} 

하지만 printf와, 당신은 당신을 제공하는, 그것을 역 참조하고 캐릭터 라인의 최초의 캐릭터 그런 다음 printf에 대한 %s의 인수로 사용하므로 해당 문자가 제공 한 메모리 주소로 이동하여 거기에서 발견 된 내용을 인쇄하려고합니다.

P. 당신은 운이 좋지 않습니다. 일반적으로 이와 같은 일을하는 것은 당신에게 세그 폴트를 줄 수 있기 때문에, 그 라인까지 추적하여 포인터 오류가 있음을 알 수 있습니다.

+0

맞습니다 - 역 참조를 제거하면 해결됩니다! 정말 고맙습니다! : D –

+0

나는 그 코드를 여러 번 반복해서 보았고 그것이 전혀 어울리지 않는다고 덧붙여 야한다. 이 핸드 헬드 컴퓨터는 잘못된 것을 할 때 가장 중요한 오류 메시지를 표시하는 것이 아니라 대부분의 경우 재미 있습니다. –

2
그건 당신이 직면하고있는 문제입니다 경우가 알려져 있지 않습니다

하지만, 21 자입니다 VerifyReadScreen에 사용되는 buffer, 할 가능성이 가장 높은 오버 플로우 :

if(strlen((*vlr).ServAdd) >= 20) { 
    sprintf(buffer, "%20s", (*vlr).ServAdd); 
} 

%20s 형식 지정자 방지하지 않습니다 sprintf은 20 자 이상을 씁니다. 20 자보다 짧으면 문자열을 공백으로 채 웁니다 (또는 if 조건에 <= 20을 입력 했습니까?). 여기

else { 
    memset(buffer, 0x20, (int)(strlen((*vlr).ServAdd)/2) + 1); 
    strcat(buffer, (*vlr).ServAdd); 
} 

일부 패딩

은 문자열의 길이에 따라 이루어집니다,하지만 난 그게 결과가 20자를 초과하지 있는지 확인 것이라고 표시되지 않습니다.

+0

'snprintf'은 당신의 친구입니다! – Cascabel

+0

이 코드는이 시점에서 매우 거친 내용이지만, 알아두면 좋습니다. 감사! –

관련 문제