1.기본 개념
 포인터는 다른 변수의 주소(address)를 저장하는 변수이다. 즉, 포인터 변수는 변수의 값으로 주소를 저장한다.

 형식 : 데이터형 *변수명;
 ex) char *ch; //또는 char* ch;
       int *num; //또는 int * num;

 위와 같이 데이터형을 쓰고 *을 쓰고 변수명을 적어준다. char*은 char형 변수의 주소, int*은 int형 변수의 주소를 저장한다는
의미이다. 여기서 포인터 변수는 포인터형에 관계없이 항상 크기가 4바이트다. char*형 변수, int*형 변수에 관계없이 "주소"를
저장하기 때문에 4바이트(32비트 플랫폼 기준) 크기를 갖는다. 하지만 포인터 변수가 가리키는 변수는 char형은 1바이트,
int는 4바이트와 같이 각 데이터형에 알맞은 크기를 가진다.

 #include <stdio.h>
 int main(void)
{
 char x;
 char *p = &x;

printf("char 의 크기 = %d\n",sizeof(x)); //char의 크기는 1바이트이므로 1이 출력됨
printf("char*의 크기 = %d\n",sizeof(p)); //char*의 크기는 4바이트이므로 4가 출력됨

return 0;
}

 포인터 변수 선언 시 유의할 점은 다수의 포인터 변수 선언 시에 int* a,b;라고 하면 int *a; int b;로 선언된 것과 같다.
 따라서 int *a, *b; 이렇게 포인터 변수마다 *을 써주어야 한다.

2.포인터의 사용
 포인터 변수를 사용하기 위해서 일단 두 가지 연산자가 필요하다. 첫 번재는 주소 구하기 연산자
(address of operator)
로 변수 이름 앞에 &을 사용하여 변수의 주소를 구할 수 있다.

 int x;
 int *p;
 p = &x; //x의 주소를 포인터 변수 p에 대입

 &연산자는 주소를 구하는 것이므로 상수나 수식에는 사용이 불가능하며 변수에만 사용이 가능하다.
그리고 반드시 int형 변수의 주소는 int*형의 변수에 저장해야 하며 다른 형의 변수에 저장하면 컴파일 경고가 발생한다.
 두 번째는 간접 참조 연산자(indirection operator)이다. 포인터 변수 앞에 *을 사용하면 포인터 변수가 가리키는
변수의 값을 읽어오거나 변경할 수 있다.

 int x;
 int *p = &x; //x의 주소를 포인터 변수 p에 대입
 *p = 10; //p가 가리키는 변수, 즉 x에 10을 대입

아래의 코드로 공부한 내용을 직접 확인해보자.

#include <stdio.h>
int main(void)
{
 int x;
 int *p = &x;
 *p = 10; //x에 10을 대입

 printf("x =%d\n",x); //x의 값인 10이 출력됨
 printf("*p =%d\n",*p); //p가 가리키는 변수 x의 값인 10이 출력됨

 printf("&x =%d\n",&x); //변수 x의 주소 값이 출력됨
 printf("p =%d\n",p); //p는 변수 x의 주소 값을 저장하고 있으므로 변수 x의 주소 값이 출력됨

 printf("&p =%d\n",&p); //포인터 변수 p의 주소 값이 출력됨

 return 0;

 포인터 변수 p 역시 변수이므로 메모리에 할당된 공간이 있고 그에 대한 주소를 가지므로 printf("&p= %d\n",&p);에서는
포인터 변수 p가 할당받은 메모리의 주소 값이 출력된다.

※ 이중 포인터(double pointer)
 int x;
 int *p = &x;
 int **dp = &p;
 **dp = 10;

//즉, *(*dp) = *(p) =  x = 10

삼중, 사중 포인터도 만들 수는 있으나 잘 사용되지 않는다.

3.포인터 사용 시 주의사항
 앞서 말했듯이 포인터 변수의 데이터형은 포인터 변수가 가리키는 변수의 데이터형과 반드시 일치해야 한다.
이유를 살펴보면 다음과 같다.

 short a;
 int *p = &a;
 *p=10;
위와 같은 선언 시에 포인터 변수 p는 자신이 가리키는 곳에 int형 변수가 있다고 가정하는데 실제로는 short형 변수인 a가
있기 때문에 short형 변수의 크기인 2바이트에 추가로 그다음 주소의 2바이트까지 합쳐서 총 4바이트, 즉 int형 변수의
크기로 10을 저장한다. 그렇게 되면 a 변수뿐 아니라 다음 주소의 값까지 변경되어서 실행 에러가 발생한다.
 또다른 주의사항은 포인터 변수를 초기화 하지 않아 쓰레기 값을 가지고 있을 때이다. 포인터 변수도 변수이므로
초기화 해주지 않으면 쓰레기 값을 갖는다.
 int *p;
 *p = 10;
 위와 같은 선언 시 p가 쓰레기 값을 가지고 있을 때는 10을 메모리의 어느 위치에 저장하게 될지 모른다. 따라서 심각한 문제를 일으킬 수도 있다.
 그렇다면 초기화하는 방법은 무엇일까? 포인터가 아무것도 가리키지 않을 때는 변수에 0번지를 저장하고, 이것을
널 포인터(null pointer)라고 부른다.
 int *p = NULL; //널 포인터로 초기화

 if(p!=NULL) //널 포인터가 아닌지 확인 후에 사용
 *p=10;

 if(p) //0이 아닌 값은 참이므로 이렇게 확인하는 방법도 가능
 *p=10;

'프로그래밍 > C' 카테고리의 다른 글

공용체와 열거체  (0) 2011.01.19
구조체  (0) 2010.10.23
배열과 포인터의 관계  (0) 2010.10.09
선택정렬 (Selection Sort)  (0) 2010.10.09
배열 (array)  (0) 2010.10.09
비트 연산자  (0) 2010.10.03
삼각형 출력하기  (0) 2010.10.03
1.기본 개념
배열(array)은 같은 데이터형 변수를 메모리에 연속적으로 할당하고 같은 이름으로 이용이 가능한 방법이다.
 형식 : 데이터형 배열명 [크기] = {초기값1, 초기값2, ...};
 ex) int arr[5] = {1,2,3,4,5};
       double sum[10] = {1,2,3};
       int exam[] = {100,200,300};
 기본적인 형식은 위와 같다.
 배열의 값에 접근할 때는 인덱스(index)를 이용하는데 인덱스는 같은 이름의 배열 중에서 몇 번째 원소인지를 나타내는
것이다. 주의할 점은 인덱스는 0부터 시작하고 하나씩 증가한다는 것이다. 예를 들어 int arr[5]라는 배열은 크기가 5이고
원소 arr[0], arr[1], arr[2], arr[3], arr[4]를 포함하는 총 5개의 원소로 이루어진 배열이다. 인덱스가 0부터 시작하기
때문에 마지막 원소의 인덱스는 '배열의 크기 -1'이 된다. 참고로 인덱스는 리터럴 상수나 매크로 상수는 가능하나
변수는 불가능하다.

 배열도 변수의 집합이므로 초기화 해주지 않으면 쓰게기 값을 갖게 되므로 선언 시 초기화 해주는 것이 여러모로 좋다.
 배열을 초기화 해주는 방법은 {}을 이용해서 초기 값을 선언해주면 된다. double sum[2] = {0,1};과 같이 선언해주면
sum[0]=0; sum[1]=1;로 초기화 해준 것이다. 그런데 double sum[2] = {};과 같이 공백으로 비워두면 초기 값을
지정하지 않아 컴파일 에러가 발생한다. 전체를 0으로 초기화 하려면 double sum[2] = {0};으로 하면 된다.
 위의 표에서 double sum[10] = {1,2,3};은 sum[0]=1; sum[1]=2; sum[2]=3;이고 sum[3]~[9]=0;이 된다. 
 int exam[] = {100,200,300};의 경우에는 배열의 크기가 지정되지 않았지만 초기화를 해준 값을 토대로 자동으로 크기를
지정해준다. 즉, int exam[3] = {100,200,300};으로 선언된 것이다. 그리고 당연히 배열의 크기보다 많은 초기 값을
선언하면 에러가 발생한다. 참고로 int arr[5]; int size = sizeof(arr)/sizeof(arr[int]);와 같이 선언해서 배열의 원소의
개수, 즉 배열의 크기를 구할 수 있다. 5(배열의 크기) x 4(int형=4바이트) 이므로 배열의 전체를 20바이트이다. 따라서
20/4=5이므로 크기를 구할 수 있다.

2.다차원 배열
 가장 기본적인 다차원 배열로 이차원 배열의 형태는 아래와 같다.
 형식 : 데이터형 배열명 [제1크기][제2크기];
 ex) int score [2][3];

 이차원 배열은 제1크기x제2크기만큼 메모리에 할당된다.
 int score [2][3];은 3개씩 2묶음이라고 생각하면 된다. 즉, 2명의 학생에 대한 국어, 영어, 수학의 점수를 저장하는 배열로
적합하다. 이유를 살펴보면 다음과 같다. 이차원 배열에 접근 할 때는 가장 오른쪽 인덱스부터 증가한다.
int score [2][3];에서
score [0][0];
score [0][1];
score [0][2];
score [1][0];
score [1][1];
score [1][2];
 위와 같이 오른쪽 인덱스부터 증가하고 그 다음 왼쪽 인덱스가 증가한다. 따라서 제1인덱스가 0(학생A)일 때 제2인덱스
0(국어), 1(영어), 2(수학)이라고 생각하면 쉽다.
 이차원 배열의 초기화도 {}을 이용하며 묶음 단위로 {}로 묶는다.
ex) int score [2][3] = {{1,2,3},{4,5,6}}; //3개씩 2묶음
      int score [2][3] = {1,2,3,4,5,6}; //이 형태도 위와 같은 의미
      int score [2][3] = {{1,2},{3,4}}; //{{1,2,0},{3,4,0}}으로 초기화
      int score [2][3] = {{1,2,3,4}}; //{1,2,3,4,0,0}으로 초기화
이차원 배열의 초기화 시에도 배열의 크기가 생략 가능하지만 반드시 제1크기만 생략 가능하다.
ex)  int score [][3] = {1,2,3,4,5,6}; //int score [2][3];으로 인식
       int score [2][] = {1,2,3,4,5,6}; //몇 개짜리 3묶음인지 알 수 없어서 에러

C 언어에서는 이차원 배열뿐 만 아니라 삼차원, 사차원 배열도 지원한다. 다차원 배열이라고 부르는 것에서 알 수 있듯이 
특별히 차수에 대한 제한을 두지 않는다.

'프로그래밍 > C' 카테고리의 다른 글

배열과 포인터의 관계  (0) 2010.10.09
포인터 (Pointer)  (0) 2010.10.09
선택정렬 (Selection Sort)  (0) 2010.10.09
비트 연산자  (0) 2010.10.03
삼각형 출력하기  (0) 2010.10.03
형변환 (type conversion)  (0) 2010.10.03
삼항 연산자를 이용한 최대값 구하기  (0) 2010.10.03

1. 비트 OR 연산자 (|)

 a의 비트
 b의 비트
 a의 비트 | b의 비트
 0 0
0
 0 1
1
 1 0
1
 1 1
1
각 비트에 대해서 OR 연산을 수행한다.

0
 0 0
 0  1  0 1
0
 | |
|
|
 | |
|
|
 0 0
0
 0 1
1
0
0
 =  =  = =
 = =
 = =
 0  0 0
 0  1 1
 1 0
위와 같이 각 비트들을 모두 OR 연산 한다.

2. 비트 XOR 연산자 (^)
a의 비트
b의 비트
a의 비트 ^ b의 비트
 0 0
0
 0 1
1
 1 0
1
 1 1
0
XOR은 배타적 논리합(exclusive OR)이라고도 하고, 두 값이 다르면 1, 같으면 0이 되는 연산이다.

3. 비트 NOT 연산자 (~)
 a의 비트
~a의 비트
 0  1
 1  0
단항 연산자로 피연산자가 하나뿐이고 각 비트를 반전시킨다. 즉, 0은 1로, 1은 0으로 만든다.

4. 비트 이동 연산자 (<<, >>)

0

 0

 1

 0

 1

 0

1

 0

 1

 0

 0

 0

  위의 첫번째 표는 10을 2진수로 나타낸 것이다. 아래의 두번째 표는 10<<2로 10을 왼쪽으로 2비트씩 이동시킨 것이다.
파란색 부분은 빈자리에 대신 들어온 비트이다. 이때 빈자리에는 0이 채워진다. 비트 이동 연산자의 우변이 n이라고 하면, 비트 왼쪽 이동은 2^n을 곱하는 것과 결과가 같다.반대로 오른쪽 이동은 2^n을 나누는 것이 된다.

 #include <stdio.h>
 int main(void)
{ 
 int a=10; //0x0a
 int b; 
 b = a <<2;
 printf("a <<2 = %08x(%d)\n",b,b);
 b = a >>2;
 
 printf("a >>2 = %08x(%d)\n",b,b);
 
 return 0;
}

 비트 이동 연산자를 이용한 위의 코드로 확인이 가능하다.


'프로그래밍 > C' 카테고리의 다른 글

배열과 포인터의 관계  (0) 2010.10.09
포인터 (Pointer)  (0) 2010.10.09
선택정렬 (Selection Sort)  (0) 2010.10.09
배열 (array)  (0) 2010.10.09
삼각형 출력하기  (0) 2010.10.03
형변환 (type conversion)  (0) 2010.10.03
삼항 연산자를 이용한 최대값 구하기  (0) 2010.10.03

+ Recent posts