'공부/프로그래밍 일반'에 해당되는 글 9건
- 2010/06/06 루비 프로그래밍 언어 (4)
- 2009/05/10 Editplus Erlang Syntax 파일 (4)
- 2008/12/27 뇌를 자극하는 윈도우즈 시스템 프로그래밍
- 2008/02/10 UVa 100문제 달성!!! (3)
- 2007/09/18 복잡한 포인터 선언 이해하기 (3)
- 2007/09/14 다중 포인터 배열의 포인터 (2)
- 2007/09/12 디버깅 모드와 릴리즈 모드 (2)
- 2007/01/19 Hello World! (6)
- 2006/04/11 넥슨 입사문제 1번 (7)
윤성우씨가 집필한 책을 읽을때마다 그 설명을 보고 놀라곤 한다. 수 많은 번역서들의 어색한 문장과 우리나라 정서와는 뭔가 맞지 않는 듯한 설명으로 다가가기 어려운게 사실인데, 이분이 집필한 책은 그렇지가 않다.
책 제목은 윈도우즈시스템 프로그래밍 이지만 컴퓨터 구조나 간단한 운영체제에 대한 설명까지 곁들여져 있다. 내가 읽으면서 가장 인상 깊었던것은 윈도우즈 프로그래밍에 대한 설명보다 컴퓨터 구조에 대한 설명인데, 컴퓨터 구조를 직접 하나 하나 설계해 가는 과정중 "왜 이 레지스터가 필요한지" 그 이유를 끄집어 내주기 때문에 컴퓨터가 왜 이런 구조를 가지고 있는지를 받아들이고 이해할 수 있게 해준다.
한빛미디어에서는 원래 동영상 강의는 따로 돈을 내야 볼 수 있지만 윤성우씨의 부탁(신념?)으로 동영상강의 무료 쿠폰까지 책에 들어가 있으니 동영상 강의로도 책 내용을 복습(혹은 예습)할 수 있다. 학습효과는 두배!
맨 마지막 챕터는 설명이 약간 부실한 감이 있긴 하지만, 초보 개발자가 윈도우즈 시스템 프로그래밍에 입문하기 위해서는 정말 안성맞춤인 책이다.
덧1) 윤성우씨가 최근에 C언어 책을 하나 더 집필하셨던데, 이건 왠지 좀 아쉽다 =_=.
덧2) 이 책을 다 읽은진 몇주가 지났는데, 그당시 진행하고 있던 프로젝트에서 막히는 부분이 이 책덕분에 해결되었다. 역시 개발자는 개발하는 기간에도 꾸준히 공부를 해야 하는것!
http://acm.uva.es/p 에 있는 2000여개의 문제중 드디어 100개를 풀었습니다 [....] 제작년에 ACM-ICPC라는 대회를 접하게 되면서 Programming Challenges를 사서 공부를 했었는데, 두달정도의 준비기간동안 충분한 준비를 하지 못해서 고배를 마셨던 기억이 [......] 있는데요, 산업기능요원으로 복무하는동안 알고리즘 문제를 풀면서 실력을 차곡 차곡 쌓고자 위 사이트의 문제를 풀기 시작했습니다.
이번에 풀면서 어려운 문제는 전혀 안건들었어요. 쉬운문제가 2000개중에 100개는 있겠지! 라는 생각으로 간단한 수열혹은 규칙만 사용하는 문제들을 골라골라 풀어서 100개를 달성했습니다. (이중에는 큐나 스택등의 초 간단한 자료구조를 필요로 하는 문제도 있었던거 같아요. 왠만해서는 안풀었습니다만..... 정확히 기억이 -_____-;;) 문제를 풀면서 "팩토리얼" 과 ,"소수"을 가지고 얼마나 문제를 울궈먹을 수 있는지를 느낄 수 있었습니다. 무슨 변형문제가 그렇게 많은지.. ( 쉬운 문제의 기준은 http://felix-halim.net/uva/hunting 와, 개편된 uva의 문제 사이트인 http://icpcres.ecs.baylor.edu/onlinejudge/ 의 %를 참고했습니다.)
어떤 문제는 당황스럽게까지 했는데, 600자리의 정확도를 요하는 문제인듯 보였으면서 double형으로 계산해도 Accepted가 뜨는 문제도 있었어요, 영어 해석이 전혀 되지 않아서 http://acm.uva.es/board 에 풀이를 올려준 글을 보고 풀었던 문제도 있고(완소 board♡)... 쉬운줄 알고 덤볐다가 전혀 갈피를 잡지 못하고 결국 gg친 문제도 있습니다.
문제를 풀면서 느꼇던 점들은 http://uva.xo.st 에 올렸는데, 올린 날짜들을 보니 작년에 쉬운거 100문제 풀기를 도전했을때 잠시 반짝 하고 그간 너무 띄엄띄엄 풀었다는게 눈에 확 띄네요. 반성반성.
쉬운문제 100개정도 풀고 어려운 알고리즘 공부를 하자 라고 다짐을 했었으니, 이제 알고리즘 공부 본격적으로 해야 하는데.... 사둔 알고리즘 책은 이미 5권을 넘어섰고, 그 내용또한 간단한게 아닌데다가 회사 프로젝트는 점점 빡빡해지고 영어공부랑 자격증 취득 계획도 있어서 언제 공부가 가능할련지 모르겠습니다. ㅠㅠ... 적어도 Introduction to Algorithms에있는 내용의 반 이상은 알고(사실 거의다 아는게 희망사항!), STL은 모두 사용할 수 있을정도의 실력은 키우고 싶은데 말이죠..
학부 2학년에 있던 자료구조및알고리즘 시간에 나름대로 열심히 수강을 했고, 그때는 배운걸 직접 손수 구현이 가능했는데 지금은 솔직히 불가능합니다 -_-.. 그때 배웠던 책을 꺼내들고 다시 복습한 다음에 Introduction to Algorithms이나 The Art of computer Programming을 읽어야 겠어요..
언제나 하고싶은건 많고 해야할 일도 많은데 시간이 부족한거 같습니다.ㅜㅜ
여담이지만.. 요즘 The Secret이란 책을 읽고 있는데, 그 책에서 "시간이 부족하다" 라고 생각을 하면 정말 시간이 부족해진다던데.. "난 시간이 충분해^^" 라고 생각을 하며 진짜로 그렇게 믿고 살아야 한답니다. (말이 좀 이상하네요 ^^;;)
회사에 있는 MircoSoftware ( <월간>마소 ) 8월호를 읽던중 반가운 글을 보았습니다.
바로 이전 포스팅인 포인터에 대한 글이였는데, 제목이 무려 "신입 개발자를 위한" 복잡한 포인터 선언 이해하기. 포인터의 난해함때문에 고민을 했던적이 있던지라 반가운 글이였습니다.
복잡한 포인터 선언 이해하기
개발자 커뮤니티의 C언어 게시판에 자주 등장하는 질문 가운데 하나가 바로 복잡한 포인터 선언문 해석에 대한 것이다. 대부분의 초보 개발자나 학생들은 이를 막연히 외우려고 노력한다. 'int *a[3]은 int 포인터를 저장하는 배열', 'int (*a)[3]은 int 배열에 대한 포인터' 라는 식으로 암기하는 것이다.
하지만 이렇게 외운 지식은 그 형태가 조금만 달라져도 무용지물이 되고 만다.
그렇다면 어떻게 해야 이러한 선언문을 쉽게 해석할 수 있을까? 간단하다. 다음의 규칙만 이해하면 된다.
복잡한 선언을 정확하게 이해하기 위한 첫 단계는 선언문 내부에 나타나는 각 요소의 정확한 의미를 이해하는 것이다.
아래 표에는 선언문 내부에 등장하는 각 구성요소의 의미와 사용 예가 나와 있다. 이처럼 선언문을 해석할 때 영어를 활용하면 훨씬 간편하게 의미를 이해할 수 있다. 따라서 각 기호에 맞는 영어 표현도 함께 알아두는 것이 좋다.
|
기호 |
표현 |
의미 |
예 |
|
* |
pointer to | 특정 대상체를 가리키는 포인터 |
int *a; |
|
[] |
array of | 특정 대상체를 저장하는 배열 |
int a[3]; |
|
() |
function | 인자를 받고 값을 리턴하는 함수 |
int a(); |
다음으로 이해해야 할 것은 선언문을 해석하는 순서다.
선언문은 선언 대상이 되는 변수명에서 시작해 오른쪽으로 가면서 해석한다. 선언문의 끝이나 오른쪽 괄호를 만나면 방향을 바꿔 왼쪽으로 가면서 해석한다. 왼쪽으로 가면서 해석을 하다 왼쪽 괄홀르 만나면 다시 오른쪽으로 가면서 해석한다. 이렇게 해서 선언문의 가장 왼쪽 끝에 도달하면 해석이 마무리된다.
| 표현식 | 해석 순서 |
| 해석 결과 | |
| int **a; | a => a; => *a; => **a; => int **a; |
| a is a pointer to pointer to int a는 int를 가리키는 포인터의 포인터다. | |
| int *a[3]; | a => a[3] => a[3]; => *a[3] => int *a[3]; |
| a is an array of 3 pointer to int a는 int를 가리키는 포인터를 세 개 저장하는 배열이다. | |
| int (*a)[3]; | a => a) => (*a) => (*a)[3]; => int (*a)[3]; |
| a is a pointer to array of 3 int a는 int 세 개를 저장하고 있는 배열을 가리키는 포인터다. | |
| int *(*(*fp1)(int))[10]; |
fp1 => fp1) => (*fp1) => (*fp1)(int) => (*fp1)(int)) => (*(*fp1)(int)) => (*(*fp1)(int))[10]; => *(*(*fp1)(int))[10]; => int *(*(*fp1)(int))[10]; |
| fp1 is a pointer to function that takes an int as an argument and returns a pointer to an array of 10 pointers to ints. fp1은 int를 인자로 받고 int에 대한 포인터를 열 개 저장하는 배열을 가리키는 포인터를 리턴하는 함수에 대한 포인터다. | |
| char *(*(**foop[][8])())[]; | foo[] => foo[][8]) => *foo[][8]) => (**foo[][8]) => (**foo[][8])()) => *(**foo[][8])()) => (*(**foo[][8])())[]; => char *(*(**foo[][8])())[]; |
| foo is an array of array of 8 pointer to pointer to function that returns a pointer to array of pointer to char. foo는 char를 가리키는 포인터를 저장하는 배열을 가리키는 포인터를 리턴하는 함수에 대한 포인터를 가리키는 포인터를 8개 저장할 수 있는 배열에 대한 배열이다. |
/*
역시 포인터는 어려운 존재입니다 -__-;
이 글에서 소개되어있는 해석하는 방법은 "영어"를 사용하는 사람들을 위한 해석방법이군요, 문장의 순서가 우리나라와는 다르기 때문에 우리나라에 맞게 적용하기 위해서는 반대 방법으로 해야할듯 합니다. 이를테면 괄호의 맨 밖부터 시작해서 왼쪽부터 오른쪽으로 가면서 끝을 만나면 그 내부의 괄호안에 들어가서 왼쪽에서 오른쪽으로 진행하는 식으로.. (실제로 해보시면 회색처리된 한글 해석순서와 비슷하다는걸 알 수 있습니다. 네 비슷입니다 =_=, 완전히 적용시키기엔 무리가 있네요 [][8] 같은경우는 오른쪽에서 왼쪽으로 가야 합니다.
PS. micro Software의 2007년 8월호 325page의 글을 옮겨 적은 것 입니다. 문제가 될경우 알려주시면 삭제하겠습니다.
*/
하지만 어느 프로젝트를 진행중에 "이차원 포인터 배열의 포인터"를 한 함수에서 반환을 하고, 다른 함수에서 인자로 받는 코드를 작성해야 하는 경우가 발생했었다.
(이런식의 코딩은 해본적이 없어서 금방 코드가 작성되지 않았던..;;)
하지만 함수를 작성하고나서 생각한것은.. "이건 객체지향이 아니자나!!" _no
{
public:
void ReceiveFunction(void* in)
{
m_data = (DataType* (*)[10][10])in;
}
private:
DataType* (*m_data)[10][10];
};
class CSend
{
public:
void* SendFunction()
{
return (void*)m_data;
}
private:
DataType* m_data[10][10];
};
int main()
{
CSend s;
CReceive r;
r.ReceiveFunction(s.SendFunction());
return 0;
}
" DataType*(*)[10][10] " 이런식의 코딩이 가능하다는것을 알아냈다는것에 의의를 두자. (라고 자위하고 있다)
많은 개발자들이 쓰고 있는 IDE인 Visual Studio.
Visual Studio에는 디버깅 모드와 릴리즈 모드가 있죠, 릴리즈 모드는 프로그램을 배포하기 위해 컴파일 하는 모드로, 디버그모드로 컴파일시 들어가는 디버깅에 필요한 자질구리한 정보를 뺀 알짜 프로그램만 쏙~ 뽑아내는것 입니다.
하지만 단지 이것만 생각하기엔 디버깅 모드와 릴리즈 모드는 이상한 다른점이 있어요. (이상하고 정말 이상해요)
그 이상하고 황당한 다른점을 소개해드리고자 합니다.
첫번째, 릴리즈모드는 초기화를 해주지 않는다.
어느정도 경험이 있는 개발자라면 다 알고 있는 사실입니다. 하지만.. 제가 겪은건 좀 황당해요.
2년전 학교에서 텀프로젝트를 하면서 발견했던 현상입니다.
이는 Visual Studio의 버그인지는,, 확실히 모르겠습니다만 Visual Studio .NET 2003에서 발생하는건데요,
C/C++의 기본서에 모두 써 있는 내용이 있습니다. "전역변수는 0으로 초기화된다". 특별한 명시를 해주지 않아도 전역으로 선언한 변수들은 초기값이 0으로 된다는 말입니다. 굳게 믿고 전역변수들은 컴파일러가 알아서 초기화를 잘 시켜줄거라 생각을 했죠.
하지만 그 전역변수에서 문제가 발생했었습니다. 초기화를 따로 시키지 않고 사용을 했었는데 Release모드로 컴파일하니 값이 처음엔 0으로 잘 나오다가 값자기 값이 바뀌는겁니다 -_-; 정말 황당했어요, 처음부터 값이 제대로 나오지 않았다면 초기화에 문제가 있구나~ 라고 생각할 수 있겠는데 값이 갑자기 바뀌어 버리는겁니다. 당시 프로젝트 과제를 제출할때는 해결을 하지 못해서 Debug모드로 제출을 했었지만, 나중에 "디버그모드에서 잘 돌아가다가 릴리즈모드에서 에러가나는것은 초기화문제 때문일 가능성이 크다" 라는 글을 보고서야 초기화구문을 넣어주니 제대로 동작하는것을 확인할 수 있었습니다.
두번째, 릴리즈모드는 같은 문자열 상수라도 서로다른 공간에 할당한다.
char *b = "ABCDE";
if( a == b ) printf("Good!\n");
else printf("Bad!\n");
이 코드의 실행결과는 어떨까요?
a, b모두 같은 문자열이므로 Good! 이출력됩니다. 라고 말하는 분은 없을꺼라 생각합니다. 쌍따옴표로 묶인 문자열은 C/C++에서는 문자열상수로써 메모리공간에 할당이 되고, 그 주소값이 a와 b에 들어가므로 다른곳에 값이 할당될때는 틀릴수도 있습니다.
컴파일러가 "같은 문자열 상수"일경우엔 최적화 과정을 통해서 a가 가르키는 "ABCDE"와 b가 가르키는 "ABCDE"를 동일한 메모리 공간상에 할당을 하고 그 주소를 반환해주기 때문에 Good!이 출력됩니다. 라고 대답하는 분은 있으실꺼라 생각됩니다. 물론 저도 그렇게 생각하고 있었고요. Debug모드에서는 위 설명대로 작동이 됩니다. 문자열상수의 값이 같으면 그 주소값도 같게 되요.
하지만, Release모드에서는 두 문자들을 서로 다른 메모리공간에 할당을 합니다. a와 b의 값이 다르게 되요. VS 6.0이나 .NET 2005이상은 어떨지 모르겠습니다만.. 회사에서 쓰는 Visual Studio.NET 2003 에서는 이런 현상이 일어나네요..
혹, 컴파일옵션을 바꾸면 어떨까.. 하는 생각에 Debug모드와 Release모드 사이에 옵션중 다른점을 모두 같게 고치고 했는데도 Bad!가 나옵니다. _no
/*
첫번째 덕분에 전역변수도 초기화해서 사용하는 버릇이 생겼습니다. 객체지향 개발방법론으로 코딩할때는 전역변수를 쓸일이 없지만요;
두번째 같운경우는 좀 아쉽습니다. 같은 문자열상수면 같은 공간에 할당되었으면 하는데 혹시 Release모드에서도 같은문자열상수는 같은공간에 할당되도록 설정하는 방법이 있는지 아시는분은 덧글 남겨주세요 :D
*/
#include <iostream>
class CPre
{
public:
CPre()
{
std::cout << "Hello World! " << std::endl;
}
};
CPre PrintOut;
int main()
{
return 0;
} 어디서 봤던 코드인지는 까먹었다. C++을 공부한지 얼마 안되었을때 접했었는데., 신기하고 재미있었던 코드.
주제가.. main이 시작되기 전에 Hello World출력하기 였던가?;;
어떤 자연수 n이 있을 때, d(n)을 n의 각 자릿수 숫자들과 n 자신을 더한 숫자라고 정의하자.
예를 들어 d(91) = 9 + 1 + 91 = 101
이 때, n을 d(n)의 제네레이터(generator)라고 한다. 위의 예에서 91은 101의 제네레이터이다.
어떤 숫자들은 하나 이상의 제네레이터를 가지고 있는데, 101의 제네레이터는 91 뿐 아니라 100도 있다.
그런데 반대로, 제네레이터가 없는 숫자들도 있으며, 이런 숫자를 인도의 수학자 Kaprekar가
셀프 넘버(self-number)라 이름 붙였다.
예를 들어 1,3,5,7,9,20,31 은 셀프 넘버 들이다.
문제..
"1 이상이고 5000 보다 작은 모든 셀프 넘버들의 합을 구하라"
내가 푼 소스보기
/*
5분도 안걸린거 같다.
처음에 문제 봤을땐 전혀 감도 못잡았는데
신기하네..
프로그래밍이 잘 될때와
잘 되지 않을때가 있는거 같은 기분이 들뿐..
*/
erlang.stx