Study - Programming/C/C++2007. 11. 5. 23:39
사용자 삽입 이미지
사용자 삽입 이미지


심심해서 만들어 본것. 실제로 되니까 조금 신기하네. 이왕이면 star함수를 쓰지 않고 for 안에 for를 넣고 싶었는데 안되더라.
Posted by 머리
Study - Programming/C/C++2007. 11. 4. 01:44

  솔직히 말해서 C++은 공부를 거의 문법 스펙을 읽기만 하고 실제로 짜본건 거의 없었다. 한떄는 C보다 C++을 훨씬 많이 하곤 했었는데 지금은 거의 C로만하니 당연히 까먹을 수밖에.

  거기다 이번에 하드디스크 데이터를 날려먹으면서 그동안 연습해왔던 C++코드까지 다 잃어버려서 새로 시작하자는 의미로 하나 하나 클래스 몇개를 만들어 보기로 했다.

  그 첫번째로 우선 Integer Class를 구현해 보았다. 기본 데이터 타입인 int를 직접 만들어 본 것. 역시 많이 버벅대었다. 제대로 되었는지도 잘 모르겠고. 특히 멤버의 생성과 소멸 부분에서 많이 헤매었고 연산자 오버로딩 부분도 아직 잘 모르겠다.

  구현한 것들은 다음과 같다.
1. Constructor//Destructor
2. Assignment Operator
3. Relationship Operator
4. Arithmetic Operator
5. Array Operator

  뭐 대부분이 연산자와 관련된 부분이지만 실제 필요한 부분은 거의 넣은 것 같다. 많이 부족하지만 앞으로 많이 공부해 봐야지.

  다음 구현할 것은 String Class. 힘내자.

invalid-file

Integer_class

Posted by 머리
Study - Programming/C/C++2007. 10. 5. 03:01
  흠.. 학교 친구들이 선대 시간에 매트랩으로 확률을 이용하여 원주율을 구하고 그 그래프를 그려 보라는 숙제를 하도 많이 물어보더라. 나는 매트랩도 할줄 모르는데..

  그래도 괜찮은 주제다 싶어서 C 콘솔 버전이랑 API 사용해서 한번 만들어 봤다. 일단 Test Case 의 수 입력받고 하는건 다 생략하고(콘솔은 가능), 랜덤하게 좌표를 찍어 내어 그게 사분원(부채꼴) 안에 들어가는 경우의 수를 계산해 내어 pi를 구하는 방식이다.

Number of Test Case = n
Number of Point in Circle = C

(pi * r^2 / 4) / r^2 = C/n
pi/4 = C/n

pi = 4 * C/n

이렇게. 하다보니 콘솔은 그렇게 문제가 아닌데 API를 하도 오랫만에 해서 GDI 새로 공부하고 한다고 시간 다 보냈다. 11시쯤에 시작했는데 끝내니 2시 반.. 뭐 암튼 좋은 공부 되었다.
사용자 삽입 이미지
콘솔 버전
invalid-file

원주율 구하기 콘솔버전


사용자 삽입 이미지

윈도우 버전
Posted by 머리
Study - Programming/C/C++2007. 9. 22. 01:08
  음.. 블로그 포스트가 하도 올릴게 없어서.. 간단히 생각해 본게 C를 처음 접하거나 익숙하지 않은 사람들이 C에 익숙해지게 할 수 있도록 몇가지 간단한 퀴즈를 내 보는 식으로 포스팅을 해보자는 것이였다. 내 실력도 아직 많이 미숙하지만, 간단한 퀴즈 정도는 내 볼 수 있으니까, 내 능력이 되는대로 할만한 퀴즈가 있으면 내 보자 한다.

  커리큘럼은 일반 C 학습과 비슷하게. 이정도를 해결 할 수가 있다면 적어도 그 부분에서는 익숙하게 사용할수 있다고 할 수 있을 것이다. 자유자재라고는 장담 못하지만..

  그럼 첫 번째 퀴즈는 무엇인가? 맨 처음이니 출력 관련 문제를 간단히 내 볼까 한다. 출력 결과는 다음과 같다.
사용자 삽입 이미지

  간단하다. printf함수 하나만을 이용한 간단한 메뉴 출력 프로그램이다. 입력받거나 입력 후 작업 그런 것은 상관없으며, 단순히 위와 같은 결과물만 출력되면 된다. 참고로 Press...이 부분은 출력할 필요가 없다.

  단, 이 프로그램 작성의 조건은 다음과 같다.
1. printf함수의 사용은 한 번 뿐이다.
2. 개행을 하는 것은 \n을 이용하되, 한줄에 저 모든 것들이 나타나서는 안된다. 반드시 한 줄당 코드 한 줄이 있어야 한다.
   즉 저 프로그램을 짜기 위해서는 1개의 printf에 적어도 6줄의 코드(메뉴 및 Bar의 수 만큼)가 있어야 한다는 것이다.(기타 #include, main함수 이런 부분은 제외)

  그냥 단순히 한줄로 다 짜면 되지 않느냐 할 수 도 있겠지만 만약 콘솔에서 10개쯤 되는 메뉴를 출력하게 짜야 한다고 치자. 이것을 한줄로 한다 하면 꽤 복잡 할것이고, 문단 정렬도 꽤 성가실 것이다. 그냥 한 줄당 printf하나를 쓰기에는 뭔가 비효율 적이고, 그냥 하나의 printf로 코드를 보기 쉽게 짜 보는 것도 괜찮을 것이다.

  관심 있는 사람은 비밀글로 리플을 달으면 그에 대한 답을 할 예정이다. 간단한 테크닉이지만 의외로 잘 모르는 사람도 있어서 한번 해 본다. 그럼 답변 기대해야지!
Posted by 머리
Study - Programming/C/C++2007. 9. 15. 01:01

  프로그래밍 처음 배울때 goto쓰지 말라는 소리 많이 들었을 것이다. 그 이유는 goto는 강제적으로 움직이는 것이라 프로그램의 움직임이 자연스럽지 못하고 잘못하면 스파게티 코드를 만들기 쉽기 때문이다. 그리고 goto를 쓰지 않고도 충분히 코드를 짤 수 있고. (참고로 내 친구의 코드 중에 함수를 쓸줄 몰라서 goto를 100개 게 쓴 친구가 있었다.)

  만일 이런 식의 코드가 있다고 했을 때

for(i = 0 ; i < 10 ; i++)
   for(j = 0 ; j < 10 ; j++)
      if(j == 3) break;

  break가 걸리면 break는 안쪽 for문만 멈춘다. 그런데 이 코드에서 break의 목적이 모든 for문을 빠져 나가는 것이라면 어떻게 해야 할까? 여러가지 방법이 있겠지만 그 중의 하나가 forward goto이다. goto를 남용하는것은 매우 위험한 일이지만 이것은 backward goto를 썼을 때 많이 발생한다. 프로그램의 진행방식은 위에서 아래로의 흐름인데 이것을 backword goto로 끊으면 순서를 역행하는 것이라 위험하겠지만 그에 비해 forword goto는 안전한 편이다. 단 뒤처리는 잘해 줘야겠지. 그래도 goto가 속도가 빠른 면이 있어(함수 호출 같은 경우는 스택 왔다 갔다 해야 하고 그렇겠지만 goto는 그런건 없다.)  어떤 면에서 보면 낫다고도 볼수 있다. 그러나 이런 특수한 경우가 아니라면 그나마 추천하고 싶지는 않다. 위 코드같은 경우는 이렇게 수정할수도 있을 것이다.

for(i = 0 ; i < 10 ; i++)
{
   for(j = 0 ; j < 10 ; j++)
   {
      if(j == 3)
      {    
           Break = 1;
           break;
      }
    }
    if (break = 1) break;
}

  나름 신호 변수를 놔둬서 하는 것인데 안정성은 이게 나을수도 있겠지. 속도면을 추구한다면 goto, 아니라면 위 같은 코드도 괜찮을 것이다.

Posted by 머리
Study - Programming/C/C++2007. 9. 2. 23:16

#include <iostream>
using namespace std;
class Example
{
public:
       Example()
       {
                x = 3;
       }
       friend void Show(Example &ex);
private:
       int x;
                  
};

void Show(Example &e)
{
     cout << "x is : " << e.x << endl;
}

int main(void)
{
    Example ex;
   
    Show(ex);

    return 0;
   
}
 
  우선 Show라는 함수의 정의 부분을 보자. 일반 멤버 함수의 정의와는 달리 Example라는 클래스에 있음에도 Example :: 이런 식으로 스코프(Scope)를 해 주지 않았다. 그럼 위로 올라가 Example클래스의 Show함수의 선언을 보자. 특이한 키워드가 붙어 있을 것이다. friend 이 키워들를 붙이면 Show라는 함수는 이 클래스의 멤버 함수가 아니게 된다. 굳이 구분하자면 전역 함수쯤 될 것이다.
 main함수 안에서 Show의 사용을 보자. ex.Show()가 아닌 그냥 Show()로 불러 들였다. 그리고 인자를 보면 ex라는 객체를 레퍼런스로 넣었다. 외부 함수라는 것이다. 그런데 실행을 해 보면 신기하게 ex라는 객체에 private로 선언되어 있는 멤버 변수 x의 값을 불러 온것을 알 수 있다. 즉 friend 함수는 예외적으로 클래스 내부의 멤버에 접근 할 수 있게 해 주는 역할을 한다.

Posted by 머리
Study - Programming/C/C++2007. 8. 30. 23:30

임시 변수를 사용하지 않고, 두 변수를 교환하는 방법


a = a + b;
b = a - b; --------------> b = ( a + b ) - b = a;
a = a - b; --------------> a = ( a + b ) - b = ( a + b ) - a = b;

뭐 a ^=b ^= a ^= b 이거랑 비슷한 착상이네.. a와 b는 달라야 한다고 하더라.. 그리고 물론 덧셈(a+b)시에 오버플로우가 나서는 안되겠지.. 그래서 잘 쓰지는 않는다더라..


잠깐 생각났던 건데 a,b를 값으로 하지 말고 포인터로 넘겨주면 어떨까 생각했는데 젠장.. 포인터는 덧셈 연산인 안되지..

Posted by 머리
Study - Programming/C/C++2007. 8. 29. 01:35

출처 : http://www.winapi.co.kr/clec/cpp2/15-1-4.htm

volatile

volatile 키워드는 const와 함께 변수의 성질을 바꾸는 역할을 하는데 이 둘을 묶어 cv 지정자(Qualifier:제한자라고 번역하기도 한다)라고 한다. const에 비해 상대적으로 사용 빈도가 지극히 낮으며 이 키워드가 꼭 필요한 경우는 무척 드물다. 어떤 경우에 volatile이 필요한지 다음 코드를 보자.

 

int i;

double j;

 

for (i=0;i<100;i++) {

     j=sqrt(2.8)+log(3.5)+56;

     // do something

}

 

이 코드는 루프를 100번 실행하면서 어떤 작업을 하는데 루프 내부에서 j에 복잡한 연산 결과를 대입하고 있다. j값을 계산하는 식이 조금 복잡하지만 제어 변수 i값을 참조하지 않기 때문에 i 루프가 실행되는동안 j의 값은 상수나 마찬가지이며 절대로 변경되지 않는다. 루프 실행중에는 상수이므로 이 값을 매 루프마다 다시 계산하는 것은 시간 낭비이다. 그래서 제대로 된 컴파일러는 이 루프를 다음과 같이 수정하여 컴파일한다.

 

j=sqrt(2.8)+log(3.5)+56;

for (i=0;i<100;i++) {

     // do something

}

 

j의 값을 계산하는 식을 루프 이전으로 옮겨서 미리 계산해 놓고 루프 내부에서는 j값을 사용하기만 했다. 어차피 루프 내부에서 j값이 바뀌는 것이 아니므로 이렇게 코드를 수정해도 원래 코드와 완전히 동일한 동작을 할 것이다. 똑똑한 컴파일러는 프로그래머가 코드를 대충 짜 놓아도 속도를 높이기 위해 자동으로 최적화를 하는 기능을 가지고 있으며 이런 암묵적인 최적화 기능에 의해 프로그램의 성능이 향상된다.

그렇다면 위 두 코드가 정말로 완전히 동일할까 의심을 가져 보자. j는 분명히 루프 내부에서 상수이므로 미리 계산해 놓아도 아무 문제가 없음이 확실하다. 그러나 아주 특수한 경우 최적화된 코드가 원래 코드와 다른 동작을 할 경우가 있다. 어떤 경우인가 하면 프로그램이 아닌 외부에서 j의 값을 변경할 때이다.

도스 환경에서는 인터럽트라는 것이 있고 유닉스 환경에서는 데몬, 윈도우즈 환경에서는 서비스 등의 백그라운드 프로세스가 항상 실행된다. 이런 백그라운드 프로세스가 메모리의 어떤 상황이나 전역변수를 변경할 수 있으며 같은 프로세스 내에서도 스레드가 여러 개라면 다른 스레드가 j의 값을 언제든지 변경할 가능성이 있다. 또한 하드웨어에 의해 전역 환경이 바뀔 수도 있다.

예를 들어 위 코드를 실행하는 프로세스가 두 개의 스레드를 가지고 있고 다른 스레드에서 어떤 조건에 의해 전역변수 j값(또는 j에 영향을 미치는 다른 값)을 갑자기 바꿀 수도 있다고 하자. 이런 경우 루프 내부에서 매번 j값을 다시 계산하는 것과 루프에 들어가기 전에 미리 계산해 놓는 것이 다른 결과를 가져올 수 있다. i루프가 50회째 실행중에 다른 스레드가 j를 바꾸어 버릴 수도 있는 것이다.

이런 경우에 쓰는 것이 바로 volatile이다. 이 키워드를 변수 선언문 앞에 붙이면 컴파일러는 이 변수에 대해서는 어떠한 최적화 처리도 하지 않는다. 컴파일러가 보기에 코드가 비효율적이건 어쨌건 개발자가 작성한 코드 그대로 컴파일한다. 즉 volatile 키워드는 "잘난척 하지 말고 시키는 대로 해"라는 뜻이다. 어떤 변수를 다른 프로세스나 스레드가 바꿀 수도 있다는 것을 컴파일러는 알 수 없기 때문에 전역 환경을 참조하는 변수에 대해서는 개발자가 volatile 선언을 해야 한다. 위 코드에서 j 선언문 앞에 volatile만 붙이면 문제가 해결된다.

 

volatile double j;

 

이 키워드가 반드시 필요한 상황에 대한 예제를 만들어 보이는 것은 굉장히 어렵다. 왜냐하면 외부에서 값을 바꿀 가능성이 있는 변수에 대해서만 이 키워드가 필요한데 그런 예제는 보통 크기가 아니기 때문이다. 잘 사용되지 않는 키워드이므로 여기서는 개념만 익혀 두도록 하자.

Posted by 머리
Study - Programming/C/C++2007. 8. 29. 01:31

#include <stdio.h>

int main(void)
{
 int line;
 char star[50] ="";
 int i = 0;

 printf("Line : ");
 scanf("%d",&line);

 for(i = 0 ; i < line; i++)
 {
  star[i] = '*';
  printf("%s\n",star);
 }
 return 0;
}

Posted by 머리
Study - Programming/C/C++2007. 8. 29. 01:23
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 int i;
 switch (iMessage)
 {
 case WM_CREATE:
  SetTimer(hWnd,1,50,NULL);
  return 0;
 case WM_TIMER:
  hdc = GetDC(hWnd);
  for(i = 0 ;i <1000; i++)
  {
   SetPixel(hdc,rand()%500,rand()%400,RGB(rand()%256,rand()%256,rand()%256));
  }
  return 0;
 case WM_LBUTTONDOWN:
  hdc = GetDC(hWnd);
  Ellipse(hdc,LOWORD(lParam)-10,HIWORD(lParam)-10,LOWORD(lParam)+10,HIWORD(lParam)+10);
  ReleaseDC(hWnd,hdc);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  EndPaint(hWnd,&ps);
  return 0;
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 }
 return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
Posted by 머리