2017-01-12 1 views
-1

디버거를 사용하여 버그를 찾았습니다. 그리고 나는 그 버그가 무엇인지를 발견 할 수있었습니다. 하지만 왜 그것이 발생하는지 모르겠습니다. 버그는 linep이 1 push 이후에 약간의 멍청한 주소 (1 칸 추가됨)를 나타냅니다. 그래서 두번째로 push에서이 라인에 오류가 발생합니다 : tmp1 = tmp2 = *x;linep은 약간의 어수선한 주소입니다 (아마도). 내가 linep가 어색한 주소가되는 이유를 모르겠다. 누군가가 그 사실을 설명 할 수 있기를 바랍니다. 코드는 다음과 같습니다.Entab 프로그램에서 예기치 않은 오류가 발생했습니다 (액세스 위반 읽기)

참고 : 프로그램의 목적은 모든 탭을 4 칸 바꾸는 것입니다.

#include <stdio.h> 

#define MAXLINESIZE 1000 
#define TABSPACES 4 

void push(char *x, char val, int index); 
int mgetline(char *s, int lim); 

int main(void) { 
    char line[MAXLINESIZE]; 
    char *linep = line; 
    while (mgetline(line, MAXLINESIZE) > 0) { 
     while (*linep) { 
      if (*linep == '\t') { 
       *linep = ' '; 
       for (int i = 1; i <= TABSPACES - 1; i++) { 
        push(line, ' ', linep - line + 1); 
        linep++; 
       } 
      } 
      linep++; 
     } 
     printf("%s", line); 
     linep = line; 
    } 
    return 0; 
} 

void push(char *x, char val, int index) { 
    char tmp1, tmp2, cnt; 
    char *ptc; 
    x += index - 1; 
    ptc = x; 
    tmp1 = tmp2 = *x; 
    cnt = 0; 
    while (tmp2) { 
     tmp2 = *x; 
     *x = tmp1; 
     tmp1 = *(x + 1); 
     *(x + 1) = tmp2; 
     x += 2; 
     cnt++; 
    } 
    *ptc = val; 
} 

int mgetline(char *s, int lim) 
{ 
    int c; 
    char *t = s; 

    while (--lim > 0 && (c = getchar()) != EOF && c != '\n') 
     *s++ = c; 
    if (c == '\n') 
     *s++ = c; 

    *s = '\0'; 

    return s - t; 
} 

참고 : 입력 . 탭 (09 진수 ASCII 코드)와 동일하다 * 공간 (20 진수 ASCII 코드)와 동일하다.

입력 :.

ABCD의 *의 EF ** g의 ****의 HJ * .k ** 리터

당신은에 제대로 포인터를 복사 루프를 설정해야
+0

당신은 자리에서 선 더 이상 할 수없는 변경 될 수 있습니다. 삽입 포인터가 소스 포인터를 따라 잡아서 당신 앞에있는 도로를 파괴 할 것이므로 문자를 걸러 내고 더 짧게 만들 수 있습니다. null 종결자를 개구리 도약시킬 수도 있습니다. –

+0

또한 읽는 모든 행에 대해'linep'를'line'의 시작으로 재설정해야합니다. 현재, 라인 읽기 루프 밖에서는 처음 한 번만 시작합니다. –

+0

좋아요, 공백을 삽입하면 전체 줄을 오른쪽으로 밀면됩니다. 이는 매우 비효율적이며 텍스트가 오른쪽 끝에있는 불법 영역으로 밀려 들어갈 위험이 있습니다. 입력란 하나, 출력물 하나씩 두 줄로 나누어 보십니까? 또는 버퍼 오버런의 위험이 항상있는 중간 문자열을 사용하지 않고 즉시 출력 스트림에 인쇄하십시오. –

답변

1

실제 입력을 덮어 쓰지 않고 공백을 문자열에 넣을 수있는 새로운 버퍼. 여분의 공백이 라인을 오버플로하지 않도록해야합니다. 또한 EOL이 입력되었는지 확인해야합니다.

푸시가 작동한다고 가정하면 라인 배열의 최대 크기를 초과하는 위험이있는 오른쪽으로 밀어냅니다. 또한 새 포인터를 반환하지 않으므로 여분의 공백을 테스트하고 줄 배열의 전체 내용을 매번 이동합니다. 별도로 입력 및 출력 라인으로 처리하는 것이 좋습니다.

푸시 코드를 사용하려면 여분의 공백을 삽입 할 수있을만큼 길게 만들고 루프 내에 linep = line;을 추가하십시오. Strlen()을 사용하여 원래의 라인 크기를 계산하고, 추가 된 공간의 총 수만큼 증가시키고, 그것이 MAXLINESIZE보다 크게 설정 될 배열을 오버플로하지 않는지 테스트하십시오. 루프에서 추가 한 모든 공간을 검사하지 않도록 푸시에서 새 포인터 (공백 뒤에)를 리턴하십시오.

코드를 "수정"하지 말고 더 효율적으로 다시 실행하도록 제안합니다. 제안 사항을 제시 한 후 버그를 지적하는 주석이있는 원본 코드가 표시됩니다.

int main(void) { 
    char line[MAXLINESIZE]; 
    char *linep = line; 
    char newline[MAXLINESIZE]; 
    char *newlinep = newline; 
    while (mgetline(line, MAXLINESIZE) > 0) { 
     linep = line; 
     newlinep = newline; 
     while (*linep) { 
      if (*linep == '\t') { 
       for (int i = 0; i <= TABSPACES - 1; i++) { 
        *newlinep = ' '; 
        newlinep++; 
       } 
       if ((newlinep - &newline) >= MAXLINESIZE) { 
        printf("Line filled, need to stop"); 
        newlinep = &newline[MAXLINESIZE-1]; 
        break; 
      } 
      else { 
       *newlinep = *linep; 
       newlinep++; 
      } 
      linep++; 
     } 
     *newlinep = '\0' 
     printf("%s", newline); 
    } 
    return 0; 
} 

여기에 내 의견 원래의 코드를 필요로 무엇으로

char *push(char *x, char val, int index); 
int mgetline(char *s, int lim); 

int main(void) { 
    // Make line big enough to hold the extra spaces 
    char line[3*MAXLINESIZE]; 
    char *linep = line; 
    while (mgetline(line, MAXLINESIZE) > 0) { 
     // You need to reset the line pointer here 
     linep = line; 
     while (*linep) { 
      if (*linep == '\t') { 
       *linep = ' '; 
       for (int i = 1; i <= TABSPACES - 1; i++) { 
        // Return the pointer to put after the spaces 
        // You also need to test to avoid overrun 
        linep = push(line, ' ', linep - line + 1); 
       } 
      } 
      linep++; 
     } 
     printf("%s", line); 
     linep = line; 
    } 
    return 0; 
} 

char * push(char *x, char val, int index) { 
    // You need to check to make sure you do not overrun x. 
    char tmp1, tmp2, cnt; 
    char *ptc; 
    x += index - 1; 
    ptc = x; 
    tmp1 = tmp2 = *x; 
    cnt = 0; 
    while (tmp2) { 
     tmp2 = *x; 
     *x = tmp1; 
     tmp1 = *(x + 1); 
     *(x + 1) = tmp2; 
     x += 2; 
     cnt++; 
    } 
    *ptc = val; 
    return ptc; 
} 
+0

예. 이것은 효과가있다. 하지만 새로운 코드가 아니라 내 코드로 복구 (예 : 버그 찾기)를 원했습니다. – Siliproksi

+0

@ Siliproksi 푸시가 작동한다고 가정하면 라인 배열의 최대 크기를 초과하는 위험이있는 오른쪽으로 밀어냅니다. 또한 새 포인터를 반환하지 않으므로 여분의 공백을 테스트하고 줄 배열의 전체 내용을 매번 이동합니다. 별도로 입력 및 출력 라인으로 처리하는 것이 좋습니다. – sabbahillel

+0

Turth. Porbably, 나는 할 것이다. 하지만 먼저이 코드에서 버그를 찾으려고 노력할 것입니다. – Siliproksi

관련 문제