sourcetip

K&R 연습 1-9: 입력을 출력하여 여러 공백을 하나의 공백으로 대체

fileupload 2023. 10. 10. 20:54
반응형

K&R 연습 1-9: 입력을 출력하여 여러 공백을 하나의 공백으로 대체

나는 C 다리를 얻기 위해 C에 관한 책들을 뒤지고 있습니다.알겠어요?!)저는 방금 K&R 책에서 1-9번 연습을 마쳤습니다. 참고로 "입력 내용을 출력에 복사할 프로그램을 작성하여 하나 이상의 빈칸의 각 문자열을 하나의 빈칸으로 대체"하는 것입니다.제 코드에 무슨 일이 있는 건지 여쭤볼 게 있습니다만..

#include <stdio.h>

//Copy input to output. Replace each string of multiple spaces with one single space

int main(int argc, char *argv[]){

    int ch, lch;      // Variables to hold the current and last characters, respectively


    /* This loop should 'put' the current char, then store the current char in lc,
     * loop back, 'get' a new char and check if current and previous chars are both spaces.
     * If both are spaces, do nothing. Otherwise, 'put' the current char
     */

    for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){
            if(ch == ' ' && lch == ' ')
                    ;
            else putchar(ch);
    }

    return 0;
}

첫 번째 문자 입력을 제외하고는 대부분 작동합니다.예를 들어, 첫번째 줄 입력이

"This        is   a test"

내 코드 출력

"his is a test". 

첫 번째 문자 입력을 삭제한 후, 프로그램은 연습의 요구를 충족시키기 위해 지속적으로 작동합니다.

누가 제 루프에서 제가 저지른 실수가 문제의 원인이 되고 있는지 알려주실 수 있나요?다른 어떤 조언도 환영합니다.

포루프 문장에서, 당신은 버그를 가지고 있습니다.

for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){...}

여기서는 첫 번째 문자를 ch에 저장한 다음 문자 입력을 다시 읽음으로써 (ch!=EOF) 여부를 다시 테스트합니다.

한다를 합니다.ch=getchar()초기화 문에서. 두 번째 파트에 있다고 합니다.

for(;(ch = getchar()) != EOF; lch = ch){...}

또한 lch를 실행하기 전에 초기화해야 합니다. lch는 루프의 첫 번째 반복에서 비교하기 전에 lch에 저장된 값이 없기 때문입니다.그러니까.lch=0먼저 초기화됩니다.

for(lch = 0; (ch = getchar()) != EOF; lch = ch){...}

컴파일러에서 경고를 활성화하는 것을 고려해 보십시오. 아마 이 문제를 감지하고 경고하므로 수정할 수 있습니다.

위의 내용을 통해 문제가 해결될 것입니다.

(답변 수정을 도와준 블루문과 하이드에게 감사드립니다.)

루프 초기화에서 getchar를 두 번 호출합니다.

 for(ch = getchar(); (ch = getchar()) != EOF; lch = ch)

대신 초기화(첫 번째 문자를 얻기 위해)에서 한 번 호출하고, 반복이 끝나면(다음 문자를 얻기 위해) 호출해야 합니다.

int ch, lch = 0; // avoid using uninitialized variable

for(ch = getchar(); ch != EOF; lch = ch)
{
        if(ch == ' ' && lch == ' ')
                ;
        else putchar(ch);

        ch = getchar();
} 

업데이트: lch와 관련된 문제를 지적해 준 블루문과 셰카르수만에게 감사드립니다.

입니다.getchar -번 시 -번ch할 때 한 번 더,수ch그에 반대하여EOF.

ch = getchar()합니다.

for( lch = '?' ; (ch = getchar()) != EOF; lch = ch) {
    ...
}

를(를) 시작해야 .lch공간 이외의 다른 가치를 갖습니다.

.getchar()에 한 번한 번,번.for조건.로 검색한 따라서 처음 검색한 문자는 삭제됩니다.

.lch루프하기 전에, 비교하기 전에.때라:

  • :' '선두 공간을 "사전 matching"함으로써 다듬어 줍니다.
  • 다른 항목으로 설정하면 선행 공간이 정상적으로 처리됩니다.

루프 헤더는 (두번째 경우) 다음과 같습니다.

 for(lch = 'a' /*arbitrary*/; (ch = getchar()) != EOF; lch = ch)

되지 않은 에 .lch.

이 루프 변경

for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){
        if(ch == ' ' && lch == ' ')
                ;
        else putchar(ch);
}

다음의 방법

for( lch = EOF; ( ch = getchar() ) != EOF; lch = ch )
{
        if ( ch != ' ' || lch != ' ' ) putchar( ch );
}

그렇지 않으면 루프의 시작 부분에서 문자를 두 번 읽습니다.

또한 내 생각에 과제는 다른 과제를 설명합니다.

"프로그램을 작성하여 입력 내용을 출력에 복사하고, 하나 이상의 빈칸의 각 문자열을 하나의 빈칸으로 대체합니다."

빈칸의 각 줄을 하나의 빈칸으로 교체해야 합니다.:) 위에 표시된 루프는 이 작업을 수행하지 않습니다.

for-loop으로 하는 것이 과제가 아닌 이상, 당신이 더 깨끗한 코드를 얻기 위해 노력한다면 언어를 배우는 것이 더 좋습니다.코드가 무엇을 하는지 스스로 말해보세요. 예를 들어, 동등한 동안 루프와 for-loop을 비교해보세요.

//initialize lch to prevent undefined behaviour
//if the first character is a space, it will be printed
lch = 'A';

// as long as you can read characters
while((ch = getchar()) != EOF) {

    // if either the current character or the previous one is not a space
    if(ch!=' ' || lch!=' ') { 

        //print it
        putchar(ch);
    }

    // remember the current for the next round
    lch = ch;
}

일단 while-construct를 이해하면, hacky for-loop으로 변환할 수도 있지만, 왜 그러십니까?반면에 읽기가 더 쉽고 컴파일러는 둘 다 같은 방식으로 컴파일하기 때문에 신경 쓰지 않습니다. (아마도)

정답은 많이 나와 있지만 디버거(gdb)를 사용하여 직접 추적할 수 있는 방법을 알려드리겠습니다.

먼저 코드를 다음과 같이 변경합니다(한 줄에 하나의 문만!).

...

for(ch = getchar(); 
   (ch = getchar()) != EOF; 
   lch = ch){

...

합니다()-ggcc)합니다를 사용하여 합니다.

 gdb ./a.out

합니다에 .main():

(gdb) break main

프로그램을 시작합니다.

(gdb) run

합니다.main():

Breakpoint 1, main (argc=1, argv=0x7fffffffe448) at main.c:15
15      for(ch = getchar(); 
(gdb) 

코드를 통과합니다.

(gdb) step

사용하다print chgbd합니다()ch 이 기 중"안.

gbd를 조종하는 방법에 대한 자세한 내용은 여기 http://beej.us/guide/bggdb/ 에서 확인할 수 있습니다.

네, 지금 일어나고 있는 일은 당신이 당신의 성명서를 발표할 때, 먼저 당신은 다음과 같은 ch를 초기화한다는 것입니다.

for( ch= getchar();

따라서 이 순간 첫 번째 문자(T)를 얻고 포인터가 다음 문자(h)로 한 위치를 이동합니다.

그리고 나서 당신은 다시 그와 함께 차를 얻게 됩니다.(ch = getchar()) !=EOF;

바꿔 보다for (ch= getchar();사용.for (ch= '' ;대신.

그것이 해결되기를 바랍니다.

세가지 부분이 있습니다.forstatement: 초기화, 조건 및 증분.이 부분들은 두 개의 세미콜론에 의해 분리됩니다.

A의 조건 부분은 매우 혼란스럽습니다.for진술은 부작용이 있습니다.부작용은 증분 부분에 속합니다.

for (ch = getchar(); ch != EOF; lch = ch, ch = getchar())

그리고, 다른 사람들이 지적했듯이,lch초기화해야 하므로 다음과 같습니다.

intch = 'a';

그리고 마지막으로, 비록 이것이 프로그램의 정확성에 영향을 미치지는 않지만, 저는 그것을 반대로 하겠습니다.if테스트:

if (ch != ' ' || lch != ' ')
    putchar(ch);

이거 나한테 통했어요.

#include <stdio.h>
int main(int arg, char *argv[]){
char c = 0;
long blank = 0;
long tab   = 0;
while((c=getchar())!= EOF){
 if(c == ' '){
    ++blank;  
 }

 if(c != ' '){
     if(blank>1){
       printf("%c", ' ');
       blank = 0;
       printf("%c", c);            
        }
 else{
        printf("%c", c);                            
     }
  }    

 } //end of while
return 0;
}

@eleasar에서 약간의 변화가 있었습니다.12호선은 이전의 것은 공란이 하나도 인쇄되지 않기 때문에 (공란>1)에서 (공란>=1)로 변경되어야 했습니다.

#include <stdio.h>
int main(int arg, char *argv[]){
char c = 0;
long blank = 0;
long tab   = 0;
while((c=getchar())!= EOF){
 if(c == ' '){
    ++blank;  
 }

 if(c != ' '){
     if(blank>=1){
       printf("%c", ' ');
       blank = 0;
       printf("%c", c);            
        }
 else{
        printf("%c", c);                            
     }
  }    

 } //end of while
return 0;
}

다른 숙소:

#include <stdio.h>

int main()
{
    int charac;

    // Variable declared for verifying consecutive whitespaces 
    bool blank = false;

    // As long as you did not input EOF (Ctrl + Z on Windows, Ctrl + D on linux, macOS)
    while ((charac = getchar()) != EOF){

        // Current char is whitespace, the one before was also whitespace => go to next iteration    
        if((charac == ' ') && (blank == true)){
            continue;
        }
        // If current char is whitespace, keep this in mind(blank = true) and output the whitespace
        else if(charac == ' ')
        {
            blank = true;
            putchar(charac);
            continue;
        }

        // If current character is not whitespace, output it and reset the blank boolean
        putchar(charac);
        blank = false;
    }

    return 0;
}

저도 이 책을 읽고 C를 배우고 있는데 이런 방법을 생각해냈는데 피드백이 개선되었으면 좋겠습니다.메모리 공간을 낭비하지 않기 위해 너무 많은 변수를 선언하지 않으려고 했습니다.여러 개의 탭과 공간을 하나의 케이스로 처리하고 싶어서 나중에 프린트할 담요 공간을 정의하게 되었습니다.

#include <stdio.h>

/* space char was defined so I can treat ' ' and '\t' on the same case */
#define BLANK ' '


int main(){

    int c;

    while((c = getchar()) != EOF){

        /* if char is either ' ' or '\t' */
        if((c == ' ') || (c == '\t')){

            /* print a blank */
            putchar(BLANK);
            /* read next char */
            c = getchar();

            /* while after the ' ' or '\t' the char is again ' ' or '\t' ... */
            /* I'm not going to bother with it and I'm going to read the next char */
            while((c == ' ') || (c == '\t')){
                c=getchar();
            }

            /* print the char */
            putchar(c);
        }

        /* another char */
        else {
            putchar(c);
        }
    }

    
}

언급URL : https://stackoverflow.com/questions/31597961/kr-exercise-1-9-output-the-input-replacing-multiple-blanks-by-a-single-blank

반응형