10 포인터

Download Report

Transcript 10 포인터

메모리 구조

컴퓨터 메모리
메모리 셀이 연속적으로 나열
된 형태
 각 메모리 셀에는 주소가 부여
되어 있음
 데이터는 각 데이터 크기에 필
요한 만큼 메모리 셀을 차지함


64M 메모리를 가정했을 때 메모리 구성도
메모리 셀 자체 정보
어떤 데이터 a가 차지하는 메
모리 셀 개수는 sizeof(a)로
알 수 있음
 메모리 셀 주소는?

1
포인터

포인터(pointer)란?
데이터를 저장하기 위해 할당된 메모리 공간의 주소
 포인터 상수(pointer constant): 메모리 주소 값
 포인터 변수(pointer variable): 주소 값을 저장할 수 있는 변수
 데이터에는 자료형이 연관되어 있으므로 포인터에도 자료형이 연관됨
(예: int 포인터, double 포인터 등)


간접참조(indirection, dereferencing)
포인터가 가리키는 곳을 따라가 연관된 데이터 혹은 그 데이터가 저장된
공간을 참조하는 것
 간접참조한 데이터의 자료형은 포인터 자료형을 이용하여 판단함

포인터
간접참조
int 포인터 상수
1024
int형 데이터
double 포인터 변수
1052
double형 데이터
2
포인터 선언과 사용

포인터 선언 형식
자료형 *포인터변수;

포인터 사용 예
int one = 1;
//
int *to_one;
//
to_one = &one;
//
one = one + 1;
//
one = *to_one + 1; //
*to_one = one + 1; //

int 변수
int 포인터 변수
to_one은 one을 가리킴
one ≡ 2
one ≡ 3
one ≡ 4
one
1
4
3
2
to_one
포인터와 일반 변수를 함께 선언
int one, *to_one;
int one, *to_one = &one; // 선언과 함께 초기화!
3
toOne.c

간접참조 수식 *to_one의 의
미는 대입 연산자의 어느 쪽에
있느냐에 따라 정해짐
오른편: to_one이 가리키는
곳에 저장된 값
 왼편: to_one이 가리키는 곳
에 할당된 변수(int 변수)

실행결과:
one
one
one
one
=
=
=
=
1
2
3
4
4
포인터 제1법칙(law1.c)
포인터 제1법칙
*(& a) ≡ a
포인터 제1법칙의 의미
 주소연산을 취한 결과
에 간접참조연산을 취
하면 원래 변수와 같다
실행결과:
숫자 n을 입력해 주세요. 275
n
= 275
*&n
= 275
5
10.2 포인터 인수전달
6
포인터 인수전달

포인터를 인수로 전달하면



포인터를 간접참조함으로써 해당 포인터가 가리키는 데이터 값
을 변경할 수 있다
호출된 함수에서 호출한 함수의 변수 값을 변경할 수도 있다
포인터 인수 전달을 사용하는 이유


호출된 함수의 '부수효과(side-effect)'로서 호출한 함수의 변수 값
을 변경하기 위해
인수로 전달할 데이터의 크기가 매우 큰 경우에 인수전달 효율을
높이기 위해
 인수 데이터 크기가 큰 경우 예: 배열, 구조체
7
변수 값 교환 프로그램(swap0.c)
이 부분을 함수로 만들어 봅시다!
실행결과:
변수 값을 순서대로 출력하면 2, 3 입니다.
변수 값을 순서대로 출력하면 3, 2 입니다.
8
변수 값 교환 함수?(swap1.c)
교환되지 않은 이유?
swap의 a, b는 main의 a,
b가 아니다. main의 a, b
의 사본일 뿐이다.
실행결과:
변수 값을 순서대로 출력하면 2, 3 입니다.
변수 값을 순서대로 출력하면 2, 3 입니다.
9
변수 값 교환 함수(swap2.c)
swap에서 main의
a, b의 주소를 알고
있으므로 이들 변수
값을 변경할 수 있
다.
실행결과:
변수 값을 순서대로 출력하면 2, 3 입니다.
변수 값을 순서대로 출력하면 3, 2 입니다.
10
10.3 배열과 포인터
11
배열과 포인터

배열 이름을 포인터에 저장




배열 이름은 배열이 할당된 공간의 주소이므로 포인터 상수임
따라서 배열 이름을 포인터 변수에 저장할 수 있음
이 때, 포인터의 타입은 배열 원소를 가리킬 수 있는 타입이어야
함
포인터 가감연산


포인터에 가감연산을 취하면 포인터가 가리키는 자료의 크기 단
위로 포인터 값이 증감함
포인터 가감 연산 예:
int a[10], *p = a;
p += 2;
포인터 p 값은 2만큼 증가하는 것이 아니라
2 * sizeof(int)만큼 증가함
12
arrayName.c
char형 배열 이름
은 char형 포인터
에 저장할 수 있다.
실행결과:
배열 이름을 이용한 출력:
포인터 변수를 이용한 출력:
Good bye yellow brick road~!
Good bye yellow brick road~!
13
ptrIncr.c
실행결과:
sizeof(int) = 4
a + 0 = 0012FF58
a + 1 = 0012FF5C
b - 2 = 0012FF60
b - 1 = 0012FF64
14
포인터를 통한 배열원소 참조
배열 첨자연산대신
포인터 간접참조연산을
사용할 수 있다.
실행결과:
I am just a poor boy ~
15
포인터 제2법칙(law2.c)
포인터 제2법칙
p[n] ≡ *(p + n)
포인터 제2법칙의 의미
 배열 첨자연산은 본질적
으로 포인터 연산이다.
실행결과:
I am just a poor boy ~
I am just a poor boy ~
16
포인터 상수에도 적용됨

배열이름은
포인터 상수
포인터 제2법칙은 포인터 상수
에도 똑같이 적용된다.
실행결과:
I am just a poor boy ~
I am just a poor boy ~
17
배열 인수 전달 복습
배열 형태로 선언한 매개변수
에는 배열 이름(포인터 상수)
이 전달되므로 사실 포인터임
 따라서 배열 매개변수 선언 시
크기 선언은 중요하지 않음
T p[250] ≡ T p[3] ≡ T p[]

배열 형태지만 사실
은 char 포인터임
실행결과:
I am just a poor boy ~
18
포인터다운 배열 참조 방식

배열 시작 위치를 기억할 필요
가 없다면 포인터를 증가시켜
가며 배열 원소를 참조할 수 있
다.
p가 가리키는 원소를 참조한 후
p를 1 증가시킴
실행결과:
I am just a poor boy ~
p가 가리키는 원소가 '참'이면 반
복. 즉 p가 가리키는 원소가
'\0'이 아니면 반복.
19
10.4 더 복잡한 선언문
20
포인터의 포인터

int 포인터의 포인터를 한 번
따라가면 int 포인터를 얻을
수 있다.
ppi는 포인터 변수
를 가리킬 수 있는 포
인터
실행결과:
i
*pi
**ppi
**ppi
*pi
i
=
=
=
=
=
=
5
5
5
12345
12345
12345
21
배열 포인터와 포인터의 포인터
배열 포인터로 출력한
2차원 배열
포인터의 포인터로 출
력한 포인터 배열
실행결과:
[Array Pointer]
0012FF4C: This
0012FF51: That
0012FF56: Here
0012FF5B: Hour
[Pointer Pointer]
0012FF68: This
0012FF6C: is
0012FF70: pointer
0012FF74: array
22
10.5 typedef
23
typedef

typedef는…




자료형 별칭(type alias)을 정의하는데 사용되는 키워드
복잡한 자료형을 간단한 이름으로 지칭할 수 있음
선언문 앞에 typedef를 붙이면 선언하는 이름은 타입 이름이 됨
typedef 사용 예

int에 대한 타입 별칭
int i;
typedef int iType;

// i는 int 변수
// iType은 int 타입의 다른 이름
int 포인터에 대한 타입 별칭
int *p;
// p는 int 포인터 변수
typedef int *pType; // pType은 int 포인터 타입
pType q = &i;
// q는 pType, 즉 int 포인터
24
typedef.c
이렇게 선언한 뒤에는
IntType ≡ int
RealType ≡ double
이다.
따라서
변수 선언은 물론,
자료형 변환에도 사
용할 수 있다.
실행결과:
5 + 7 = 12
5 / 7 = 0.714286
25
복잡한 타입을 typedef로…


typedef를 이용하면 복잡한 타입을 쉽게 다룰 수 있음
배열 포인터 선언 예
int (*q1)[20];

typedef를 이용하여 단계적으로 선언하는 예
typedef int AI[20];
AI *q2;
// q1과 q2모두 크기 20인 int 배열에 대한 포인터임
26
10.6 void 포인터
27
void 포인터



void는 '없음(nothing)'
void*는 '아무것이나 가리키는
포인터(pointer to anything)'
그래서 void*를 '범용 포인터
(generic pointer)'라고 부르기도
한다.
이 부분을 함수로 바꾸면…
실행결과:
i의 주소 = 0012FF74
f의 주소 = 0012FF78
28
void 포인터에 대한 간접참조


void 포인터는 간접참조할 수 없
음
간접참조하려면 명시적으로 형변
환을 수행해야 함
실행결과:
i = 19100829
f = 3.141592
29
10.7 함수 포인터
30
함수 포인터

함수 포인터(function pointer)란?





함수를 가리키기 위한 포인터
함수 포인터를 이용하여 함수를 호출할 수 있음
함수 포인터로 함수를 호출할 때에는 간접참조하지 않아도 됨
리턴타입 뿐만 아니라 매개변수 자료형도 함수의 타입에 해당함
함수 포인터 활용 예
int (*fp)(int);
int add1(int x) { return x + 1; }
void prInt(int x) { printf("%d", x); }
int add(int x, int y) { return x + y; }
...
fp = add1;
// prInt는 저장불가(리턴타입이 다름)
// add는 저장불가(매개변수 타입이 다름)
two = fp(1);
// add1을 호출하게 됨
31
funPtr.c
실행결과:
자연수 하나를 입력하세요.
팔진표기:
100
십진표기:
64
32
64
average.c (1/2)
산술평균
조화평균
기하평균
세 함수의 타입이 모두 같다는 사실에 주의하자.
a_mean: double × double  double
h_mean: double × double  double
g_mean: double × double  double
33
average.c (2/2)
함수 포인터 배열 fun
실행결과:
평균을 구할 두 수를 입력해 주세요.
5 10
어떤 평균을 구하고 싶으신가요?
1. 산술평균
2. 조화평균
3. 기하평균
번호를 입력해 주세요. 1
선택하신 산술평균은 7.500000
34
프로그래밍 실습
35
▶ 프로그래밍 실습 1

명령줄 인수를 처리하는 프로그램 Do.c를 작성하여라. Do.c의 실행
파일을 Do(혹은 Do.exe)라고 하면 Do는 자신을 포함하여 문장을 입
력으로 받는다. 그리고 마치 그 문장을 이해하고 답변하는 것처럼 반
응한다. 예를 들면, 다음과 같다.
> Do you have match?
Yes, I have match.
> Do you like C language?
No, I don't like C language.
긍정적인 답변을 할 것인지 부정적인 답변을 할 것인지는 무작위로
결정하라. 무작위로 결정하기 위해 rand()와 srand()를 활용하라.
36
▶ 프로그래밍 실습 2

암호화 알고리즘 중에는 "증분 k(displacement k)" 알고리
즘이 있다. 예를 들어, k = 3인 경우에는 각 알파벳을 3개
뒤로 미룬다. 즉 a는 d로 b는 e로 변경한다. z 다음의 알
파벳은 다시 a가 오는 것으로 가정한다.
이런 방식으로 암호화하면 k = 3일 때 문자열
"Joy of C programming"
은
"Mrb ri F surjudpplqj"
이 된다. 사용자로부터 k를 입력받은 후 그 다음 행부터
주어지는 문자열을 암호화하는 증분 k 암호화 프로그램
을 작성하라. k는 0이상 25이하의 수라고 가정하자.
37