CHAPTER 10
POINTERS

[IMAGE: An Quarter-Size Version of The Joy of C Front Cover]
This chapter introduces pointers, a data type that can hold addresses. We study how to use them to provide call-by-reference parameter passing and to traverse arrays efficiently. We also see how to use them to access dynamically allocated arrays, arrays for which space is allocated at run time rather than compile time. The chapter concludes with a new implementation of sets, this time with dynamically allocated sets of varying sizes.

Jump to: [Previous Chapter | Next Chapter]


  1. POINTERS
  2. USING POINTERS TO SIMULATE CALL BY REFERENCE
  3. TRAVERSING ARRAYS USING POINTERS
  4. ARRAY PARAMETERS AND POINTERS
  5. POINTERS AS FUNCTION RETURN VALUES
  6. CONSTANTS AND POINTERS
  7. GENERIC POINTERS AND POINTER CONVERSIONS
  8. DYNAMICALLY ALLOCATING ARRAYS
  9. CASE STUDY: DYNAMICALLY ALLOCATED SETS

Objectives



Pointer: Memory address를 저장하는 data structure (메모리 주소를 저장하는 변수)

Pointer variable 정의: base_type *pointer_variable;

예)

int *p1, p2;

Integer를 저장할 수 있는 memory pointer 변수 p1 (pointer to integer)과 integer를 저장할 수 있는 변수 p2를 정의

Pointer에 대한 pointer (pointer to pointer), pointer에 대한 pointer에 대한 pointer도 정의할 수 있다. 그러나 세 단계 이상의 pointer 정의는 프로그램을 이해하기 어렵게 만들므로 가급적 사용을 제한한다.

int **p; // pointer to pointer to integer


Pointer 관련 operators

&: Address-of (변수의 주소)

*: Value-pointed-to (pointer가 point한 메모리에 저장된 값)

int val = 10;       // int 값 10을 저장하고 있는 메모리 : val
int *p = &val; // 변수 p는 값 10을 저장하고 있는 변수 val에 할당된 메모리의 주소 값을 저장: pointer variable 
// 나중에 초기 값을 부여하려면 p = &val;을 사용하여야 한다.

printf("&val=%X, p=%d, *p= %d, val=%d\n", &val, p, *p, val);

NULL pointer: 특수 목적으로 사용 (address 0)



Pointer와 function arguments

void swap(int *a, int *b) // integer a, b 값들을 서로 교환

{
   int temp;

   temp = *a;
   *a = *b;
   *b = temp;
}

Function은 하나의 값을 return하나 pointer를 이용하여 여러 값들을 호출 function으로 보낼 수 있다. 이러한 function은 이해하기 어려운 부수 효과 (side-effect)를 가져와 자주 사용은 별로 바람직하지 않다. 특히 function을 다른 function의 argument로 사용하기 어렵게 한다.

예) hours.c


Pointer arithmetic (address arithmetic)

Pointer와 관련된 의미있는 연산들은 다음과 같다.



Pointer 연산 시 pointer가 point하는 자료형에 따라 자동적으로 주소 계산이 행해진다. 즉, pointer to integer와 pointer to float 값을 1 증가 시키는 것은 각각 integer와 float에 사용되는 메모리 byte 수 만큼 증가시키는 결과를 갖는다.

* 주의: Pointer와 pointer의 더하기, pointer에 대한 곱하기, 나누기는 아무 의미가 없다.

예) 32bit compile 시

char *p1;
int *p2;
float *p3;
double *p4;

p1 = 100;
p2 = 200;
p3 = 300;
p4 = 400;
// p1 + 1 ==> 101
// p2 + 1 ==> 204
// p3 + 1 ==> 304
// p4 + 1 ==> 408



Pointer와 array

배열명은 주소 (pointer 값)로 처리된다. (프로그램 내에서 값을 변경시킬 수 없다. 즉, 상수로 처리됨.)

int ary[5] = { 10, 20, 30, 40, 50 }; 
int *p1, *p2; // integer를 저장할 수 있는 메모리 주소를 저장하는 포인터 변수 p1, p2 정의

p1 = ary; // p1 = &ary[0]; 와 동일
p2 = &ary[4]; // p2 = p1 + 4;와 동일

1: *p1 == ary[0],  *(p1 + 1) == ary[1],  *(p + i) == ary[i] == p[i]
2: (p1 < p2)는 TRUE
3: *p1 ==> 10
4: *(p1 + 3) ==> 40
5: *p1 + 3 ==> 13
6: *p1++ ==> *(p1++) ==> evaluate 결과는 10이고 그 후 p1을 1 증가 시킴 (p1 == &ary[1])
7: (*p1)++ ==> 11
8: *++p1 ==> 20
9: ++*p1 ==> 11
10: *p1 = 100; ==> ary[0] = 100;



Pointer array

int *ptr[10];  // pointer to integer 10개를 저장할 수 있는 배열 ptr 정의
int (*ptr)[10];  // integer 10개를 저장할 수 있는 배열에 대한 포인터 ptr 정의



Pointers to functions

int (*fp)(); // fp는 int를 return하는 function에 대한 pointer

int *f(); // f는 pointer to integer를 return하는 function

예)

void f1() { printf("Function 1 is called.\n"); }
void f2() { printf("Function 2 is called.\n"); }

void main()
{
void (*fp)();

fp = f1;
(*fp)(); // f1();과 동일
fp = f2;
(*fp)(); // f2();와 동일
}

결과:
Function 1 is called.
Function 2 is called.


복잡한 pointer p 정의 예)

char *p; // pointer to char
char **p;  // pointer to pointer to char
char (*p)[10];  // pointer to array [10] of char
char *p[10];  // array [10] of pointer to char
char *p();  // function returning pointer to char
char (*p)();  // pointer to function returning char
char (*p[10])();  // array [10] of pointer to function returning char



Dynamic memory allocation

Static allocation: global variable처럼 compile 시 특정 영역의 메모리가 할당되어 프로그램 실행 중 계속 사용 가능한 메모리 사용

Automatic allocation: function 또는 block 실행 시 할당되어 그 function 또는 block 실행이 끝나면 재사용이 가능한 메모리 사용

Dynamic allocation: 프로그램 실행 도중 필요 시 사용 가능 메모리 영역 (heap; pool of unallocated memory)에서 할당받아 사용하고 사용이 끝나면 다시 heap으로 되돌릴 수 있는 메모리 사용


Generic pointer: void *

임의의 자료형을 point할 수 있으나 크기를 모르기 때문에 pointer 관련 연산은 할 수 없다. 사용 시 특정 자료형 pointer로 casting하여 사용할 수 있다.

Heap에서 memory를 할당받을 경우 malloc function을 사용하고 할당받은 memory를 heap으로 돌려줄 경우 free function을 사용한다. (memory 사용)

Prototypes:

void *malloc(int);

free(void *);

예) char 10개를 저장할 수 있는 메모리 할당

char *cp;
cp = (char *)malloc(10);

// int 100개를 저장할 수 있는 메모리 할당

int *ip;
ip = (int *)malloc(100 * sizeof(int));

// 이후 pointer 연산 기능을 사용하여 memory를 이용할 수 있다.
// malloc function이 memory를 return할 수 없는 경우 (heap에 충분한
memory가 남아 있지 않을 경우) NULL pointer (혹은 NULL 값)를 return한다.
// 사용자는 malloc function이 제대로 memory를 할당하였는지 다음과
같이 검사하여야 한다.

if (ip == NULL) Error("No memory available");

// 사용이 끝난 memory는 다음과 같이 heap으로 돌려준다.

free(ip); // 또는 free((void *) ip); 



실습) 학번(long)과 성적(float)을 입력받아 성적순으로 출력하는 프로그램을 다음 두 가지 경우를 처리하도록 각각 작성하라.



Assignment #8 (기간: 1주일)

Integer를 저장한 array와 그 크기를 파라미터로 받아 array에 저장된 각 숫자의 빈도수를 출력하고 array에 저장된 수 중 최소값과 최대값을 모두 return하는 프로그램을 작성하라.

예)
array 내용: 91 93 98 92 92 95 93 92 91 95 99 92 98
출력:
91: 2
92: 4
93: 2
95: 2
98: 2
99: 1
최소값: 91
최대값: 99


[ Table Of Contents | Previous Chapter | Next Chapter]