· C언어
#[C언어] 1.5.2 문자의 갯수 세기
0도리 ・ 2017. 4. 17. 23:45
URL 복사 이웃추가
본문 기타 기능
신고하기
다음의 프로그램은 문자의 갯수를 세는 프로그램으로 파일 복사 프로그램을 변형시킨 것이다.
#include<stdio.h>main(){long nc;nc = 0;while (getchar() != EOF)nc++;printf("%ld\n", nc);}
++nc;
이것은 nc를 1만큼 증가시키라는 말로서 nc=nc+1과 같다. nc를 1만큼 감소시킨다는 것은 --nc처럼 나타낸다. 이것도 nc = nc-1과 같은 뜻이지만 표현이 훨씬 간결하다. nc를 1만큼 증가시키라는 것은 ++nc 또는 nc++의 두 가지 모두 가능하지만, 두 경우는 좀 차이가 있다. ++nc는 nc를 사용하기 전에 1을 증가시키고 nc++는 사용 후에 1증가시킨다. 지금은 차이점을 잘 모르겠지만 2장을 보면 그 차이를 알 수 있을 것이다. --의 경우도 마찬가지이다.
문자 개수를 세는 프로그램에서 아주 많은 문자도 셀 수 있게 하기 위해 nc는 long으로 했다. int형은 보통 16비트 값으로서 최댓값은 32767이 되고 long은 보통 32비트의 값을 가진다. printf의 출력 양식 중에서 %ld는 출력되는 변수가 long형임을 나타낸다.
long형으로도 모자랄 만큼 큰 파일이 있을 것에 대비하려면 변수의 형을 double(배정도 실수형: double precision float)로 해주면 된다. 그리고 for 문을 사용해서 프로그램을 고치면 다음과 같다.
#include<stdio.h>main(){double nc;for (nc = 0; getchar() != EOF; ++nc);printf("%.0f", nc);}//공백은 1바이트라는 것을 알 수 있다. 특수문자는 2바이트
%f는 실수형 출력을 나타내는데, float형이나 double형에 공통으로 사용된다. 그리고 소수점 이하 자리에는 출력하지 않기 위해서 %0f로 썼다. 여기서 for 루프의 몸체에는 아무것도 없다. for 루프에서 해야 할 모든 동작은 for 뒤의 괄호 속에서 다 이루어진다. 그렇다고 몸체에 아무것도 써 놓지 않으면 안 되므로 세미콜론을 써 놓았다.
만약 읽어들이는 파일이 문자가 하나도 없는 파일이라면, while이나 for의 조건을 만족하지 않기 때문에 루프의 몸체는 실행되지 않고 0이 출력된다. while이나 for의 장점 중에 하나는 루프의 첫 부분에서 조건을 검사한다는 것이다. 그래서, 필요 없이 루프가 실행되는 경우가 생기지 않는다.
1.5.3 행의 갯수 세기
파일의 각 행의 사이에는 행을 바꾸는 기호(\n)가 들어있는 것이 보통이므로 형의 개수를 세기 위해서는 \n의 개수를 세면된다.
그런 동작을 하는 프로그램은 다음과 같다.
#include<stdio.h>main(){int c, nl;nl = 0;while ((c = getchar()) != EOF)if (c == '\n')++nl;printf("%d\n", nl);}
while의 몸체에 if의 문이 들어있다. if 뒤의 괄호 속의 조건이 만족되면 그다음 문장(또는 중괄호로 싸인 부분)이 실행되고 만족되지 않으면 그냥 그다음으로 넘어간다. ==는 "와 같다"라는 뜻이 기호로서 FORTRAN의. EQ와 같다. =는 치환을 위한 기호이다. 보통 C 프로그램에서는 비교보다 치환이 더 많이 쓰이게 되므로 치환을 위한 기호가 더 짧은 것으로 선택되었다.
어떤 문자에 작은따옴표를 붙이면 그 문자에 해당하는 값을 얻을 수 있다. 예를 들어 ASCII 문자를 사용하는 컴퓨터의 경우 'A'는 65와 같다. 물론 'A'와 65가 완전히 꼭 같다는 말이 아니고 a='A'와 같은 명령을 주면 a의 값이 65가 된다는 말이다.(문자형은 정수형으로 변환된다.) ASCII 이외의 문자에서는 A의 값이 65가 아니므로 A를 나타내기 위해 65를 사용하는 것은 별로 권할만한 일은 못된다. '\n'을 해보면 행을 바꾸라는 신호가 실제로는 어떤 값을 갖는지를 알 수 있다. \(역 슬래시)를 사용하는 문자들(escape 문자라고 한다)도 작은따옴표로 값을 알 수 있다. ASCII 문자를 사용하는 컴퓨터의 경우 '\n'은 13이 된다. 여기서 '\n'이 하나의 문자로 취급된다는 것을 다시 한번 강조한다. "\n"는 문자 하나를 가진 문자열(string)이다. C에서 문자를 표현할 때는 작은따옴표(' ')를 사용하고 문자열을 사용할 때는 따옴표(" ")를 사용한다는 것을 알아두기 바란다.
예제 1-8
빈칸, tab과 행의 개수를 세는 프로그램을 작성하라.
예제 1-9
한 파일을 읽어서 그중 빈칸이 연달아 나오면 그것을 모두 한 칸으로 만들어 출력하는 프로그램을 작성하라.
예제 1-10
한 파일을 읽어서 그중에 tab이 있으면 그것을 \t, backspace가 있으면 그것을 \b로 그리고 \(역 슬래시)가 있으면 그것을 \\로 대치해서 출력하는 프로그램을 작성하라.
1.5.4 단어 갯수 세기
이번에 살펴볼 프로그램은 행, 단어, 문자의 개수를 세는 프로그램이다. 빈칸이나 tab 또는 행바꿈 문자(\n)가 나오면 한 단어가 끝났다고 생각하기로 한다. 프로그램은 다음과 같다.
#include<stdio.h># define IN 1# define OUT 0main(){int c, nl, nw, nc, state;state = OUT;nl = nw = nc = 0;while ((c = getchar()) != EOF) {++nc;if (c == '\n')++nl;if (c == ' ' || c == '\n' || c == '\t')state = OUT;else if (state == OUT) {state = IN;++nw;}}printf("%d(널의 개수) %d(널 또는 탭 또는 빈칸개수) %d(모든걸 포함한 단어 개수)\n", nl, nw, nc);}
이 프로그램에서 state라는 변수는 지금 읽어들인 것이 단어 내에 있는 문자인지 아닌지를 표시하기 위해 사용된다. 단어 내에 있으면 state는 IN(즉 1)의 값을 갖고 아니면 OUT(즉 0)의 값을 가진다. 0과 1로 하지 않고 IN과 OUT으로 한 이유는 IN과 OUT이 보기 쉽기 때문이다. 별 차이 없다고 생각할지 모르지만 프로그램이 복잡해지면 큰 차이가 난다.
nl = nw = nc = 0;
라는 문장은 nl, nw, nc 모두를 0으로 해 주는 명령이며 다음과 같은 뜻이 된다.
nl = (nw = (nc = 0) );
|| "또는(or)"이라는 뜻의 연산자이다. 그러므로
if(c == ' ' || c == '\n' || c == '\t')
는 "c가 빈칸이거나 c가 \n이거나 또는 c가 \t 이면"이라고 해석할 수 있다. "그리고(AND)"라는 연산자는 &&이다. ||나 &&로 연결된 조건들은 왼쪽에서부터 검사된다. 위의 프로그램의 경우, c가 빈칸이면 그다음의 조건은 검사되지 않고 넘어간다. 이런 사실은 프로그램이 복잡할 때는 아주 중요한 사실이 된다. 이 프로그램에서 주의 깊게 보아야 할 또 한 부분은 else이다. else는 다음과 같이 사용된다.
if(수식)
문장1
else
문장2
즉 수식(조건)이 만족되면 문장 1이 수행되고 만족되지 않으면 문장 2가 수행된다. 위의 프로그램에서는 else 뒤에 if를 한번 더 사용하고 있다.
예제 1-11
위의 프로그램이 오동작을 하도록 하는 입력 파일을 만들어 보라.
예제 1-12
파일을 읽어 한 행에 한 단어씩 출력하는 프로그램을 작성해 보라.
댓글쓰기 이 글에 댓글 단 블로거 열고 닫기
인쇄