-
[Kernighan - C] #1-10 외부변수전기전자공학/프로젝트 2017. 6. 24. 19:18
1. 10 외부 변수
The C Programming Language - Kernighan, Ritchie
프로그램을 작성하다 보면 여러 함수에서 공통으로 변수를 사용해야 될 때가 있는데, 이 변수를 '공통 변수'(global variable)이라 한다.
공통 변수의 정의는 extern 이라는 명령어를 사용한다.
이 변수는 함수 바깥에서도 정의하고 함수 각각에서 정의되어야 한다.
예제) 가장 긴 행 출력 프로그램 <-- 1.9 에서 했던 내용과 동일하지만 longest, max, line을 공통변수로 바꿔서 코딩했다.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#include <stdio.h> // 가장 긴 행 출력 프로그램#define MAXLINE 1000 /* 최대 입력받을 수 있는 행 길이*/int max; /* 최대 길이 */char line[MAXLINE]; /* 현재 입력받는 행을 담는 배열 */char longest[MAXLINE]; /* 가장 긴 행을 저장할 배열 */int getline(void);void copy(void);/* 가장 긴 행을 출력한다; specalized ver */main(){int len;extern int max;extern char longest[];max = 0;while ((len = getline()) > 0)if (len > max) {max = len;copy();}if (max > 0)printf("%s", longest);return 0;}/* getline: 행을 입력받아서 행의 길이를 측정 */int getline(){int c, i;extern char line[];for (i = 0; i < MAXLINE - 1 && (c = getchar()) != EOF && c != '\n'; ++i)line[i] = c;if (c == '\n') {line[i] = c;++i;}line[i] = '\0';return i;}void copy(){int i = 0;extern char line[], longest[];while ((longest[i] = line[i]) != '\0')++i;}cs 프로그램의 첫 부분에서 변수를 선언하고 각 함수에 필요한 공통변수를 extern과 함께 문장으로 선언하고 있다.
공통변수를 사용하는 함수가 공통변수가 선언된 파일과 같은 데 들어있는 경우(위와 같이 display.c에 같이 들어있을 때)
'extern' 선언을 생략할 수 있다.
그치만 다른 .c 파일에 있을 경우, copy함수 안에 extern 선언이 꼭 있어야 한다.
그러면 라이브러리에 있는 함수를 사용할 경우 그 함수에는 사용하는 모든 공통변수들을 프로그램의 처음에 선언해 주어야 한다는 게 말이된다.
#include <stdio.h>
이 선언을 통해 stdio에서 사용되는 공통변수는 다 선언된 거라 할 수 있다.
프로그램 작성시 모든 변수를 공통으로 두면 매개변수 부분도 필요없고 간편할 거라 생각할 수 있지만
사용하는 변수가 많아질 수록 혼돈하기 쉬워지고 일반성이 줄어든다.
일반성이라는 말은 예를 들어, 다른 곳에서 copy 함수를 사용하려면 copy함수에서 어던 변수가 공통으로 잡힌지 알고 난뒤 선언해 주어야 한다.
[예제 1-20]
파일 중에 있는 tab을 같은 길이의 빈칸으로 대치하는 프로그램을 작성하라.
매 n번째 위치에 tab지점이 있다 가정한다. (프로그램 이름: dtab)
내가 만든 파일: tt.h , main.c, dtab.c
tt.h
123456#include <stdio.h>#define MAXLINE 1000void dtab(char[], int);int getline(char[], int);cs main.c
12345678910111213#include "tt.h"main(){int len;char line[MAXLINE];int num = 4;while ((len = getline(line, MAXLINE)) > 0){dtab(line, num);printf("%s\n", line);}}cs dtab.c
12345678910111213141516171819202122232425#include "tt.h"/* 왜 위치에 따라 tab의 공간이 달라지는가... */#define TABWIDTH 4void dtab(char s[], int n) {char cpArr[MAXLINE];int i, j;i = 0;while (s[i] != '\0')cpArr[i++] = s[i];cpArr[i] = '\0';for (i = 0; i < TABWIDTH; i++)s[n + i] = ' ';j = n + 1;while (cpArr[j] != '\0'){s[n + i] = cpArr[j++];i++;}s[n + i] = '\0';}cs 참고코드
1234567891011121314151617181920212223242526#include <stdio.h>#include <stdlib.h>#define TABWIDTH 8int main(void){int i;int c, col, spaces;col = 0;while((c = getchar()) != EOF) {if (c == '\t') {spaces = TABWIDTH - col % TABWIDTH;for (i = 0; i < spaces; ++i)putchar(' ');col = col + spaces;} else {putchar(c);col = col + 1;if (c == '\n')col = 0;}}return EXIT_SUCCESS;}cs 참고 코드로 하면 tab의 위치가 달라져도 출력모양은 달라지지 않는다.
spaces = TABWIDTH - col % TABWIDTH 부분을 익혀둬야 겠다.
[예제 1-21]
빈칸이 연속으로 나올 때 그것을 tab 문자로 바꾸는 프로그램을 작성하라
즉 예제 1-20의 역작용을 하는 entab 프로그램을 작성하되, 사용되는 tab문자의 갯수는 될 수 있는 데로 작도록 하라.
entab.c (참고 코드 <- 출력 동작을 나중으로 미룸)
123456789101112131415161718192021222324252627282930313233343536373839404142#include<stdio.h>#define TABINC 8int main(void){int nb, nt, pos, c;nb = 0;nt = 0;for (pos = 1; (c = getchar()) != EOF; ++pos)if (c == ' ') // 입력한 게 빈칸이면{if ((pos % TABINC) != 0)++nb;else // 빈칸갯수 = tab너비 이면{nb = 0;++nt;//printf("t");}}else // c가 빈칸이 아니면{for (; nt > 0; --nt) // 이전에 빈칸갯수=tab너비 있으면putchar('\t'); // '\t' 출력 (entab의 핵심!)if (c == '\t') // 빈칸입력x && tab이면nb = 0; // nb = 0 -> 빈칸 출력을 안하도록..else // 빈칸x && tab x이면,for (; nb > 0; --nb) // 이전 입력에 빈칸(들)이 있지만, tab너비만큼이 아니면putchar(' '); // 입력된 빈칸만큼 출력putchar(c); // c가 빈칸이 아닐 때는 입력된 c 값을 그대로 출력// 이 프로그램은 (빈칸=탭 너비)만을 확인하는 걸 중점으로 두므로 다른 건 상관xif (c == '\n')pos = 0;else if (c == '\t')pos = pos + (TABINC - (pos - 1) % TABINC) - 1;}return 0;}ㅂcs pos = pos + (TABINC - (pos - 1) % TABINC) -1;
이 수식에서 TABINC - (pos - 1) & TABINC는 앞 detab.c의 TABWIDTH - col %TABWIDTH와 같다.
여기서 pos 의 기준이 1인 관계로 pos -1 = col 이다.
pos는 현재 위치를 의미하므로 원래 저장된 pos + (위치에 따른 빈칸너비) -1 해주면 된다.
[예제 1-22]
한 행의 n 번째 열 앞에 나타나는 빈칸 아닌 문자 중에서 마지막 문자의 뒷부분을 다음 행으로 보내어 한 행을 두 개 이상의 행으로 만드는 프로그램을 작성해보라
ver1: 그냥 c = getchar()으로 입력받아서 특정 길이 이상이면 \n으로 한 행을 두행으로 나눠서 출력
#include <stdio.h>main(){int i = 0; // 열을 표시하는 인덱스int n = 5; // n번째에서 행을 나누기 위한 변수int c; // 입력받는 공간while ((c = getchar()) != EOF){if (i %= n == 0){putchar('\n');if (c != ' ' || c != '\t')putchar(c);else;}elseputchar(c);i++;}}ver2. getline(line, MAX);
line 부분 - 중간에 '\n'을 입력해서 line 배열 성분 자체를 바꾸는 것
(문자열 배열 line을 copy해놓은 다음 반복변수를 각각 i,j로 써서 n번째 배열이 나올 때 마다 \n성분 넣기
if( d== '\\')
putchar(getchar());
이 부분의 코드 해석이 아직 불완전하다.
[예제 1-23]
Write a program to reomove all comments from a C program. Don't forget to handle quoted strings and character properly.
C comments do not nest
한글: c 프로그램에서 모든 설명문을 없애는 프로그램을 작성하라. 인용 부호 속에 있는 문자열에 주의
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374#include <stdio.h>void rmcomment(int c);void incomment(void);void in2comment(void);void echo(int c);main(){int c, d;printf(" To check /* Quoted String */ \n");while ((c = getchar()) != EOF)rmcomment(c);}void rmcomment(int c) {int d;if (c == '/') // main에서 입력받은 문자가 '/'일 때{if ((d = getchar()) == '*') // 다음 입력받은 문자 d = '*' 인 경우incomment(); // 인용문 /* */이거나 // 일 때else if (d == '/') {in2comment();}else{putchar(c);putchar(d);}}else if (c == '\'' || c == '"') // '이거나 "이게 입력되면,echo(c);elseputchar(c);}void incomment() // 인용문으로 슬래시 별(/*) 별 슬래시(*/)을 이용할 때{int c, d;c = getchar();d = getchar();while (c != '*'|| d != '/') // 처음에 바로 */이렇게 끝나는 게 아니면!{c = d; // 입력받은 d를 계속 c에 담아 놓기 때문에 *를 호출 받고 다음에 /를 받으면// while문을 빠져나감d = getchar(); // getchar() 함수 호출로 계속 입력받을 수 있고,}}void in2comment() // 인용문으로 슬래시 두번을 이용할 때{int c;while ((c = getchar()) != '\n');printf("\n");}void echo(int c){ // '말'안에 있는 // 나 /* 는 인용문으로 인식하지 않고// 그래로 출력한다.한다.int d;putchar(c); // 말(문학에서의 인용문)일 때는 '나 "를 출력while ((d = getchar()) != c) { // d = ' || d = "이 아니면putchar(d); // '말'을 출력if (d == '\\') // ?? 말을 입력 받는 도중 \가 있으면putchar(getchar()); // ?? 입력 받은 걸 그대로 출력 (단, ' 나 "가 오기 전 까지)// 영문 풀이: Within a quoted string, if we encouter a special character,//then we try to read them literally as two characters and print them.}putchar(d);}cs if( d== '\\')
putchar(getchar());
이 부분의 코드 해석이 아직 불완전하다.
[예제 1-24]
기본적인 C문법을 검사하는 프로그램을 작성하라.
검사 대상은 짝이 맞지 않는 괄호, 중괄호, 그리고 인용부호, escape 문자, 설명문 표시 등이다.
'전기전자공학 > 프로젝트' 카테고리의 다른 글
[Kernighan - C] #2-9 비트 연산자 (0) 2017.06.25 [Kernighan - C] #2-8 증가 연산자와 감소 연산자 (0) 2017.06.25 [Kernighan - C] 1장 언어소개 - (5. 문자 입출력) (0) 2017.06.24 [Kernighan - C] 1장 언어소개 - (4. 상수정의) (0) 2017.06.24 [Kernighan - C] 1장 언어소개 - 3. For문 (0) 2017.06.24