'배열'에 해당되는 글 3건

Programming/C C++
배열은 아래와 같은 형식으로 작성됩니다.
데이터형 배열명[배열길이];
예를 들어 int형 변수 5개를 선언한다고 하면
int intarry[5];
위와 같이 하면 됩니다. 이렇게 배열을 선언하면 메모리상에 int에 해당하는 4byte공간이 연속적으로 할당되며 배열의 이름인 intarray는 메모리상에 할당된 공간의 시작주소를 갖게됩니다.

배열의 시작은 0부터 시작하므로 위의 배열은 0~4까지 5개의 배열을 가지게 되며 각각의 개별적인 배열에는 다음과 같은 방법으로 인덱스를 부여하면 됩니다.
intarray[0] = 10;
intarray[1] = 20;
배열은 선언과 초기화를 따로 하지 않고도 배열을 선언할때 {}를 사용하여 선언과 동시에 초기화할 수 있습니다.
int intarray[5] = {10, 20, 30, 40, 50};
지금까지의 배열은 1차원 배열입니다. 만일 이 배열을 2차원이나 3차원등의 배열로 만들고자 한다면 []를 사용하여 원하는 차원의 수만큼 연속적으로 지정해 주면 됩니다.
int intarry[5][3]; //2차원
int intarry[5][3][2]; //3차원
다차원 배열에 대한 접근은 1차원 배열과 같습니다. 예를 들어 위 2차원 배열의 경우
intarry[0][0] = 10;
intarry[0][1] = 10;
intarry[0][2] = 10;

intarry[1][0] = 20;
intarry[1][1] = 20;
intarry[1][2] = 20;

intarry[2][0] = 30;
intarry[2][1] = 30;
intarry[2][2] = 30;

intarry[3][0] = 40;
intarry[3][1] = 40;
intarry[3][2] = 40;

intarry[4][0] = 50;
intarry[4][1] = 50;
intarry[4][2] = 50;
이와 같은 배열의 접근이 가능합니다.

배열은 C언어 세계에서 문자열을 표현하는데 많이 사용되는 방법입니다. 문자열을 초기화 할때는 {}가 아닌(물론 가능하긴 합니다만) 아래와 간단한 방법을 주로 이용합니다.

char s[6] = "cliel";
문자열을 이루는 문자는 5자인데 배열을 6으로 한 이유는 문자열의 끝을 구분하는 특수문자인 \0 문자도 같이 할당되어야 하기 때문입니다.
 
이 방법은 일반적인 배열을 초기화 할때보다 간편하긴 하지만 문자열길이+\0 에 대한 값을 배열의 길이값으로 지정해야 한다는 불편함이 있으므로 C++에서는 다음과 같이 문자열을 초기화 하는 방법도 허용합니다.
char* s = "cliel";
포인터를 사용하는 경우에는 우선 cliel 문자열을 배열로서 메모리에 할당한 다음 첫번째 요소에 대한 주소값을 포인터 변수 s에 대입하는 방법으로 문자열을 다루게 됩니다.

포인터변수도 배열로서 다룰 수 있는데 다음은 그 방법을 보여주고 있습니다.
char* ss[3];

ss[0] = "aaaaa";
ss[1] = "bbbbb";
ss[2] = "ccccc";

for (int i = 0; i < 3; i++) {
   cout << ss[i] << endl;
}
포인터를 사용하는것은 문자열이나 정수와 같은 일반적인 데이터형도 가능합니다.
int i[3];

i[0] = 1;
i[1] = 2;
i[2] = 3;

int* ii[3] = { &i[0], &i[1], &i[2] };

for (int i = 0; i < 3; i++) {
   cout << "address : i[" << i << "] - " << &ii[i] << endl;
   cout << "value : i[" << i << "] - " << *ii[i] << endl;
}

'Programming > C C++' 카테고리의 다른 글

[Visual C++] 업/다운 캐스팅  (0) 2012.10.17
[Visual C++] 프렌드 클래스  (0) 2012.10.16
[Visual C++] 배열  (3) 2012.10.10
[Visual C++] 복사생성자  (0) 2012.10.09
[Visual C++] 클래스(Class) 의 기본  (5) 2012.10.08
[Visual C++] 연산자 오버로딩(Operator Overloading)  (0) 2012.10.05
3 0
Programming/C C++
1. 기본작성법

#include <stdio.h>

main()
{
  printf("main 함수\n");
 
  prnt();
}
prnt()
{
  printf("prnt 함수\n");
}


prnt함수를 작성하고 main에서 prnt함수를 호출합니다.


2. 함수의 Data전달 인수설정

(1) 단일인수

#include <stdio.h>

main()
{
  int a;
  int b;
 
  a = 100;
  b = 200;
 
  prnt(a, b);
}
prnt(int a, int b)
{
  printf("결과 %d\n", a + b);
}


'함수명(데이터형 변수, 데이터형 변수...)' 형식으로 함수를 작성하면 값을 받을 수 있는 함수가 됩니다. 예제에서는 prnt(int a, int b)라고 하였으므로 integer형 값 2개를 인수로 받을 수 있으며 함수내부에서는 인수값 2개를 합하여 그 결과를 표시하도록 하였습니다.(main함수에도 a와 b라는 변수가 있으며 prnt함수에도 a와 b라는 변수가 있는데 각각의 함수안에서 쓰인 변수명은 서로 같다 하더라도 충돌하지 않습니다.)

참고:
호출되는 함수의 입장에서는 어떤 값이 인수로 전달될지 모르기 때문에 이 인수를 가르켜 가인수라고 하며 함수를 호출하는 입장에서는 어떤 값을 줄지 명확하므로 실인수라고 합니다.


(2)배열인수

#include <stdio.h>

main()
{
  char s[6] = "hello";
 
  prnt(s);
}
prnt(char ss[])
{
  printf("%s 라고 인사하다.\n", ss);
}


prnt에 단일값이 아닌 배열(문자배열)로 인수값을 건네주고 있습니다. 배열의 경우에는 함수를 호출하는 쪽도, 호출되는 실제 함수쪽도 배열 길이가 100이나 1000, 2000정도 되었을때 a[1], a[2], a[3].... 처럼 일일이 건네주려고 하면 매무 어려울 것입니다.
따라서 배열의 경우에는 배열값 자체가 아니라 배열의 첫 주소값만 전달하는 방법을 사용하고 있습니다.

main에서 prnt함수를 호출할때 배열이름인 s만 인수로 건네주고 있습니다. s[6]처럼 배열의 요소를 지정하지 않았는데 왜냐하면 s라고 하는 녀석이 배열이 시작되는 첫 주소를 가지고 있기 때문입니다. 즉, 함수끼리 배열을 인수로 건네줄때는 배열의 시작주소만으로 전달하면 되는 것입니다.

prnt함수에서는 '데이터형 이름[]'의 형태로 인수를 지정하여 배열값(실제는 배열의 첫 주소값)을 받도록 합니다. 이처럼 함수를 작성할때 배열을 인수로 하는 경우에는 얼마만큼의 배열을 받을지 알 수 없기 때문에 char ss[10]처럼 하는 경우는 거의 없습니다. 오로지 배열이 시작되는 첫 주소값만을 인수로 가지기 때문입니다.

정리하자면 배열값을 함수끼리 인수로 건네주고 받을때는 '배열값 자체가 아니라 배열의 시작주소만을 전달한다.' 라는 것을 기억해 두시기 바랍니다.


(3) 주소값 인수

#include <stdio.h>

main()
{
  int a, b, c;
 
  a = 200;
  b = 200;
 
  c = prnt(&a, &b);
 
  printf("결과 %d\n", c);
}

int prnt(int *a, int *b)
{
  return (*a + *b);
}


함수로 인수를 전달할때는 값자체가 아닌 주소값을 전달 할 수도 있습니다. 주소라는 것은 현재 변수값이 아니라 Memory의 어떤 부분에 저장되어 있는가를 의미하는 Memory의 주소값을 전달하는 것입니다.

변수의 주소값은 '&변수명'형식으로 나타낼 수 있으며 함수가 주소값을 인수로 전달받을 경우에는 '*인수명'으로 지정해 인수를 받아오도록 처리합니다.


그럼 값을 전달하는 것과 주소값을 전달하는것은 무슨 차이가 있을까요? 함수의 인수로 값을 전달하는 경우는 해당 값이 복사되어 인수로 전달되는 것입니다.

#include <stdio.h>

main()
{
  int a, b, c;
 
  a = 200;
  b = 200;
 
  c = prnt(a, b);
 
  printf("결과 %d\n", c);
}

int prnt(int a, int b)
{
  return (a + b);
}


이와 같이 값을 전달하도록 하는 경우 main함수의 변수 a와 b에 있는 각각 200이라는 정수값을 prnt함수의 a와 b인수에 전달하게 되므로 main함수 a와 b에도 200, prnt함수 a와 b에도 200이라는 똑같은 값을 가지게 되는 것입니다.

따라서 만일 prnt함수에서 인수값 a와 b의 값을 바꾸게 되는 경우가 생겨도 main함수의 a와 b에는 영향을 주지 않습니다. 값이 복사되는 형태로 전달되기 때문에 완전히 별개의 변수로 Data를 가지고 있기 때문입니다.


하지만 값이 아닌 주소를 인수로 건네주는 경우에는 해당 주소가 건네진 변수값을 바꾸게 될때 이 주소를 참조로 하고 있는 다른 부분에 대해서도 영향을 받게 됩니다.

#include <stdio.h>

main()
{
  int a, b, c;
 
  a = 200;
  b = 200;
 
  printf("main함수의 a값은 %d\n", a);
  printf("main함수의 b값은 %d\n", b);
 
  prnt(&a, &b);
 
  printf("main함수의 a값은 %d\n", a);
  printf("main함수의 b값은 %d\n", b);
}

int prnt(int *a, int *b)
{
  *a = *a + 20;
  *b = *b + 20;
 
  return;
}


main에서 변수 a가 저장된 Memory번지를 1000번지 변수 b가 저장된 Memory번지를 2000번지라고 가정했을때 prnt함수를 호출하여 주소값을 전달하면 각 변수의 값인 200을 보내는 것이 아니라 a와 b의 주소인 1000번지와 2000번지를 인수로 보내게 됩니다.

prnt함수에서는 *a = *a + 20와 *b = *b + 20;을 통해 1000번지의 Memory주소에 있는 값과 2000번지의 Memory주소에 있는 값을 바꾸게 되면 결국 maint함수에서는 바뀌어진 값을 표시하게 되는 것입니다.


3. 값의 반환

#include <stdio.h>

main()
{
  int a, b, c;
 
  a = 100;
  b = 200;
 
  c = prnt(a, b);
 
  printf("결과 %d\n", c);
}

int prnt(int a, int b)
{
  int c;
 
  c = (a + b);
 
  return c;
}


prnt함수에서 두개의 정수형 Data를 인수로 받아 그 인수를 더한 후 결과값을 다시 호출한 main()으로 반환하고 있습니다. 값을 반환하는 함수의 경우는 함수명 앞에 값을 반환하는 Data형을 지정하고 함수내부에서 return을 통해 Data형에 맞는 값을 반환하도록 합니다.


이때 함수에서 주소값을 반환하려면 함수명 앞에 주소를 나타내는 *문자를 붙이고 값이 아닌 주소를 건네주기만 하면 됩니다.

다음은 정수값을 갖는 변수의 주소와 문자열값을 갖는 pointer의 주소를 반환하고 그 주소값의 Data를 확인하는 예제입니다.

#include <stdio.h>

int *number(int i, int j);
char *namechar();

main()
{
  printf("%d\n", *number(10, 20));
  printf("%s\n", namechar());
}

int *number(int i, int j)
{
  int r;
 
  r = i + j;
 
  return &r;
}

char *namechar()
{
  char *name = "kosama\0";
 
  return name;
}



참고:
return문은 값을 반환하는 기능이외에 함수의 처리를 중단하는 기능으로도 사용되며 값을 반환하는 경우도 단일값 이외에 수식을 처리하는 방법으로도 활용할 수 있습니다. 또한 필요하다면 return문은 여러개를 하나의 함수에 쓸 수도 있습니다.

#include <stdio.h>

main()
{
  int a, b, c;
 
  a = 100;
  b = 200;
 
  c = prnt(a, b);
 
  printf("결과 %d\n", c);
}

int prnt(int a, int b)
{
  if (a != 100){
    printf("a가 100이 아닙니다.\n함수처리 중단...\n");
    return;
  }
  else
    return (a + b);
}


a가 100일 경우 return문을 통해 a와 b인수를 합한 결과값을 반환하도록 합니다.


#include <stdio.h>

main()
{
  int a, b, c;
 
  a = 200;
  b = 200;
 
  c = prnt(a, b);
 
  printf("결과 %d\n", c);
}

int prnt(int a, int b)
{
  if (a != 100){
    printf("a가 100이 아닙니다.\n함수처리 중단...\n");
    return;
  }
  else
    return (a + b);
}


a가 100이 아닌경우 Message를 출력하고 return하여 함수처리를 중단하도록 합니다.(함수가 중단되어도 main함수에서는 여전히 결과값을 표시하기 때문에 의미가 없는 값이 출력되고 있습니다.)


이때 return문으로는 2개 이상의 인수를 전달할 수 없습니다. 만일 2개의 결과를 동시에 받아야 한다면 return이 아닌 함수에 주소값을 전달하거나 전역변수를 사용하여 처리해야 합니다.

4. Prototype 선언으로 함수사용법 명확히 하기

C언어는 Compil시에 Program내부에서 함수의 호출이 올바른가에 대한 판단은 하지 않습니다. 예들들어

#include <stdio.h>

main()
{
  int a, b, c;
 
  a = 200;
  b = 200;
 
  c = prnt(a, "abc");
 
  printf("결과 %d\n", c);
}

int prnt(int a, int b)
{
  return (a + b);
}


prnt함수는 정수형 인수 2개만 받을 수 있지만 main에서는 prnt함수를 호출할때 "abc"라는 문자열값을 인수로 건네주고 있습니다.

이 Program을 Compil하면 어떠한 오류도 표시하지 않지만 실제 Program을 실행시켜 보면 정상적으로 동작하지 않음을 알 수 있습니다.


이 문제를 해결하기 위해서는 Program의 선두에 해당 함수의 형식을 지정해야 하는데 이 것을 흔히 Prototype 선언(함수원형선언)이라고 합니다.

#include <stdio.h>

int prnt(int a, int b);

main()
{
  int a, b, c;
 
  a = 200;
  b = 200;
 
  c = prnt(a, "abc");
 
  printf("결과 %d\n", c);
}

int prnt(int a, int b)
{
  return (a + b);
}


Program상단에 int prnt(int a, int b); 라는 Prototype을 선언하였습니다. Prototype을 선언하는 방법은 함수를 작성할때의 가장 처음부분을 똑같이 써주기만 하면 됩니다.


Program을 Compile하려고 하자 Prototype선언으로인해 함수사용이 잘못되었음을 표시해 주고 있습니다.

또한 Prototype선언시 인수부분에는 인수명을 생략하고 다음처럼 데이터형만 나타낼 수 있습니다.

int prnt(int, int); 또는 주소값 전달시 int prnt(int *, int *); 

실제 prnt에서 쓰인 a와 b라는 인수명을 생략하였는데. 이렇게 하는것도 정상적인 Prototype선언에 해당합니다.

물론 Prototype 선언을 하지않고도 함수사용에 대한 오류를 나타낼 수 있습니다. 이렇게 하려면 Program에서 개발자가 작성한 함수를 main함수위에 놓게 되면 Prototype을 선언한것과 같은 효과를 볼 수 있습니다.

#include <stdio.h>

int prnt(int a, int b)
{
  return (a + b);
}

main()
{
  int a, b, c;
 
  a = 200;
  b = 200;
 
  c = prnt(a, "abc");
 
  printf("결과 %d\n", c);
}


prnt함수를 main위에 작성하였습니다.


Prototype을 선언한것과 같은 오류를 나타내고 있습니다.

5. header File선언과 Prototype선언의 관계

Program에서 printf함수를 호출하여 사용한 경우 #include <stdio.h>를 통해 stdio.h header File선언이 필요하다고 하였습니다.

이것은 printf함수가 어떻게 동작할지에 대한 실체적 부분이 stdio.h안에 있기 때문인데 그것 말고도 printf함수가 어떻게 사용되야 하는지에 대한 Prototype선언이 stdio.h안에 정의 되어 있기 때문입니다.

따라서 printf함수처럼 사용자 함수가 아닌 표준 함수를 사용한 경우에는 각 함수마다 필요한 header File에 Prototype이 선언되어 있으므로 혹시 함수를 잘못 사용한 경우가 생긴다 하더라도 Compile시에 오류를 나타낼 수 있는 것입니다.

main()
{
  printf(100);
}

stdio.h의 include부분을 빼고 printf를 호출하였습니다. printf함수를 호출할때 정수값인 100을 곧장 인수로 건네주고 있는데 이것은 printf함수를 잘못 사용하고 있는 것입니다.


Compile시에 오류가 없으나 실제 Program을 작동시키면 오류가 발생하게 됩니다.

#include <stdio.h>

main()
{
  printf(100);
}


include를 통해 stdio.h File을 다시 포함하도록 하였습니다.


Compile을 시도하려 하자 함수사용이 잘못 되었음을 알리는 오류가 나타납니다.

6. 함수의 통용범위

일반적으로 함수를 선언하면 해당 함수는 다른 File에서 선언된 함수라 하더라도 사용이 가능합니다.

#include <stdio.h>

main()
{
  printf("main함수 입니다.\n");
 
  myfunc();
}
▶ 위 program을 test.c로 저장합니다.

#include <stdio.h>

myfunc()
{
  printf("myfunc함수 입니다.\n");
}


이 Program을 test2.c로 저장합니다.


main에서 myfunc함수를 정상적으로 호출하고 있습니다.

만일 작성된 함수를 다른 File에서 참조할 수 없도록 하려면 함수를 Static로 선언하면 됩니다. 위 Program에서 myfunc함수를 수정하여 Static으로 선언하고

#include <stdio.h>

static myfunc()
{
  printf("myfunc함수 입니다.\n");
}


test2.c로 저장하고 Compile을 시도하면 error를 발생하게 됩니다.


참고로 main에서는 별도로 떨어진 File에서 static으로 선언된 함수를 호출하는 것이 불가능합니다.

7. void형 함수

어떠한 인수도 받지 않는 함수는 괄호(())만을 통하여 인수설정을 생략할 수 있지만 이를 좀더 명시적으로 표현하기 위해서는 void를 사용합니다.

#include <stdio.h>

main()
{
  prnt();
}

prnt(void)
{
  printf("인수없음\n");
}


prnt()사용자 함수에 void를 사용하여 인수가 없음을 명시하고 있습니다.

더불어 prnt()함수에서는 어떠한 값도 반환하지 않는데 이때에도 void는 아무런 값을 반환하지 않는 함수라는 것을 명시하기도 합니다.

#include <stdio.h>

main()
{
  (void)prnt();
}

void prnt(void)
{
  printf("인수없음\n");
}


print()함수에 void를 사용하여 반환값과 인수값없음을 명시적으로 표현하고 있습니다. 또한 prnt()함수를 호출하는 쪽에서도 함수앞에 (void)라고 작성함으로써 함수를 호출하지만 어떠한 값도 받지 않는다는 것을 명시하고 있습니다.(값을 반환하는 함수를 호출한다 하더라도 되돌아 오는 값을 활용할 필요가 없는경우에도 쓰이곤 합니다.)

'Programming > C C++' 카테고리의 다른 글

[C, C++] Microsoft C, C++ Compiler  (0) 2010.01.22
[C, C++] Class 상속  (0) 2010.01.13
[C, C++] 함수작성및 Data전달  (0) 2010.01.07
C언어 함수사용 예제 Souce  (0) 2010.01.06
[C, C++] Pointer  (0) 2010.01.05
[C, C++] 변수통용범위(변수의 기억 Class)  (0) 2010.01.04
0 0
Programming/C C++
다음 Program은 변수를 활용한 간단한 예제입니다.

#include <stdio.h>

main()
{
  int i;
 
  i = 100;
 
  printf("i값 : %d\n", i);
}


이 Program은 결과로 i값을 출력합니다.


이 Program은 변수 i에 3이라는 값을 넣고 다시 i변수를 통해 해당 값을 출력하도록 작성된 예제입니다.

그런데 Computer의 입장에서 보면 단순히 변수 i가 있다는 것에서 끝나지 않습니다. 변수 i가 선언되면 Memory에 integer형의 Data를 담을 수 있는 공간을 확보하고 그 안에 3이라는 정수값을 저장합니다. 이때 저장된 해당 위치를 Memory의 Address라는 주소형태로 구분해야 합니다.

만일 변수라는 개념이 없이 개발자가 직접 Memory주소를 가지고 Data를 다루게 되면 Program구현이 상당히 어려워지고 위험해지게 될 것입니다. 그래서 Memory주소를 직접 다루는 대신 변수라는 Data를 다루기 시작한 것입니다.

일반적으로 변수를 참조하면 해당 변수에 들어있는 값을 다루게 되는데 만일 변수의 값이아닌 변수가 가리키고 있는 Memory주소를 직접 다루고자 한다면 Pointer를 사용해야 합니다.

#include <stdio.h>

main()
{
  int i;
  int *p;
 
  i = 100;
  p = &i;
 
  printf("i값 : %d\n", i);
  printf("i의 memory 주소값 : %d\n", p);
  printf("해당 memory주소에 있는 실제 data : %d\n", *p);
}


Pointer를 쓰기위해 int *p; 로 Pointer를 선언합니다. 이 Pointer는 p = &i;를 통해 i변수의 주소값을 저장하고 마지막 printf()함수를 통해 pointer가 가리키고 있는 Memory주소에서 Data를 가져와 보여주고 있습니다.


이처럼 특정 변수에 값이 아닌 주소를 직접 불러오려고 하면 변수 앞에 & 문자를 붙여 주기만 하면 됩니다. 이때 이렇게 불러들인 주소값을 직접 다루기 위해 Pointer가 사용되는 것입니다.

Pointer는 특정 변수가 가리키고 있는 번지를 기억하는 역활을 하며 Pointer를 통해 해당 Memory번지에 있는 Data를 가져오려면 Pointer앞에 *문자를 추가해야 합니다. 그러면 Pointer는 Memory주소에 있는 값을 직접 나타내게 되는 것입니다.

1. 배열과 Pointer의 활용

배열을 활용하고 있는 다음 Program을 보십시오.

#include <stdio.h>

sprint(char ss[]);

main()
{
  char s[6] = "hello";
 
  sprint(s);
}

sprint(char ss[])
{
  int i;
 
  for (i=0;i<=4;i++){
    printf("%c\n", ss[i]);
  }
 
  return;
}


이 Program은 main함수에서 char형 배열변수에 hello라는 문자열을 대입하고 sprint함수의 for문으로 해당 배열값의 각요소를 출력합니다.


main함수에서 sprint함수를 호출할때 작성한

sprint(s);

이 부분을 주목해 주세요.

배열을 전달할때는 위와 같이 배열변수 이름만이 사용되고 있습니다. 이는 배열전체를 모두 전달하는 것이 아니라 배열이 시작되는 Memory의 첫 주소값을 전달하고 sprint함수에서는 전달받은 주소값을 통해 배열값을 활용하고 있습니다.

즉 배열의 경우 배열변수이름만 쓰게되면 해당 배열이 시작되는 주소값을 얻게 된다는 것이고(일반변수처럼 & 문자를 붙이지 않습니다.) 이 특징 통해 Pointer에서도 배열을 다룰 수 있다는 의미가 됩니다.

#include <stdio.h>

main()
{
  char s[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
  char *p;
 
  p = s;
 
  printf("%s\n", p);
}


char배열 s의 시작주소를 char주소를 기억하는 p Pointer에 대입합니다. 그러면 s와 Pointer p의 주소는 같아지고 Printf함수에서는 배열 s가 아닌 p형 Pointer로 문자열을 출력할 수 있는 것입니다.(s배열로 문자열을 출력할때도 printf("%s\n", s); 로 주소값을 통해 문자열을 출력하였으므로 Pointer로 출력할때도 p를 그대로 사용하여야 합니다. *p로 하면 주소에 있는 값을 받아오므로 제대로된 결과를 얻을 수 없습니다.)


Pointer로 문자열 표현시 위에서 처럼 배열을 사용하는 경우도 있지만 Pointer자체에 직접 문자열을 초기화 하는 것도 가능합니다.

#include <stdio.h>

main()
{
  char *p = "hello";
 
  printf("%s\n", p);
}


Pointer p에 "hello"라는 문자열을 초기화 합니다. 이때 Pointer p는 "hello"문자열을 저장하고 있는 Memory에서 h로 시작하는 주소를 갖게 됩니다.


위 Program에서 p는 "hello"문자열의 시작주소를 가지고 있으므로 첨자로 배열주소를 지정하면 문자배열처럼 다룰 수 있습니다.

#include <stdio.h>

main()
{
  char *p = "hello";
  int i;
 
  for (i = 0; i < 5; i++)
    printf("%c\n", p[i]);
}



참고:
예제에서는 for문을 통해 Pointer p의 첨자를 증가시키면서 주소에 있는 값을 가져오고 있습니다. 이는 언뜻 보면 p Pointer의 주소를 1씩 증가시키는 것처럼 보일 수도 있으나 실제로는 그렇지 않습니다.

현재 Pointer p는 char형이므로 Pointer p에 +1을 한다는 것은 1byte만큼의 주소를 건너뛴다는 의미가 됩니다. 잘 알고계시는 바와 같이 char형은 8bit(1byte)의 Memory공간을 갖고있기 때문입니다.

2. Ponter를 통한 값의 변경

Pointer는 주소값을 가진다고 하였습니다. 이 Pointer에서 직접 값을 조작하면 원래 변수에 있던 값도 같이 바뀌게 됩니다. 왜냐하면 Pointer와 변수는 같은 주소를 유지하고 있기 때문입니다.

#include <stdio.h>

main()
{
  int a = 100;
  int *p;
 
  p = &a;
 
  *p = 200;
 
  printf("a의 값 %d - p의 값 %d\n", a, *p);
}


처음 변수 a에 100의 값을 대입하고 Pointer p에 해당 변수의 주소값을 건네준뒤 *p = 200;에서 Pointer가 가리키는 주소(변수 a의 주소)에 있는 값을 200으로 변경합니다. 이때 변수 a도 Pointer p와 같은 주소값을 가지고 있으므로 200의 값을 갖게 됩니다.


#include <stdio.h>

main()
{
  char s[6] = "hello";
  char *p;
  int i;
 
  p = s;
 
  *(p + 3) = 'p';
  *(p + 4) = '!';
 
  printf("%s\n", s);
  printf("%s\n", p);
 
  for (i = 0; i <= 5; i++){
    printf("%c\n", *(p + i));
  }
}


char형 배열 s에 "hello"라는 문자열을 초기화 한 후 배열의 시작주소값을 Pointer p에 전달합니다. Pointer p는 s배열의 시작주소을 가지므로 Pointer값을 1증가면 Pointer p주소값이 1만큼 늘어나게 되므로 Pointer p는 문자 'e'가 위치한 주소로 바뀌게 됩니다.

주의:
void형의 Pointer는 특정 범위를 주소값을 가지고 있는 상태가 아니므로 +나 -연산이 불가능합니다.

이런 원리를 통해 *(p + 3) = 'p'; 라고 하면 Pointer p의 주소값 3늘어나게 되고 (이때 p는 "hello"에서 4번째 배열을 가리키는 'l'의 주소값을 의미합니다.) 동시에 값을 'p'로 바꾸고 있습니다. 이와 같은 방법으로 마지막 배열의 주소값 Data도 '!'로 바꾼 후 최종적으로 조회하게 되면 다음과 같은 결과를 얻게 되는 것입니다.


3. const와 Pointer

Pointer변수를 const로 하면 값을 변경할 수 없는 Pointer가 됩니다. 이때 const를 어떻게 선언하느냐에 따라 주소값을 const로 할것인가 또는 값을 const로 할것인가가 달라지게 됩니다.

(1) 주소 const

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  char *const p = s;
 
  printf("%s\n", p);
}


*const p 형태로 Pointer를 선언해서 이 Pointer에 지정된 주소값 자체는 바꿀 수 없도록 하고 있습니다.


여기서 주소값을 바꿀 수 없다는 점에 주목해 주십시오. char *const p = s;로 Pointer를 선언함과 동시에 배열 s의 주소값을 대입하고 있는데 이렇게 하는 이유는 *const p로 인해 주소값을 바꿀 수 없기 때문에 선언과 동시에 주소값을 전달해 줘야 하기 때문입니다.

결국 다음과 같이 *const 로 Pointer를 선언한 뒤 새로운 값을 대입하는 것은 불가능한 것입니다.

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  char *const p;
 
  p = s;
 
  p += 1;
 
  printf("%s\n", p);
}


*const p로 Pointer를 선언하고 p에 s의 주소값을 대입하고 있으며 이후 Pointer자신의 값을 다시 1만큼 증가하도록 하고 있습니다.


Compil시 값을 바꿀 수 없다는 Error를 표시하고 있습니다.

(2) 값 const

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  const char *p;
 
  p = s;
 
  printf("%s\n", p);
}


const char *p로 Pointer를 선언하여 Pointer의 주소는 바꿀 수 있으나 값을 바꿀 수는 없도록 하고 있습니다.


예제에서 p = s;를 통해 주소값을 대입하고 있지만 해당 Pointer는 값을 바꿀 수 없는 형태의 Pointer이므로 아무런 문제 없이 Compil되고 실행됩니다.

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  const char *p;
 
  p = s;
 
  *p = 'x';
 
  printf("%s\n", p);
}


const로 선언된 Pointer에 *p = 'x';의 형태로 값을 바꾸도록 하고 있습니다.


p Pointer는 const로 선언되었으므로 값을 바꿀 수 없다는 Error를 내며 Compil에 실패합니다.

4. 범용 Pointer

Pointer의 선언은 원래

char *p;

처럼 해당 Pointer의 Data형을 지정됩니다. 하지만 어떤 Data형으로도 쓰일 수 있는 Pointer가 있는데 그것이 바로 범용 Pointer입니다. 이러한 범용 Pointer는 다음과 같이 선언됩니다.

void *p;

Pointer선언 부분에 Data형 대신 void라고 하면 해당 Pointer는 범용 Pointer가 됩니다. 이렇게 선언된 Pointer는 어떤 Pointer라도 포함할 수 있게 됩니다.

void *p;
char *cp;
int *ip;
 
p = cp;
p = ip;

하지만 범용 Pointer의 주소를 일반 변수에 대입할 때는 그Data형을 지정해 줘야 합니다. 왜냐하면 범용 Pointer는 주소값만 가질뿐이지 어떠한 Data형인지 지정되지 않았기 때문에 얼마만큼의 Memory를 확보해야 하는지에 대해서는 알 수 없기 때문입니다.

#include <stdio.h>

main()
{
  void *p;
  char c;
  int i;
 
  c = 100;
  p = &c;
 
  i = *(int *)p;
     
  printf("%d\n", i);
}


int i에 대입시 범용 Pointer를 int형 Pointer로 cast하여 대입(*(int *)p)하고 있습니다.


만일 위와 같이 하지 않고 그냥 대입하려 한다면

#include <stdio.h>

main()
{
  void *p;
  char c;
  int i;
 
  c = 100;
  p = &c;
 
  i = *p;
     
  printf("%d\n", i);
}


Compiler는 오류를 발생시키게 됩니다.


5. 함수와 Pointer와의 관계

변수를 선언하면 그 변수는 Computer의 Memory에서 해당 Data형에 맞는 크기 만큼의 영역을 확보하게 될 것입니다.

함수도 마찬가지 입니다. 함수자체도 Memory어딘가에 위치하고 있으며 결과적으로 함수가 위치한 이 주소값을 Pointer로 활용할 수 있습니다. 따라서 실제로 이런 동작을 구현하게 되면 직접 함수를 호출하지 않고도 Pointer만으로 함수를 호출한 것과 같은 결과를 얻을 수도 있습니다.

#include <stdio.h>

int plus(int i, int j);

main()
{
  int (*pls) (int i, int j);
  int ir;
  pls = plus;
 
  ir = pls(10, 20);
 
  printf("%d\n", ir);
}

int plus(int i, int j)
{
  return i + j;
}


int (*pls) (int i, int j);을 통해 함수형 Pointer인 pls를 선언합니다. 이때 Pointer를 함수처럼 호출할때의 인수도 int, int j같이 지정해 줘야 합니다.

이 Pointer를 pls = plus;와 같이 대입하면 plus() 함수의 주소값이 해당 pls Pointer에 대입되고 이후 pls(10, 20);를 통해 함수를 호출하듯이 사용할 수 있게 되는 것입니다.

이는 plus함수가 Memory의 1000번지에 있다고 가정한다면 plus(10, 20);라고 하였을 경우 1000번지에 10과 20을 넘겨 처리를 수행한다라는 의미가 되므로(주소값이 목적이 되므로) 주소값을 갖는 Pointer를 함수처럼 활용하는것 또한 가능해 지는 것입니다.


다음은 함수 Pointer를 조금 변형한 것으로 함수의 인수 자체를 함수 Pointer로 구현한 것이며 결과는 이전 예제와 같습니다.

#include <stdio.h>

int plus(int i, int j);

main()
{
  int ir;
 
  ir = callplus(plus, 10, 20);
 
  printf("%d\n", ir);
}

int callplus(int (*pls) (int i, int j), int x, int y)
{
  return pls(x, y);
}

int plus(int i, int j)
{
  return i + j;
}


callplus(plus, 10, 20)에 의해 함수자체를 함수 Pointer의 인수로 건네줍니다. 이때 callplus()함수는 그 내부에서 전달받은 함수 Pointer를 통하여 실질적인 함수호출을 실현합니다.

함수 Pointer에 대해 하나더 언급하자면 함수 Pointer도 배열로 처리하는 것이 가능하다는 것입니다. 이미 변수 Pointer를 언급할때 배열로서 처리할 수 있다라고 하였는데 이것은 함수 Pointer의 경우도 마찬가지 입니다.

#include <stdio.h>

int plus(int i, int j);
int mlus(int i, int j);

main()
{
  int (*pls[2]) (int i, int j);
  int ir;
  int ir2;
 
  pls[0] = plus;
  pls[1] = mlus;
 
  ir = pls[0](10, 20);
  ir2 = pls[1](30, 10);
 
  printf("%d\n", ir);
  printf("%d\n", ir2);
}

int plus(int i, int j)
{
  return i + j;
}

int mlus(int i, int j)
{
  return i - j;
}


int (*pls[2]) (int i, int j);을 통해 pls Pointer함수를 배열로 하여 2개(0~1)를 생성하도록 하였습니다.

이후 일반 배열처럼 pls[0], pls[1]... 과 같이 해당 함수 Pointer를 활용하기만 하면 됩니다.

'Programming > C C++' 카테고리의 다른 글

[C, C++] Microsoft C, C++ Compiler  (0) 2010.01.22
[C, C++] Class 상속  (0) 2010.01.13
[C, C++] 함수작성및 Data전달  (0) 2010.01.07
C언어 함수사용 예제 Souce  (0) 2010.01.06
[C, C++] Pointer  (0) 2010.01.05
[C, C++] 변수통용범위(변수의 기억 Class)  (0) 2010.01.04
0 0
1
블로그 이미지

클리엘