2016년2학기 고급컴퓨터프로그래밍및실습 (36342-02)
제8장 포인터
1
포인터 기초
포인터 선언, 연산, 주의 사항
배열과 포인터
문자열 상수와 문자열 포인터
목차
2
컴퓨터 주기억장치 (메모리)
3
0 1 2 3 4 5 6 7 8
n-1 n-2
10 x
int x;
x = 10;
(1) 변수 x에 저장되어 있는 값 = 10
(2) 변수 x의 주소 = 4
포인터 (pointer)
주소(address)를 저장하는 변수
4
1236
주소: 3800
p
150
주소: 1236
x
포인터 p 는 변수 x 를 가리킨다.
x
주소: 1200
포인터 선언과 주소 지정 예제
int x;
int *p;
x = 10;
p = &x;
printf(“x=%d”, x);
printf(“*p=%d”, *p);
*p = 20;
x = x + *p;
*p = *p * 2;
5
10
p
주소: 2032
1200
10 20
변수 x 의 주소
포인터 p가 가리키는 변수
80 40
포인터 선언
6
int *p;
int * p;
int* p;
OK
포인터의 사용
포인터를 사용하려면 주소 구하기 연산자(&: address-of operator) 와 간접 참조 연산자(*: indirection operator)가 필요하다.
7
x
1200
포인터 사용 예제
int x;
int y;
int *p;
p = &x;
*p =10;
p = &y;
*p =20;
8
10
p
2032
1200
y
1400
20
1400
포인터의 잘못된 사용
& 연산자는 반드시 변수명 앞에만 사용할 수 있으며, 상수나 수식에는 사 용할 수 없다.
9
초기화되지 않은 포인터
10
포인터를 초기화 하지 않으면 그 포인터가 어디를 가리키는지 알 수 없으므로,
실행 오류가 생긴다.
NULL 포인터
11
아무 것도 가리키고 있지 않을 때는 NULL 로 초기화해 두는 것이 좋다.
NULL 포인터의 사용
12
포인터형과 변수의 데이터형 (1/2)
13
double 형 포인터가 int 형 변수를 가리킬 수 없다.
즉, 포인터 타입과 변수 타입은 같아야 한다.
포인터형과 변수의 데이터형 (2/2)
14
절대 주소의 사용 (X)
15
절대 주소는 특수한 경우에만 사용하는 것 으로, 일반적인 프로그램에서 사용하면 컴파일/실행 에러가 발생한다.
warning C4047: '초기화 중' : 'int *'의 간접 참조 수준이 'int'과(와) 다릅니다.
간접참조 연산자와 증감 연산자
p+N은 p가 가리키는 데이터형 N개 크기만큼 증가된 주소
p-N은 p가 가리키는 데이터형 N개 크기만큼 감소된 주소
16
*pi = 10;
*(pi+1) = 20;
*(pi+2) = 30;
10 20 30
간접참조 연산자와 증감 연산자
17
10.0 20.0 30.0
*(pd+0) = 10.0;
*(pd+1) = 20.0;
*(pd+2) = 30.0;
포인터와 증감 연산자
18
포인터와 +, - 연산
‘포인터-포인터’ 연산은 두 포인터의 차를 구하는 데 사용된다.
19
배열 접근 방법 : 배열명과 인덱스
20
10 20 30 40 50
A[0] A[1] A[2] A[3] A[4]
일반적인 방법
배열 A 에 저장되어 있는 숫자들을 화면에 출력하시오.
배열 접근 방법 : 포인터 p
21
10 20 30 40 50
A[0] A[1] A[2] A[3] A[4]
p
p = &A[0]; 또는 p+0
p = A;
A
p+1 p+2 p+3 p+4
printf(“%d”, *(p+4));
50
포인터로서의 배열명
(인덱스를 제외한) 배열명은 그 배열의 포인터와 같다.
22
arr arr+1 arr+2 arr+3 arr+4
배열 접근 방법 : 포인터 A
23
10 20 30 40 50
A[0] A[1] A[2] A[3] A[4]
A+0
A
A+1 A+2 A+3 A+4
printf(“%d”, *(A+4));
50
A[i]와 *(A+i)는 같은 표현임
배열 접근 방법 : 포인터 q
24
10 20 30 40 50
A[0] A[1] A[2] A[3] A[4]
p
q
A
q q q q
숫자 1개 출력후 포인터 q가 다음 숫자를 가리키도록 이동시키자
주의 사항
배열 이름인 포인터
A는 q 와 같이 이동 불가 즉, A = q; 와 같이
A 값을 수정할 수 없다.
배열 접근 방법 : 포인터 q를 배열처럼
25
10 20 30 40 50
A[0] A[1] A[2] A[3] A[4]
q
q[0]
A
q[1] q[2] q[3] q[4]
주의 사항
배열 이름이 포인터이듯이 (반대로) 포인터 p도
배열 이름처럼 인덱스를 쓸 수 있다.
배열 접근 방법:
포인터 p가 배열 중간 가리킬 때
26
10 20 30 40 50
A[0] A[1] A[2] A[3] A[4]
A
p p+1 p+2
실행결과 30 40 50
(참고) 배열 이름을 포인터로 사용 (1/2)
배열의 시작 주소에서 int i개 크기만큼 증가된 주소에 있는 값
27
주소
값 배열 이름을 포인터처럼
사용하는 경우
(참고) 배열 이름을 포인터로 사용 (2/2)
28
주소 출력
값 출력
(참고) 포인터를 배열 이름처럼 사용 (1/2)
배열의 시작 주소로 초기화된 포인터를 이용해서 배열의 모든 원소에 접근할 수 있다.
포인터 변수를 배열 이름인 것처럼 사용할 수 있다.
29
값
주소
(참고) 포인터 p와 p[i]의 사용
배열의 원소를 가리키는 포인터는 배열의 어떤 원소든지 가리킬 수 있다.
포인터가 배열의 원소가 아닌 일반 변수를 가리킬 때도 *(p+i) == p[i]는 항상 성립한다.
30
(예제) 포인터와 배열 이름 (1/2)
31
배열의 시작 주소로 초기화된 포인터
배열 원소의 주소 구하기
(예제) 포인터와 배열 이름 (2/2)
32
배열 원소의 값 구하기
배열과 포인터의 차이점
배열이 메모리에 할당되고 나면, 배열의 시작 주소를 변경할 수 없다.
포인터 변수는 값을 변경할 수 있으므로, 포인터 변수에 보관된 주소는 변경 할 수 있다.
33
이중 포인터
포인터 변수의 주소를 저장하는 포인터 변수
이중 포인터가 가리키는 포인터를 이용해서
변수에 접근하려면 **처럼 두 번 간접 참조를 해야 한다.
34
(1) 지난학기 강의노트 7장 27~52쪽 참조
(2) ACPL 7장(복습) 노트 참조
(3) 문자열 상수, 포인터
문자열 포인터
35
문자열 상수(1/3)
문자열 리터럴은 문자열 리터럴의 주소를 의미한다.
문자열 리터럴은 다른 리터럴과는 달리 메모리에 보관해두고 사용한다.
36
문자열 상수(2/3)
문자열 리터럴은 메모리에 보관하지만 변수처럼 값을 변경할 수는 없다.
37
문자열 상수(3/3)
char*형 변수 p가 문자열 리터럴을 가리킬 때, 문자열 리터럴의 내용은 변경할 수 없지만, char*형 변수에 다른 문자열 리터럴의 주소를 대입할 수는 있다.
38
문자열 리터럴의 의미
39
문자열 리터럴의 주소로 초기화된 포인터
실행 에러 발생
문자열의 대입
문자 배열에는 문자열을 직접 대입할 수 없다.
문자열의 내용을 변경하려면 = 연산자 대신 strcpy 함수를 이용해야 한다.
40
문자열의 비교
문자열의 내용을 비교할 때 == 연산자를 사용하면 안된다.
문자열의 내용을 비교하려면 == 연산자 대신 strcmp 함수를 이용
41
문자열 포인터(1/2)
char*형 변수에는 문자열 리터럴의 주소를 저장할 수도 있고, 문자 배열 의 주소를 저장할 수도 있다.
char*형 변수가 문자열 리터럴를 가리키는지 문자 배열을 가리키는지에 따라, 실행 에러가 발생할 수도 있다.
42
문자열 포인터(2/2)
변경 가능한 문자열을 가리킬 때는 char*형을 사용한다.
변경할 수 없는 문자열을 가리킬 때는 const char*형을 사용한다.
43
const 포인터
포인터 변수를 선언할 때도 const 키워드를 사용할 수 있다.
const가 사용되는 위치에 따라 포인터 변수의 의미가 달라진다.
44
const 키워드가 데이터형 앞에 있는 경우
포인터가 가리키는 변수의 값을 읽어볼 수만 있고 변경할 수 없다.
포인터 변수 자신의 값(주소)은 변경할 수 있다.
45
const 키워드가 포인터 변수명 앞에 있는 경우
포인터 변수 자신의 값(주소)을 변경할 수 없다.
포인터가 가리키는 변수의 값은 변경할 수 있다.
46
const 키워드가 양쪽 모두에 있는 경우
포인터가 가리키는 변수의 값도 변경할 수 없고 포인터 변수 자신의 값(주 소)도 변경할 수 없다.
47
(정리) 포인터의 기초
포인터 : 다른 변수의 주소를 저장하는 변수
포인터의 선언 : 데이터 형, *, 변수명이 필요하다.
int * p;
포인터 사용 : 변수의 주소를 구할 때는 주소 구하기 연산자 &를 이용, 포인터가 가리키는 변수에 접근할 때는 간접 참조 연산자 *를 이용한다.
int *p = &x;
*p = 10;
포인터 사용 시 주의사항 : 포인터 변수는 포인터가 가리키는 변수의 데 이터 형과 일치하도록 선언해야 한다. 포인터가 가리키는 변수가 없을 때는 NULL을 저장한다.
48
(정리) 포인터와 배열의 관계
포인터로서의 배열 : 배열의 이름은 배열의 시작 주소이므로 포인터처럼 사 용할 수 있다.
arr[i]는 *(arr + i)와 같다.
배열의 원소를 가리키는 포인터 : 배열의 원소를 가리키는 포인터는 배열처 럼 사용할 수 있다.
*(p + i)는 p[i]와 같다.
배열과 포인터의 차이점 : 배열의 시작 주소는 변경할 수 없지만 포인터에 저장된 주소는 변경할 수 있다.
49
(정리) 포인터와 문자열
문자열 리터럴 : 문자열 리터럴의 주소를 의미
char *p = "abcde"; p에는 "abcde"의 주소 저장
문자열 포인터 : 문자열 포인터가 문자열 리터럴을 가리킬 때는 문자열의 내 용을 변경할 수 없지만, 문자열 포인터가 문자 배열을 가리킬 때는 문자열의 내용을 변경할 수 있다.
const 포인터 : 포인터를 선언할 때 const의 위치에 따라서 의미가 다르다.
const char *p = str1; p가 가리키는 str1의 내용을 변경할 수 없다.
char * const p = str1; p에 저장된 주소를 변경할 수 없다.
const char * const p = str1; p가 가리키는 문자열도 변경할 수 없고 p도 변경할 수 없다.
50