C를 공부하다 중간고지인 포인터를 익히기 되면 void형 포인터라는 복병을 만나게 된다.

void *vp;    //대상체의 타입을 명시하지 않는 특별한 포인터형 이다.


  1. 임의의 대상체를 가리킬 수 있다.
    1. 대상체가 정해져 있지 않다는 말은 어떠한 대상체도 가리키지 못한다는 뜻이 아니라 임의의 대상체를 가리킬 수 있다는 얘기와도 같다. 선언할 때 대상체의 타입을 명시하는 일반적인 포인터는 지정한 타입의 대상체만 가리킬 수 있지만 void형 포인터는 어떠한 대상체라도 가리킬 수 잇다.
      void형 포인터는 임의의 포인터를 대입 받을 수 있지만 반대로 임의의 포인터에 void형 포인터를 대입 할 때는 반드시 캐스팅을 해야 한다.
      pi = (int* )vp;    //int*pi
      pd=(double*)vp;    //double* pd

  2. *연산자를 쓸 수 없다.
    1. void형 포인터는 임의의 대상체에 대해 번지값 만을 저장하며 이 위치에 어떤 값이 들어 있는지는 알지 못한다. 따라서 *연산자로 이 포인터가 가리키는 메모리의 값을 읽을 수 없다. 대상체의 타입이 정해져 있지 않으므로 포인터가 가리키는 위치에서 몇 바이트를 읽어야 할지, 또 읽어낸 비트를 어떤 식으로 해석해야 할지를 모르기 때문이다. 만약 vp번지에 저장된 값이 정수형이라는 것을 확실히 알고 읽고 싶다면,

      *(int *)vp;        
      //vp를 잠시 정수형 포인터로 바꾼 후 번지의 정수값을 읽는다.

  3. 증감연산자를 쓸 수 없다.
    1. 대상체의 타입이 정해져 있지 않으므로 증감 연산자도 곧바로 사용할 수 없다.

      vp=(int *)vp + 1;    
      //vp를 잠시 int*로 캐스팅한 후 1을 더하면 4바이트를 더한다.

void형 포인터의 특징에 대해 간단하게 요약해 보면 대상체가 정해져 있지 않으므로 임의의 번지를 저장할 수 있지만 *연산자로 값을 읽거나 증감연산자로 이동할 때는 반드시 캐스트 연산자가 필요하다. 순수하게 메모리의 한 지점을 가리키는 기능만 가지는 포인터 이기 때문이다.

참고 : 이중포인터(winapi)

Tag |

3.23(금) clock() 함수 응용 사례.

from Study/C언어 2007/03/23 16:12 view 22350

#include <Turboc.h>

//typedef long clock_t;
//#define CLOCKS_PER_SEC 1000

void
main()
{
    clock_t t1,t2;
    int count=0;

    t1=clock();

    for (;;) {

        printf("기다리십시오. %d\n",count++);

        t2=clock();

        if (t2-t1 > 3*CLOCKS_PER_SEC) {

            break;
        }
    }

    printf("끝났습니다.\n");
}

3초간 어떤 작업을 반복적으로 수행 하고 싶을 때 쓸 수 있는 코드 이다.

시작시간과 현재 진행된 시간차가 3*1000,즉 3초일 때 루프벗어 난다. Delay는 기다리는 동안

다른 일을 할 수 없지만 일정 시간동안 어떤 작업을 하고 싶다면 clock 함수로 구한 시간을 이용하여

두 시간값의 차(t2 – t1)을 구해준다.

Tag |

#include <TurboC.h>
#include <math.h>

void
main()
{
    int i;
    time_t t1,t2;

    time(&t1);
    for( i = 0; i < 100000 ; i++)
        printf("결과= %f\n", sin(i*3.1416/180)*(i*3.1416/180));
    time(&t2);
    printf("%.2f초가걸렸습니다.", difftime(t2,t1));
 
}

Time함수와 difftime함수를 통해서 돌려봤더니 속도 차이가 엄청나다.. 이게 바로 CPU의 성능 차이인가..

서브컴(노트북) IBM X20 CPU – 600, RAM – 384M 대략 87초 OTL  

메인컴(데스크탑) 듀얼코어 CPU - E6600, RAM – 2G 환상(?)적인 5초 ^^\

사용자 삽입 이미지사용자 삽입 이미지 CEXAM.exe

속도측정 실행파일

Tag |

이차원배열과 포인터 익히기

from Study/C언어 2007/03/22 17:06 view 23833

포인터는 C의 중간 고비쯤 된다. 이 능선만 잘 넘기면 C언어의 활용도가 한 200프로(?) 향상 되고 이해가 되지

않았던 부분들도 조금씩 풀려나가는 걸 알 수 있었다. 그러나 2차원 배열은 왠지 복잡한 부분이 있다.

포인터배열, 배열포인터, 2차원배열을 포인터로 주소 넘기기 이러한 것들이 나를 혼란스럽게 한다.

책을 읽어보니 이해가 팍팍 되었다. 그럼 책에 내용을 정리해본다.

    int imsi[3];

    int *imsip;

    imsip = imsi;

1차원 배열에서 배열과 포인터를 연결시키기 위한 간단한 대입 이다. 그렇다면 2차원 배열은 어떻게 하는걸까?

순간 **imsip 가 떠올라서 써본다면 "꽝" 이다. **imsip는 *ptr 의 주소값인 &ptr을 받는 변수이지 이차원
 
배열의 주소값을 받지 못한다.

*imsip2[3]; 과 (*imsip)[3]; 의 차이를 정확히 알고 있어야 함수로 주소값을 넘겨주는 작업을 할 때 고생을 줄일
 
수 있다. 이 둘의 차이는 과연 무엇일까?

imsi[0][0]

3

imsi[0][1]

5

imsi[1][0]

12

imsi[1][1]

54

imsi[2][0]

534

imsi[2][1]

923

   

imsip

 

 

temp[0]

 

temp[1]

 
   

    int imsi[3][2] = { {3,5} , {12,54}, {534,923} };

    int (*imsip)[2];

    int *temp[2];
 
 imsi[3][2]의 정의에 의해서 메모리는 24바이트가 1차원적으로 할당된다.

 (*imsip)[2]에 의하여 변수가 하나 할당된다. 이 변수의 이름은 imsip가 되고 2차원배열을 가리킬 수 있는
 
2차원 배열포인터 변수이다.

  *temp[2]는 포인터 변수가 두 개가 생성되고 메모리에도 당연히 두 변수에 대한 할당이 이루어 진다. 주소를

저장할 수 있는 공간이 두 개 생성 된다는 것이다.

쉽게 이야기하면 temp라는 것은 포인터를 저장 할 수 있는 영역이 두개 있는 것이다. 포인터변수가 2개 생기는 게

키포인트!!
이 정도면 포인터배열과 배열포인터의 차이를 어느 정도 이해할 듯 싶다. 특히 이것와 같이 꼭 알아야
 
할 것이 있는데 배열이 가리키는 주소의 범위이다. 이걸 모르고서는 포인터를 안다고 하면 안될 것이다.

imsip = imsi;         2차원배열포인터에 2차원배열의 주소를 대입 하고 있다.

imsip = &imsi[0][0];    2차원배열포인터에 1차원배열의 주소를 대입하고 있다.

temp[0] = imsi;        포인터변수에 2차원배열의 주소를 대입하고 있다.

temp[0] = imsi[0];    포인터변수에 1차원배열의 주소를 대입하고 있다.

2, 3번째는 틀린 문법이다. 위에 설명한 것과 같이 배열이 가리키는 주소의 범위에 따라서 포인터에 대입하느냐

못하는냐가 결정 된다는 것을 꼭 명심하자!

MSWORD로 포스팅 하기

from Info/Tools 2007/03/22 08:43 view 19767

WORD2007에서 블로그 게시라는 유용한 기능이 생겼다. 굳이 워드로 작업할 필요가 있을까

라고 생각했지만 이게 또 여간 좋은 게 아니다. 특히 그림추가 하고 싶을 때 웹에서 할 때는

일일이 업로드하고 링크해주고 하는 귀찮은 면이 있었는데 요곤 그냥 붙여넣고 업로드하면

자동으로 링크 를 해준다. 귀치니즘에 사로잡힌 나에게는 이보다 더 좋은 기능이 있을까

싶다.

표기능

테두리기능

표스타일기능

내사랑 태희

-_-..

 그림업로드

정품 소프트웨어 Maxivista

from 잡담 2007/03/21 16:42 view 21853
 게임 CD외에 정품소프트웨어를 산적이 있었던가 .. 아마 없는것 같다. 헌데 Maxivista 라는 프로그램은

질러라 라는 마음을 가지게 해준 소프트웨어 였다. 노트북을 모니터로 쓰고 싶은 욕망이 얼마나 컸으면

보자마자 이 소프트웨어를 구매하게 된 것이다. 헌데 최근에 이사이트 접속도 안되고 프로그램도 자주

끊기는 감이 있어서 좀 짜증나던 차에 구글에서 3분정도 뒤지니 크랙키가 나돌아 다니고 있었다.

 -_-...39달러에 구매한 시디키였는데 크랙키가 있었다니 이게 바로 정품사용자의 허탈함? 인 걸까..

크랙키 한번 실험해봤더니 매~~우 잘 돌아가고.. 쩝. 그래도 간만에 패치에 자유롭다는게 기분이 좋쿤..

ps.크랙해도 1~2주쯤 지나면  패킷검사해서 정품인증 한다는거~!

[Flash] http://www.maxivista.com/dual_monitor.swf

3.20(화) 함수의 설계 원칙 정리

from Study/C언어 2007/03/20 18:30 view 22186
함수를 작성하는 문법과 호출하는 방법, 인수를 받아들이고 리턴하는 방법을 익히는 것은 그다지 어렵지 않지만

정말로 함수답게 잘 나누고 디자인하는 것은 무척 어렵고 단기간에 체득되지 않는다. 함수는 프로그램을 구성하는

단위로서 잘 나누어 놓으면 프로그램의 구조가 탄탄해지고 확장하기도 쉽고 재사용성도 좋아진다.

함수디자인은 오로지 많은 분석과 실습만으로 얻어지는 경험이다. 꾸준한 연습만이 해결책이라 할수있다.


함수를 잘 만드는 기본적인 지침

1. 함수의 이름을 최대한 설명적으로 작성하여 이름만으로 무엇을 하는 함수 인지, 이왕이면 어떻게 쓰는 것인지도

알 수 있도록 한다. Score, Draw, Test 라는 이름보다도 GetScore, DrawScreen, TestGameEnd와 같이 기능을

명시해주는게 보기도 좋고 효율적이다. 자바를 이용하여 코딩해 보면 GET,SET 을 주로 함수앞에 써서 값을

얻거나 정해줄때를 명확히 표현해준다.


2. 두번이상 중복된 코드는 반드시 함수로 분리한다. 3번도 아니고 2번인 이유는 해당 동작을 수정해야 할때를

생각해 보면 된다. 만일 2번의 중복된 코드가 있는데 이 코드가 논리적으로 맞지 않다면 수정을 해줘야 할 것이다.

그러나 일일이 찾아가서 두개를 모두 고친다는 보장은 없다.(나같은 놈은...특히) 실수로 한 곳을 고치지 않으면

이것이 바로 버그의 원흉이 된다. 또한 두번 중복되는데 3번은 안되고 그이상은 안되겠는가 .. 미래를 위해서라도..


3. 반복되지 않더라도 한 단위로 볼 수 있는 작업은 함수로 만든다. 설사 이 함수를 딱 한번만 호출하고 다른

곳에서 호출할 확률이 희박하더라도 이렇게 하는 것이 좋다. 코딩을 하다보면 출력을 해야 하는 부분이 있고

입력을 해야 하는 부분이 있을 것이다. main 함수내에서 이를 전부 처리해도 문제는 없다.

하지만 어디가 출력부인지 입력부인지 가독성이게 표시를 할 수 있나가 문제이다. 물론 주석으로 일일히

표시해 줘도 되지만 가독성이 떨어 진다. 함수로 객체와 비스무리하게 나눠 주면 재사용도 좋고 보수하기도 좋고..


4. 함수는 한번에 하나의 작업만 해야 한다. 함수는 프로그램을 구성하는 부품이며 부품이란 전체를 구성하는

원자적인 단위이다. 함수 하나가 출력도 하고 입력도 받는다면 굳이 함수를 쓸 필요가 있을까 고장이 나도

구조가 간단한 부품에서 나야 하지 않을까 .. 함수도 마찬가지라 생각이 든다.


5. 입력과 출력이 직관적이고 명확해야 한다. 인수는 함수에게 주어지는 작업거리인데 함수가 하는 일에

꼭 필요한 정보만 최소한의 인수로 받아들여야 한다.

void CheckStr(char *str, int len);

과 같이 함수에 인수를 넘기고자 했을 때 굳이 문자열의 길이 len을 넘겨주지 않아도 strlen이라는 함수로

문자열의 길이를 판별할 수 있다는 것이다. 불필요한 입력이 생겨버린 셈이다.


6. 함수는 자체적으로 에러 처리를 해야 한다. 파일을 처리한다든지(fopen) 초를 계산한다든지(mktime)

할 때 에러가 발생하면 이들은 -1 , null 을 반환 해준다. 이러한 반환값을 함수내에서 에러 처리를 해줘서

어떤 프로젝트로 가져 가든 별도의 수정없이 재사용 가능한 부품이 되게 해줘야 한다. 만일 에러처리를 모두

메인 함수가 담당한다면 이 또한 함수의 사용의미를 잃어 버리는게 아닐까..
Tag |

선언과 정의는 비슷한 의미 같지만 함수나 변수등에서 사용되면 그 의미는 달라진다.

선언(Declartion) : 컴파일러에게 대상에 대한 정보를 알린다. 함수가 어떤 인수들을 전달받으며

어떤 타입을 리턴하는지를 알리는 원형 선언(프로토타입)이 대표적인 선언이다. 컴파일러에게 정보만 제공하는

것이므로 본체를 가지지 않으며 실제 코드를 생성하지도 않는다. 그래서 다음처럼 여러번 중복되어도 상관없다.

int MAX(int a, int b);
int MAX(int a, int b);

정의(Definition) : 대상에 대한 정보로부터 대상을 만든다. int i; 정의문에 의해 4바이트를 할당하며

int Max(int, int){ } 정의로부터 함수의 본체를 컴파일하여 코드를 생성한다. 정의는 변수의 타입, 함수의
 
인수목록을 컴파일러에게 알려 주기도 하므로 항상 선언을 겸한다.

선언 역할-알린다,     메모리-사용안함,  정보의 완전성-불완전해도 됨,      중복가능석-가능
정의 역할-생성한다,  메모리-할당,        정보의 완전성-항상 완전해야 됨,  중복가능성-불가능


하지만 실제로는 별 구분없이 사용되고 있다. 따라서 이러한 명칭적 정의가 있다는 것만 알고 있자..

#define A 1000     // 보통 디파인한다.정의한다로 하지만 메모리 할당을 받지 않으므로 선언이다.
int i;                   // 인트형을 선언한다 이런 말을 많이 쓰지만 메모리를 잡아 먹으므로 정의이다.
extern int j;        
// 외부 함수(모듈)에 정의된 int형을 선언하는거라고 해야 정확한 표현(?) 이다.

3.20(화) 매크로함수..

from Study/C언어 2007/03/20 15:02 view 21819

프로그램 내에서 자주 사용하는 상수나 반복문을 또 쓰기 싫거나 const상수를 만들고 싶을때

#define 문을 써서 표현 하는것이 좋다.

지금 제일 많이 쓰는 #define MAX 100 이런 문장은 프로그램의 최대값을 변경 하고 싶을 때

용이하게 할 수 있다. 매크로 라는 기능으로도 유용한데 그건 아랫글 참고..

2007/03/20 - [Study/CNX] - 3.20(화) 스피커음 내보기. // 이전글넣기 플러그인 너무 좋다. ^_^

매크로 함수는 함수를 흉내 내서 인수를 받아들이고 매크로 실행 후 계산 결과를 리턴한다.

하지만 이 리턴하는게 말이 리턴이지 문장의 치환에 불과하다.

함수처럼 연산을 실행한 후에 결과값을 반환하는게 아니라는 것이다. (맨날 헷갈려ㅠ_ㅠ.)

#define dubae(i) i+i
#define double(i) i*i
#define VALUE 100
#define VALUE2 VALUE+100

두개의 매크로문으로 정확히 알 수 있는데

-dubae(3); 이라 하면 함수로 착각하여 -6으로 생각이 든다. 하지만 이건 매크로다. 단순히 문장내에

정의한 매크로를 치환해주는 역할
만 해준다. 즉, -i+i; 라는 문장이 생기는 것이다.

double(3+3); 도 마찬가지로 6을 더한 후에 6*6이 될 거라고 생각하지만 아니다.

3+3 * 3+3 ; 으로 먼저 치환이 된다. 매크로문인 double을 먼저 치환해주고 연산을 해나가는 것이다.

전처리문을 보면 VALUE2가 200이라고 생각을 해버린다. 나 같은 사람은 이 순간 VALUE2는 200이라고

철썩 믿어버린다. 그럼 고정관념이 생겨서 오류가 나도 어디가 난지 죽어다 깨어나도 알지 못한다.

VALUE2*2+100 이런식으로 계산하면 500 하고 넘어가버리면 바로 버그가 탄생되는 것이다.

분명히 알아야 될 것은 매크로는 그저 문장내에 매크로에서 정의한 문장을 옮겨주는 역할만 한다.

그러므로 이 문장은 VALUE+100*2로 해석해야 정답이다. 결과값300이라는 값이 나오게 되는 것이다.

이를 방지하기 위해서 무조건 ( ) 로 묶어주는게 상책이다. -_-... 매크로로 들어간 문장이 최우선으로 계산하게

만들어 버려서 예상치 못한 실수를 원천방지 해버리자!!!

Tag |

3.20(화) 스피커음 내보기.

from Study/C언어 2007/03/20 14:00 view 21692

  왠지 예전 도스게임이 모락모락 떠오르는 음이다.. 띠~~ 띠..

#define BEEP(fre, time) Beep( (DWORD)(131*pow(1.06, fre)), (400*time));

Beep 함수를 매크로로 만들어 봤는데 -_-..  어설프네..

Beep(주파수 발생 , 발생시간) 으로 구성되어있는데 DWORD형으로 해줘야 경고 안먹는다...

131*pow(1.06, x) 이부분은 음계에 근접한 음이라고 한다. 도(0),레(2),미(4),파(5)....

Tag |