20140402 (main 인자전달, stream)

32일차

 

 

---------------------------

main 함 수 로   인 자 전 달

---------------------------

 

- int main( int iNum, char * Cmd[] )

main함수 인자에 위의 인자 처럼 넣어주면

iNum에는 받은 명령어 갯수,

Cmd에는 그 명령어들이 각각 저장되어 있다.

 

ex) gcc -o main main.c

iNum 에는 4,

Cmd[0] : gcc

Cmd[1] : -o

Cmd[2] : main

Cmd[3] : main.c

이렇게 저장됨.

 

인자의 이름은 프로그래머 재량이지만 보통

int main(int argc, char * argv[])

로 많이 쓴다.    argc ( ARGument Count )  argv ( ARGument Vector )

 

 

 

-------------------------

이중 포인터와 2차원 배열

-------------------------

- 이전에 한 번 했었는데 헷갈려서 다시 한 번 언급한다.

void test ( int ** ptr )

{ A }

int main()

{

    int arr[5][3];

    test( arr );

....

위의 소스처럼 썼었는데 warning!

이유는

char ** 와 char [][] 참조수준이 다름.

서로 데이터 타입이 달라서 그랬다.

2차배열은 이중포인터와 같은 것인지 착각했었다.

그래서 고치면

void test( int (* ptr)[3] ) { A }      or      void test( int ptr[][3] ) { A }

둘 다 동일한 선언이고 '배열 포인터'이다.

- int * whoA [4]    // 포인터 배열

- int (* whoA)[4]   // 배열을 가리키는 포인터

 

 

 

------------------

Stream 흐름

------------------

- ' >' Redirection. 출력 방향을 바꾼다.

- 표준입력 (키보드) : stdin, 0

- 표준출력 (모니터) : stdout, 1

- 표준에러 (모니터) : stderr, 2

ms-dos, linux에서는 0, 1, 2로 스트림으로 쓴다.

ex)

dir > a.txt              dir 내용을 a.txt에 넣음

dir 1> a.txt            dir 내용을 a.txt에 넣음

dir 2> a.txt            dir 에러 내용을 a.txt에 넣음

 

 

- ' >> ' 이것도 redirection인데 ' > ' 와 다른 점은

> : 새로 쓰기

>> : 추가로 쓰기

 

 

- fprintf( Stream, format, ...);

printf 함수와 다르게 stream을 정해서 출력할 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

설정

트랙백

댓글

20140401 (함수 포인터, void 포인터)

32일차

 

 

------------------------

함    수    포    인    터

------------------------

- 함수의 주소값을 저장하는 포인터.

먼저 이 포인터를 선언하기 위해서는 Data Type을 알아야한다.

Data Type은 Prototype(함수원형)에서 이름 부분만 (*)로 바꾸면 된다.

ex)

int main()                                main함수의 Data Type은

{ 명령어들 }                                   int (*)()  이다

void test()                               test함수의 Data Type은

{ 명령어들 }                                  void (*)()  이다

int printf(const char *, ... )        printf함수의 Data Type은

                                                   int (*)(const char *, ...)  이다

 

 

- 함수 포인터 선언 및 사용

#include <stdio.h>

void test()
{
  int (*fp)(const char *, ...) = printf;

  (*fp)("hello \n");  //  C++에서는 괄호를 넣지않으면 오류라고 한다.

  fp("hello \n");  //  C에서는 위와 밑에 둘 다 가능.

  
  return ;
}

int main()
{
  void (*fp)();
  
  fp = test;

  fp();

  return 0;
}

위와 같은 방법으로 사용한다.

 

 

 

 

-------------------------

void  형    포  인  터

-------------------------

- Data Type이 void * 형이다.

타입을 안가리고 그 주소값을 warning 없이 다 받을 수 있다.

그러나 값을 가리키는 *를 붙이면 자료형이 얼만큼 인지 모르니

사용할 수 없다.

캐스팅을 하면 사용가능.

ex)

#include <stdio.h>

int main()
{
  void *  vp;
  int  iNum = 500;
  char  cNum = 100;

  vp = &cNum;
  *((char *)vp) = 99;

  vp = &iNum;
  *((int *)vp) = 400;

  printf("%d \n", cNum);
  printf("%d \n", *((int *)vp) );
  printf("%d \n", iNum);  

  return 0;
}

위에 *((char *)vp) 식으로 char * 형이라고 캐스팅을 해서 사용.

 

 

 

아래 소스는 HexaView 코드인데

void * 가 사용되는 예를 보자.

#include <stdio.h>

void HexaView(void * vpData);

int main()
{
  int  iNum = 0x12345678;

  HexaView(&iNum);

  return 0;
}

void HexaView(void * vpData)
{  
  int iCnt;
  int iCnt2;
  
  printf("===============================================================================\n");
  printf("= ADDRESS                         HEXA                             ASCII      =\n");
  printf("=-----------------------------------------------------------------------------=\n");
  
  for(iCnt2=020>iCnt2; ++iCnt2)
  {

    //----------------------------//
    //---      Address Part Start      ---//

    printf("= %08X  "vpData);

    //---      Address Part End       ---//
    //----------------------------//
  


    //---    Hexa View Part Start    ---//

    for(iCnt=016>iCnt; ++iCnt)
    {
      if(7 == iCnt)
      {
        printf("%02X  "(*((unsigned char *)vpData)) );
      }
      else
      {
        printf("%02X "(*((unsigned char *)vpData)) );
      }
      vpData = ((unsigned char *)vpData) + 1;
    }
    //---    Hexa View Part End    ----//
    //----------------------------//



    //----------------------------//
    //---        ASCII Part Start       ---//

    vpData = ((unsigned char *)vpData) - iCnt;
    for(iCnt=016>iCnt; ++iCnt)
    {
      if(0x20 <= (*((unsigned char *)vpData)) && 0x80 > (*((unsigned char *)vpData)))
      {
        printf("%c"(*((unsigned char *)vpData)));
      }
      else
      {
        printf(".");
      }
      vpData = ((unsigned char *)vpData) + 1;
    }
    //---        ASCII Part End        ---//
    //----------------------------//
    printf(=\n");
  }  
  printf("===============================================================================\n");

  return ;
}

위에 연한 빨강색 바탕으로 강조된 곳들이

void *를 사용한 곳들이다.

main 함수에서 HexaView 함수를 호출 할 때에

void *를 사용하지 않았다면

HexaView( (unsigned char *)&iNum );

이런식으로 함수를 호출할 때마다 캐스팅을 해줘야 하기때문에

편의성의 위해서 작성할 때 좀 더 코드를 길게 적어주면 좋다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

설정

트랙백

댓글

20140331 (2차원 배열, 이중포인터, 배열포인터)

31일차

 

 

-------------------------

2차원 배열 메모리 구조

-------------------------

-

char Arr[3][3];

int * ip = &Arr[0][0];

2차원 배열이 실제 메모리에서는

 

이런 식으로 저장되어 있다.

그래서 아래와 같이 모두 같은 값을 가리킨다.

ip[3] == Arr[0][3] == Arr[1][0]

 

 

 

- 줄 이동 (주소값)

Arr + 0    =    &Arr[0] + 0    =    &Arr[0]

Arr + 1    =    &Arr[0] + 1    =    &Arr[1]

Arr + 2    =    &Arr[0] + 2    =    &Arr[2]

 

- 칸 이동 (주소값)

&Arr[0][0]    =    Arr[0] + 0    =    *(Arr + 0) + 0    =    *( &Arr[0] + 0 ) + 0

&Arr[0][1]    =    Arr[0] + 1    =    *(Arr + 0) + 1    =    *( &Arr[0] + 0 ) + 1

&Arr[0][2]    =    Arr[0] + 2    =    *(Arr + 0) + 2    =    *( &Arr[0] + 0 ) + 2

 

- 칸 이동 (값)

Arr[0][0]    =    *(Arr[0] + 0)    =    *( *(Arr + 0) + 0 )    =    *( *( &Arr[0] + 0 ) + 0 )

Arr[0][1]    =    *(Arr[0] + 1)    =    *( *(Arr + 0) + 1 )    =    *( *( &Arr[0] + 0 ) + 1 )

Arr[0][2]    =    *(Arr[0] + 2)    =    *( *(Arr + 0) + 2 )    =    *( *( &Arr[0] + 0 ) + 2 )

 

 

 

-----------------------

---배열에서 []숫자 생략

배열에서 []안에 숫자 생략이 가능한데 맨 왼쪽에 있는 숫자 하나만 가능하다.

다만 초기화시에만 가능.

int iaArr[ ] = {1, 2, 4, 5};

int iaArr[ ][2] = {  {1, 2}, {3, 4}  };

int iaArr[ ][2][2] = {  { {1, 2}, {3, 4} }, { {1, 2}, {3, 4} }  };

 

 

------------------

---포인터의 포인터

 

int iNum = 3;                                      iNum -> 3

                                                     &iNum -> iNum주소

int * ip = &iNum;                                     ip -> iNum주소

                                                         &ip -> ip주소

                                                          *ip -> 3

int ** ipp = &ip;                                    ipp -> ip주소

                                                        &ipp -> ipp주소

                                                        *ipp -> iNum주소

                                                       **ipp -> 3

 

 

--------------------------

---배열 포인터, 포인터 배열

int arr[3][4];                   //  배열

int * ptr2[4];                    // 포인터 배열 , 이 변수 크기 16byte

int (*ptr)[4];                    // 배열 포인터 (16byte씩 건너뛰는 포인터) , 이 변수 크기 4byte

 

int (* ptr)[4];    // 포인터방식 선언

int ptr[][4];      // 배열방식 선언

둘 다 4byte 크기의 포인터로 연산시 16byte씩 이동하는 같은 뜻이다.

 

ex) 예제 소스

#include <stdio.h>

void ShowArr2DStyle(int (*arr)[4]int column)
{
  int  i;
  int  j;

  for(i = 0; column > i; ++i)
  {
    for(j = 04 > j; ++j)
    {
      printf("%d "arr[i][j] );
    }
    printf("\n");
  }
  printf("\n");
  printf("arr : %d \n"sizeof(arr) );
}

int Sum2DArr(int arr[][4]int column)
{
  int  i;
  int  j;
  int  sum = 0;

  for(i = 0; column > i; ++i)
  {
    for(j = 04 > j; ++j)
    {
      sum = sum + arr[i][j];
    }
  }

  printf("arr : %d \n"sizeof(arr) );

  return sum;
}

int main()
{
  int  arr1[2][4= {1,2,3,4,5,6,7,8};
  int  arr2[3][4= {1,1,1,1,3,3,3,3,5,5,5,5};

  ShowArr2DStyle(arr1, sizeof(arr1)/sizeof(arr1[0]) );
  ShowArr2DStyle(arr2, sizeof(arr2)/sizeof(arr2[0]) );

  printf("arr1의 합 : %d \n", Sum2DArr(arr1, sizeof(arr1)/sizeof(arr1[0]) ) );
  printf("arr2의 합 : %d \n", Sum2DArr(arr2, sizeof(arr2)/sizeof(arr2[0]) ) );

  return 0;
}

위의 예제처럼 이 차원 배열로도 사용할 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

설정

트랙백

댓글