저자: 한동훈(
traxacun@unitel.co.kr)
휴~ 오늘도 날씨가 무덥군요. 날씨가 더운 만큼 몸도 쳐지고, 슬슬 "프로그래밍은 나의 적성이 아니야!"라고 생각하는 분들이 생기기 시작했을 거라는 생각도 듭니다. 여기계신 분들도 그런가요?
프로그래밍이라는 것은 생각보다 쉽습니다. 다만, 꾸준히 해보면서 익숙해지는 것이 어려운 거겠지요. 영어도 처음 배울 때는 알파벳을 외우는 데만 일주일이 넘게 걸렸다는 걸 생각해보세요. 그때 누군가가 제게 "에이 비 씨 디 이 에프 지~"하는 노래만 갈켜줬어도 일주일씩 걸리지는 않았을 텐데요. 네, 제 역할은 여러분에게 큰 개념들을 알려드리고, 쉽게 이해할 수 있도록 하는 것입니다. 눈으로만 봐서는 절대 되지 않습니다. 눈으로 이해했다고 생각되는 코드라도 직접 입력할 때와 머리 속으로 생각할 때의 느낌은 전혀 다릅니다. 아마, 벌써 이런 경험을 해 보신 분들도 있을 겁니다. 단순히 기계처럼 입력하라는 것이 아닙니다. 코드가 어떻게 돌아가는지 이해하라는 겁니다. 그래서 여러분에게 문법을 외우라고 하지도 않습니다. 제가 언제 문법을 외우라고 했나요? 학교에서 보는 시험이 아닙니다. 기억이 안나면 언제든지 책을 펼쳐볼 수 있고, MSDN에서 찾아볼 수 있습니다.
처음에 얘기했던 것처럼 모든 프로그래머가 언어의 모든 기능을 100% 사용하는 것은 아니라고 했던 내용, 기억나죠? 고작 10~20% 정도만 사용할 뿐이라고 얘기했습니다. 그러니 미리 겁부터 먹지는 말자구요. 하지만 여러분 스스로 예제를 해보고, 자꾸 느껴보고, 익숙해 지는 것은 남이 대신 해 줄 수 없는 일입니다. 물론 예제를 많이 해봤다고 해서 프로그래밍을 능숙하게 하게 되는 것은 아닙니다. 예제도 그저 이해만 하고 지나가세요. 나중에 스스로 프로그래밍을 할 때 "이러한 것이 어디에 있었지!"라는 것만 기억해두고 책을 뒤적이면서 자꾸 하다보면 그때 비로소 여러분의 지식이 됩니다.
지난 시간에 했던 이야기를 복습하는 것으로 오늘 하루를 시작하도록 하지요. 예외를 처리하기 위해서 어떤 것들을 쓴다고 했었죠? 네, 예외가 발생할 수 있는 부분을 시도(try)해 보기 위해서 try를 사용하고, 예외가 발생하면 족족 잡아내기(catch) 위해서 catch를 쓴다고 했습니다. 그리고 예외가 발생해도 정상적인 처리를 하기 위해서 finally를 사용한다고 했습니다. 그리고 Exception, 예외 클래스를 설명하면서 이것도 이야기했습니다. 만병통치약은 믿을 수 없으니까 최후의 수단으로 남겨놓고 증상에 따라서 예외를 처리할 수 있어야 한다고 얘기했습니다.
클래스와 인스턴스의 관계는 제가 뭐라고 했죠? 붕어빵 기계하고 붕어빵!! 에잇! 붕어빵만 기억하면 클래스와 인스턴스는 절대 까먹을 수 있다? 없다? 없어요! 마찬가지로 예외를 사용하는 방법도 뭐만 기억하면 안 까먹는다? 네, 그렇죠. 만병통치약. 만병통치약만 기억하면 여러분은 올바른 예외 처리를 사용할 수 있습니다. 예외에 대한 개념과 만병통치약이 무엇을 의미하는 지만 알면 됩니다. try, catch, finally라는 키워드를 사용한다는 내용이나 형식은 중요하지 않습니다. 책이나 MSDN 보면 그 형식이 다 나와있으니까요. C++에서 __try, __catch, __finally를 사용하든, 자바에서 try, catch, finally를 사용하든 간에 그런 것들은 전혀 중요하지 않습니다. 제 아무리 언어의 문법을 잘 외우고 있어도 "왜 예외를 써야 하고, 언제 예외를 써야 하는지!"에 대해 잘 모른다면 좋은 코드를 작성할 수 없기 때문이죠. 마찬가지로 만병통치약을 왜 쓰면 안되는지에 대해 충분히 이해했다면 여러분의 생각을 자유롭게 종이에 옮겨놓고 그것을 해당 언어의 특정 문법으로 옮겨놓을 수 있지만, 만병통치약을 왜 써서는 안되는지 모른다면 좋은 생각 자체가 나올 수 없습니다.
저는 특별히 많은 문법을 설명하지 않습니다. 사실, 지난번 여러분의 숙제를 보고서 많은 걸 느꼈습니다. 저와 코딩하는 것도 다르고, 문제를 바라보는 시각도 다르다는 것을 느낄 수 있었습니다. 프로그래밍은 정답이 있는 문제집이 아닙니다. 하나의 문제에 대해 다양한 해결책이 나올 수 있고, 그 해결책 모두가 올바른 것일 수도 있습니다. 따라서 대부분의 경우에 저는 코드 보다는 개념을 설명하는 데 집중하려고 합니다. 문법에 대한 설명은 여러분의 책상에 있는 책,
『C# 프로그래밍』만으로도 충분합니다.
자, 지난 시간에는 잠시 객체 지향에서 벗어나 예외 처리에 대해 설명했었습니다. 다시 객체 지향으로 돌아와서 다른 이야기를 시작하겠습니다. 굳이 struct는 설명하지 않겠습니다. struct란 대상을 모델링할 때 단순히 데이터만 있는 구조를 말하는 것입니다. 따라서 객체 지향 언어인 C#에서는 struct를 거의 사용하지 않습니다. 마찬가지로 class 키워드를 사용해서 클래스를 선언할 때 대상만 모델링하고, 행동을 모델링하지 않으면 struct와 동일하게 됩니다. 그러면 왜 struct가 있을까요? 데이터 그 자체만을 다루기 위해서 class와 struct를 구분했기 때문일까요? 기존의 C 언어나 C++ 언어에서는 struct로 정의된 것들을 사용할 때 struct를 사용해서 그 데이터 구조를 정의합니다.
따라서 struct는 거의 쓰이지 않습니다. 가끔 struct를 사용해서 C 언어나 다른 언어로 작성된 데이터 구조를 사용해야 하는 경우가 있는데 이런 경우에는 "StructLayout 특성(attribute)"을 정의해서 사용하도록 합니다. 아직 여러분은 특성이 무엇인지 학습하지 않았습니다. 하지만 지금 노트에 struct를 사용할 일이 있으면 StructLayout 특성을 사용한다는 사실만 표시해 두고 필요할 때 MSDN "색인"탭에서 "StructLayout 특성"을 입력하면 필요한 정보를 얻을 수 있을 겁니다. struct에 대한 설명은 이것으로 마칩니다.
오늘은 9장까지 읽어오라고 했습니다. 그러니, 오늘은 딱 9장까지만 설명하겠습니다. 이제 8장에 대한 것들을 설명하도록 하지요. 8장은 객체지향에 대한 이야기입니다. 사실 8장도 두 번째 시간에 이미 설명했었습니다. 기억나죠? 그런 이유로 8장도 건너뜁니다. 오늘까지 9장까지 읽어보고, 예제를 해보라고 했습니다. 사실, 8장은 여러분에게 복습이었을 것이고, 제가 얘기하지 않는 세세한 것들에 대한 자세한 설명이 있습니다. 이제 남은 것은 9장뿐입니다. 객체지향에 대한 이야기는 아직도 많이 남아있습니다. 그러나 남아 있는 이야기들은 모두 객체지향을 바라보는 시각에 대한 것들입니다. 이러한 이야기는 제가 계속해서 틈틈이 이야기를 할 것입니다. 하지만 지금까지 객체지향을 설명하면서 한 이야기들이 핵심입니다. 그 개념만 잘 이해해주세요.
데이터 구조
기존의 C 언어와 같이 오래된 언어들은 나름대로의 자료구조를 지원하지 않았습니다. 때문에 데이터 구조론 또는 자료 구조론이라는 이름하에 데이터를 조작하고, 처리하는 방법에 대해서 학습하는 과정이 필요했습니다. 그리고 모든 프로그래머들은 이러한 자료구조에 대한 자신만의 코드를 작성하기에 이르렀습니다. 프로그래머들이 매일 같은 작업만 하느라 좀 더 생산적인 일을 할 수 없었던 거지요. 그래서 펄, 자바, 비주얼 베이직, C#과 같은 언어가 새롭게 나오게 되었고 이러한 언어들은 자료 구조를 언어 자체에서 지원하고 있습니다. 물론 자신만의 특별한 데이터를 처리하기 위한 자료 구조가 필요하다면 그 때는 직접 구현해야 합니다. 그러나 일반적인 용도의 데이터를 처리하는 데는 지장이 없습니다. 95% 정도는 닷넷에서 제공하는 것으로 모두 처리할 수 있습니다. 고작 5%만 특별한 자료 구조를 필요로 합니다.
책에 나와 있는 것들은 모두 이러한 자료 구조들을 클래스를 사용해서 모델링한 것입니다. 그리고 각각의 메소드 사용 방법을 설명하고 있지요. 어떠한 자료 구조에 데이터를 추가하는 Add() 메소드, 데이터를 제거하는 Remove()와 같은 문법은 중요하지 않습니다. 만약 이런 메소드를 외워야 한다고 생각한 분이 있다면 지금 그 생각을 지워버리세요. 어떤 메소드를 쓰는가는 중요하지 않습니다. 그런 것들은 책을 보면 나와 있으니까요.
펄, 자바, C#과 같이 현대에 나온 언어들은 기본적인 자료 구조들을 제공하고 있습니다. 그리고 여러분은 그것들을 사용하기만 하면 됩니다. 그리고 나중에 시간이 나면 자료 구조에 대한 책들을 보고 이해하시면 됩니다. 자료 구조 책들에 나오는 코드들을 단순히 입력해보는 것으로는 개념이 제대로 이해되지 않을 뿐만 아니라 여러분의 지식이 되지 않습니다. 개념을 제대로 이해하고, 기초를 튼튼히 한다면 여러분 스스로 코드를 작성할 수 있게 됩니다. 지금까지 자료 구조 책들을 보고 포기했던 분들이 있다면, 걱정하지 마십시오. 이 강의가 끝날 때쯤 스스로 할 수 있게 될 겁니다. 그럼 자료 구조 중에 가장 흔한 배열부터 살펴보도록 하죠.
배열
배열이 자료 구조라구요? 네, 자료 구조입니다. 지금까지는 다음과 같이 배열을 사용했습니다.
int[] intArray;
이러한 코드의 의미는 뭐죠? 배열에 여러 개의 int 형식의 데이터를 저장한다는 이야기입니다. 마찬가지로 다음을 보세요.
string[] args;
이것 역시 배열입니다. 문자열을 담을 수 있는 배열이지요. 여기에서는 [0], [1]과 같은 서수들을 사용해서 string 즉, 개별 문자열에 접근했습니다. 이처럼 []를 쓰는 것 만으로 배열을 사용할 수 있게 했습니다. 사실, 배열 이라는 것은 일련의 데이터들을 차례대로 담을 수 있는 컨테이너입니다. int[]는 int 형식을 담을 수 있는 컨테이너를 하나 만들라는 이야기입니다. 마찬가지로 string[]는 string 형식을 담을 수 있는 컨테이너입니다. int 형식의 배열을 사용하든, string 형식의 배열을 사용하든, 컨테이너는 변하지 않겠죠? 컨테이너란 바구니입니다. 바구니에 오렌지를 담든, 바나나를 담든, 파인애플을 담든 상관없습니다. 오렌지 담을 때는 오렌지만 담을 수 있는 바구니를 사용하나요?
과일을 담기 위해 쓰는 바구니를 "과일 바구니"라고 합니다. 배열도 마찬가지입니다. 어떤 형식의 데이터를 저장하든지 간에 바구니는 바뀌지 않습니다. 그리고 바구니의 기본적인 기능들도 변하지 않습니다. 바구니에 과일을 추가로 담을 수도 있고, 바구니에서 과일을 꺼내올 수도 있으니까요. 또, 바구니를 살펴보면서 바구니에 어떤 과일이 있는지도 알아볼 수 있겠죠?
닷넷에서는 이러한 과일 바구니에 해당하는 것이 있고 여러분은 이미 이 과일 바구니를 자유롭게 사용하고 있습니다. 바로 배열이죠! int[], string[], double[] 등등. 실제로는 이 바구니도 클래스로 구현되어 있습니다. 그러니까 여러분이 직접 바구니를 찾지 않아도 닷넷에서 자동으로 이 바구니를 사용하는 것이지요. 가끔 필요한 경우에 직접 바구니를 만들어 쓰는 경우도 있지만 그렇게 흔하지는 않습니다. 닷넷에서 이 바구니는 Array 클래스와 ArrayList 클래스입니다. 대충 감을 잡을 수 있겠지만 Array는 고정된 크기를 갖는 것들에 대해서 사용하며, ArrayList는 다양한 크기를 갖는 것들에 대해서 사용합니다. 당연히 고정된 크기를 갖는 Array가 처리 속도는 더 빠릅니다. 과일 바구니에 과일을 집어넣는 Add 메소드나 과일을 꺼내오는 Remove 메소드 같은 것들은 MSDN에 보면 나와 있습니다. 지금까지 직접 MSDN을 사용하는 방법을 여러 번 보여드렸는데, 강의에서는 아직까지 한 번도 보여드린 적이 없더군요. 그래서 이글의 마지막에는 MSDN을 사용하는 법과 MSDN을 통해서 얻은 정보를 어떻게 C# 코드로 작성하는지에 대해 설명하겠습니다.
배열이라는 가장 기초적인 것을 살펴봤으니, 이제 다른 구조를 살펴보죠. 큐에 대해서 살펴봅시다.
큐(Queue), Cue?
큐는 철자가 Queue입니다. Cue는 아니죠. 당구를 좋아하는 분들은 Cue라고 하실 겁니다. 뭐, 둘 다 발음은 같습니다. 그러니 편하신 대로 기억하면 되겠지요. 큐 역시 자료구조입니다. 닷넷에서는 큐도 편리하게 사용할 수 있도록 클래스로 포장해서 제공하고 있습니다. 기본적인 것들은 동일하겠지요. 데이터를 집어넣고, 데이터를 꺼내오고, 데이터를 꺼내오지는 않고 안에 뭐가 있는지 살짝 들여다보는 Peek 같은 메소드가 있습니다.
큐를 그려보면 이 그림과 같습니다. 차례대로 데이터를 넣습니다. 1, 2, 3, 4 이렇게 하나씩 넣어주면 됩니다. 그리고 차례대로 데이터가 빠져나갑니다.
이처럼 먼저 들어오니까 First In이고, 먼저 들어온게 먼저 나가니까 First Out이라고 합니다. 간단히 First In/First Out이라고 하고, 줄여서 FIFO 구조라고 합니다. 뭐, 이런 영어쯤은 몰라도 됩니다. 큐가 뭐냐고 물어보면 위 그림을 그리면서 큐라는 것은 이런 것이다라고 설명할 수 있어야 하는 것이 중요하지요. 보통 이러한 종류의 큐는 어디에 사용할까요? 큐도 이유가 있으니 만들었을 것이고, 어딘가에 써먹을 필요가 있으니 쓰는 게 아닐까요? 실제로 큐는 많이 사용하고 있습니다. 여러분이 그걸 모를 뿐이죠.
큐는 대부분의 경우에 버퍼에 많이 사용합니다. 큐를 처음보면 "에이, 저게 뭐야! 그냥 순서대로 넣었다가 순서대로 나가는 거라면 굳이 쓸 필요가 없지 않아? 직접 하나씩 읽어오면 될텐데…"라는 생각이 들 겁니다. 우리가 가장 즐겨 듣는 MP3 파일을 생각해 봅시다. MP3 파일에서 한 바이트, 한 바이트… 읽을 때 마다 하드 디스크를 읽어들이나요? 아니죠! 가끔 하드 디스크를 읽어들입니다. 한 번 하드 디스크를 읽어들일 때마다 MP3 파일에서 10~15초 동안 재생할 데이터를 읽어 들입니다. 만약 재생할 때마다 하드 디스크를 읽어들인다면 MP3 음악 파일 하나를 듣는 것 만으로도 하드 디스크를 독점하게 되고 말 겁니다. 이때 버퍼라는 것을 사용해서 이러한 작업을 원활하게 할 수 있습니다. 또한 하드 디스크가 바쁘더라도 10초에 한 번씩 읽어들이면 되기 때문에 음악을 끊김없이 듣는 데도 도움이 됩니다. 인터넷에서 음악을 듣거나 동영상을 감상할 때 "버퍼링"이라는 용어를 많이 보았을텐데요 바로 이러한 버퍼를 위한 자료 구조로 가장 많이 사용하는 것이 큐입니다.
자료 구조론을 공부하고, 큐가 뭔지 알아도 이것을 어디에 쓰는지 모르면 소용없습니다. 큐를 반드시 버퍼 구조로만 사용하는 것은 아니지만, 가장 빈번하게 사용합니다. 이것만 기억하시면 오늘 여러분은 성공하신 겁니다.
여자분들은 싫어하겠지만 군대 얘기를 해볼까요. 훈련병 때는 정말 하루 종일 뛰고, 구르고 하다보니 식사시간 만큼 기다려지는 시간이 없습니다. 비록 "수저 들어!", "밥!", "국!" 하는 교관의 구호에 맞춰서 밥을 먹는다고 하더라도 말이지요. 군대 안 가신 분들을 위해서 얘기하면 밥도 마음대로 못 먹습니다. "밥"하면 밥을 입에 넣고, "국"하면 국을 입에 넣는 거랍니다. 군대 다녀온 분들은 이미 쿡쿡 거리고 계시는군요. 뻥이에요! (웃음)
하여간 배고픔에 못이겨 이렇게 기다려지는 식사 시간에 조금이라도 빨리 밥을 먹고, 다른 사람들이 밥을 먹는 동안 잠시라도 쉬는 시간을 만끽하기 위해 식사 시간 집합이면 식당 앞에 가장 먼저 가서 기다리는 사람들이 있습니다.
이렇게 식당 입구에 차례대로 줄을 서서 기다리죠. 근데 가끔 조교들이 이런 장난을 한 기억이 납니다. "오늘은 뒤에서부터 들어간다!" 이 때, "내가 제일 먼저 밥을 먹을 거야"라고 생각하던 사람들의 인상이란… 희비가 교차하는 순간입니다.
이처럼 조교들이 "오늘은 뒤에서부터 밥 먹는다!"라고 하는 것과 같은 자료 구조가 있습니다. 바로 "스택"이죠! 스택은 다음과 같습니다.
스택은 먼저 들어간 자료가 가장 마지막에 나옵니다. 바꿔 말하면 제일 마지막에 들어간 녀석이 제일 먼저 나온다는 것입니다.
위 그림과 같은 자료구조입니다.
여러분이 평소에 제일 많이 들어봤던 것 중에 하나가 바로 스택입니다. 스택은 어떻게 사용하나요? 이런 경우를 생각해보세요. 윈도우에서 대화상자를 표시하는 MessageBox()라는 함수가 있다고 합시다. 여기에는 여러 가지 인자를 전달합니다. 보통은 다음과 같이 사용하지요.
MessageBox(0, "나는 대화상자 내용", "나는 대화상자 제목", 0)
위 그림과 같은 결과가 나오겠지요. 실제로 MessageBox의 호출은 스택을 사용합니다. 데이터를 집어넣을 때는 push라는 것을 쓰고, 꺼내오는 것은 pop이라고 사용합니다. 원래 영어 단어 뜻과 똑같습니다.
push 0
push "나는 대화상자 제목"
push "나는 대화상자 내용"
push 0
call MessageBox
이와 같습니다. 이게 진짜 어셈블리에서의 코드입니다. 다른 건 없어요. 어쨌거나 메소드에 사용한 인자들을 끝에서부터 집어넣는 다는 것을 알 수 있습니다. 그리고 함수를 호출하면 집어넣었던 것들을 하나씩 꺼내서 사용하게 됩니다. 그림으로 그릴 수 없는 게 안타깝네요! call MessageBox를 만나게 되면 메소드는 지금까지 집어넣은 것들을 위에서부터 꺼내쓰게 됩니다. 즉, 우리가 메소드에서 생각하는 것처럼 차례대로 인자들을 가져가는 것이지요. 0, "나는 대화상자 내용", "나는 대화상자 제목", 0와 같은 순서로 꺼내쓰게 됩니다.
이와 같이 메소드에 인자들을 전달하기 위해 임시로 자료를 저장하는 구조로 스택을 사용하게 됩니다. 어찌 보면 저희하고는 별로 인연이 없는 자료 구조입니다. 주로 프로그래밍 언어 내부에서 빈번하게 사용하는 자료 구조라는 것을 알 수 있을 뿐입니다. 이와 같은 스택을 사용하게 되면 얻을 수 있는 장점이 메소드에 전달할 인자가 몇 개 인지 생각하지 않아도 된다는 것입니다. 몇 개의 인자가 있는지, 몇 개의 인자를 가져와야 하는지에 대한 과정이 필요 없다는 이야기입니다.
Method(arg0, arg1, arg2, arg3, arg4, arg5)
이와 같이 되어 있다고 해도, 끝에 해당하는 arg5에서 차례대로 arg4, arg3, arg2, arg1, arg0와 같이 스택에 집어넣고 call Method를 하게 되면 메소드는 스택이 텅 빌 때 까지 몽땅 꺼내가기만 하면 됩니다. 메소드는 arg0, arg1, arg2, arg3, arg4, arg5와 같이 차례대로 꺼내기만 하면 됩니다. 간단하죠!
여담이지만 인자를 해석하는 순서에는 left to right와 right to left라는 두 가지 방법이 있습니다. 지금까지 설명한 메소드 호출 방법은 right to left입니다. 끝 arg5에서 시작해서 왼쪽에 해당하는 arg0까지 차례대로 해석하는 순서입니다. 이미 알고 있듯이 right to left는 구현하기가 쉽기 때문에 대부분의 프로그래밍 언어들은 right to left를 사용합니다. 인자들을 저장하기 위한 자료 구조 역시 스택을 사용하겠지요. 이와 반대되는 left to right라는 것은 많이 사용하지 않습니다. 인자가 몇 개인지 알아내는 것이 까다롭기 때문이죠. 소위 천재들이 쓸만한 방법이랄까. -_- 스택에 대해서는 이 정도로 끝내겠습니다.
사전(Dictionary)
이제 배열에 대해서 조금 더 생각해 보도록 하지요. 배열을 많이 사용하지만 가끔 아래와 같은 방식으로 사용하는 것을 볼 수 있습니다.
person[0] = "이름"
person[1] = "성"
person[2] = "주소"
이와 같이 필요한 데이터를 저장하기 위해 배열을 사용하는 경우 0번째에는 항상 이름을, 1번째에는 항상 성을, 2번째에는 항상 주소를 넣어야 한다는 약속이 필요합니다. 그리고 이 약속을 어기면 데이터는 알 수 없게 꼬여버리고 프로그램은 엉망이 되어 버리지요. 그리고 중요한 것은 이렇게 만들면 프로그래밍하기가 어렵다는 것입니다. 규칙들이 많으면 많을수록 외워야 할 것들이 많아진다는 이야기이니까요. 그래서 숫자 대신 사용하기 쉬운 단어 즉 은유를 사용할 수 있게 한 것이 Dictionary 객체입니다. 그래서 다음과 같이 쓸 수 있도록 해주지요.
person("name") = "길동";
person("surname") = "홍";
person("address") = "우주시 우주동 외계인 마을";
이렇게 쓸 수 있게 됩니다. 그리고 언제든지 주소가 알고 싶다면 person("address")를 사용해서 알 수 있습니다. 어떤가요? 첫번째의 배열의 0, 1, 2를 사용하는 것 보다는 name, surname, address를 사용하는 것이 쉽지 않은가요? 이와 같이 사용할 수 있도록 해주는 것이 사전(Dictionary) 객체 입니다.
그렇다면 어떤 경우에 배열을 쓰고, 어떤 경우에 사전 객체를 쓸 것인가는 자명해 집니다. 프로그래밍에서 데이터를 처리할 때, 데이터의 개수가 얼마인지는 모르지만 그러한 데이터를 일괄 처리하는 것에는 배열을 사용하는 것이 현명합니다. 얼마나 많이 있고, 어떤 데이터가 들어있는지 알 필요도 없기 때문이죠. 그저 데이터를 읽어와서 배열에 차례대로 저장한 다음에 총 합계를 구하든지 아니면 값들을 차례대로 읽어서 처리하는 경우에 배열을 사용하면 됩니다. 반대로 배열은 써야 하는데 위와 같이 배열에 어떤 데이터가 들어갔는지가 중요하고 그것들을 여러분이 제어해야 한다면 0, 1, 2와 같은 배열의 서수(또는 색인, index)를 사용하는 것보다는 은유(즉, 이름)를 사용하는 것이 더 쉬운 프로그래밍입니다. 자료 구조 역시 프로그래밍을 쉽게 하기 위한 것이지 프로그래밍을 어렵게 하기 위한 것이 아니라는 점을 기억하세요.
인덱서(indexer)
원래 다른 프로그래밍 언어들에서는 객체들을 배열처럼 다룰 수 없었습니다. C#에서는 객체들을 배열처럼 다룰 수 있게 했습니다. 그리고 배열의 서수(index)와 조금 구분하기 위해 인덱서(indexer)라는 용어를 사용합니다. 이것들의 의미는 어떻든 간에 이제 객체도 배열로 사용할 수 있습니다. 객체도 배열처럼 다룰 수 있다면 편하게 할 수 있는데, 왜 복잡하고 어렵게 해야 하는가라는 고민 때문에 객체로 배열처럼 쉽게 다룰 수 있게 하기 위한 개념으로 탄생한 것이 인덱서라는 것만 알면 됩니다. 그리고 인덱서는 클래스를 구현할 때 정의해야 합니다. 이에 대해서는 책에 자세히 나와 있습니다. 클래스에서 인덱서를 구현하고 나면 객체를 배열처럼 사용할 수 있게 할 수 있습니다. 인덱서가 유용하기는 하지만, 아직 여러분에게 설명하기에는 조금 무리가 있는 것 같습니다. 책에 설명된 정도로 만족해 주시면 감사하겠습니다.
이로서 오늘은 9장까지 마쳤습니다.
모두 9장까지 읽어보고, 예제를 못 해보신 분들은 예제를 해보시기 바랍니다. 그리고 예제가 돌아가는 것을 보면서 위에서 설명한 자료 구조들의 개념이 맞는지 눈으로 확인해보세요. 이것이 매우 중요합니다. 오늘 설명드린 자료 구조는 여러분이 어떠한 프로그래밍 언어를 사용하든, 어떤 운영체제를 사용하든 상관없는 것입니다. 특정 프로그래밍 언어에 지나치게 얽매여서 생각할 필요는 없습니다.
10장은 문자열에 대한 것과 정규식에 대한 것이고 11장은 예외처리입니다. 예외 처리에 대해서는 이미 설명했기 때문에 다시 설명하지 않습니다. 제가 생략한 부분들은 책에 자세히 나와 있습니다. 12장은 대리자(delegate)와 이벤트에 대한 것입니다. 프로그래밍이 아주 쉽고 이 책 또한 매우 쉽다고 이야기했지만, 12장 만큼은 어렵다는 사실을 인정하지 않을 수 없습니다. 그러니 꼼꼼하게 읽고, 예제를 직접 해보면서 그 형식을 눈여겨 보셨으면 합니다.
다음 시간에는 12장까지 설명을 진행하고, XML에 대해서도 설명하는 시간을 갖겠습니다. 우리의 목표는 ASP.NET 웹 프로그래밍을 멋지게 하는 것입니다. 사실, 13장, 14장, 15장, 16장 모두 각각 1,000 페이지 정도 되는 책을 봐야 합니다. 하지만 저도 여기서는 간단하게 설명할 겁니다. 책도 간단하게 설명하고 있잖아요? 사실 이것들은 입문서에서 설명하기에는 그 범위를 넘어갑니다. 그리고 ASP.NET 웹 응용 프로그램을 작성하는 것을 목표로 하고 있기 때문에 ASP.NET 응용 프로그램을 작성하는 것에 대해 학습하기 위해 새로운 교재를 선택할 것입니다. 사실 ASP.NET 응용 프로그램을 공부하기 위한 교재 선정은 아직 고민 중에 있습니다.
아직은 C#을 공부하는 단계이므로 C#부터 열심히 합시다. 지금은 이 책을 보면서 열심히 개념을 익히세요. 그리고 기초를 튼튼히 해두면 됩니다. 응용 이라는 것은 이러한 기초라는 조각들을 어떻게 꿰어 맞추는가에 달려있습니다. 기초가 튼튼하면 조각 맞추기가 쉽지만 기초가 부실하면 조각 맞추기가 어렵게 느껴지는 법입니다.
마지막으로 MSDN의 사용법에 대해서 간단히 살펴보지요. 지금까지 여러분은 Console.WriteLine()을 지겹게 사용해 왔습니다. 한번 MSDN에서 찾아보도록 하지요. 먼저 메뉴에서 Microsoft Visual Studio .NET 설명서를 선택합니다.
실행하면 다음과 같이 나타납니다.
화면 왼쪽의 탭을 보면 목차, 색인, 검색, 즐겨찾기가 있습니다. 여기서 색인을 선택합니다.
[색인을 선택한 화면]
찾을 대상에 Console.WriteLine을 입력합니다.
입력하면 자동으로 색인이 이동합니다. 원하는 것을 찾았으면 엔터키를 누릅니다. 그러면 화면 오른쪽에 다음과 같은 설명이 나타납니다. 파란 제목 부분을 보면 .NET Framework 클래스 라이브러리라고 표시되어 있는 것을 알 수 있습니다. 이 부분이 중요합니다. 특정 언어(C#, VB.NET)에만 해당하는 내용인 경우에는 C#이나 VB.NET이라고 표시됩니다. 화면에서 가장 아래로 이동하면 다음과 같은 항목들이 나타나는 것을 볼 수 있습니다.
참고 항목을 보면 Console 클래스, Console 멤버, System 네임 스페이스가 나타납니다. 왜 System 네임스페이스가 참고 항목에 나타날까요? 네, Console.WriteLine()에서 Console 클래스가 System 네임스페이스에 있기 때문입니다. 따라서 여러분의 코드에서 Console.WriteLine을 사용하고 싶다면 다음과 같은 코드를 추가해야 합니다.
using System;
그러니까 여러분이 지금까지 작성한 프로그램에서 Console.WriteLine()을 사용하지 않는다면 using System;도 쓸 필요가 없습니다. Console 멤버를 선택하면 Console 클래스에 있는 다양한 메소드들을 볼 수 있습니다. WriteLine()은 출력 후에 다음 줄로 바꾸지만 출력 후에 줄을 바꾸고 싶지 않다면 Console.Write()를 사용할 수 있습니다. 사용자에게 입력을 받고 싶은 경우에도 Console.Read()와 Console.ReadLine()을 사용할 수 있습니다. Console 멤버 항목을 보면 자세한 설명이 나와있습니다. 게다가 예제로 나와 있는 것을 알 수 있습니다. Console.WriteLine() 메소드를 보면 형식이 나와 있습니다.
public static void WriteLine(string);
그 중에 하나가 이런 형식입니다. void라는 것은 어떤 것도 반환하지 않는 다는 것을 알 수 있습니다. static에 대해서는 나중에 설명합니다.
오늘은 여러분에게 숙제가 있습니다. 시스템에 있는 드라이브 목록을 출력하는 프로그램을 짜오세요. 드라이브 목록은 Environment.GetLogicalDrives()를 사용하면 됩니다. 루프는 foreach를 사용하세요.
그럼~