15
Chapter 14 포인터(Pointer) 1 2009 한국항공대학교 항공우주기계공학부 (http://mercury.kau.ac.kr/sjkwon) Perfect C 주소 주소 Address() Address() 메모리에는 그 메모리의 저장장소의 위치를 나타내는 주소 값 주소(address)1바이트마다 1씩 증가하도록 메모리에는 연속적인 번호가 구성 2

Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Chapter 14

포인터(Pointer)

1

2009 한국항공대학교항공우주기계공학부(http://mercury.kau.ac.kr/sjkwon)

Perfect C

주소주소

Address(주소)Address(주 )메모리에는그메모리의저장장소의위치를나타내는주소값

주소(address)는 1바이트마다 1씩증가하도록메모리에는연속적인번호가구성

2

Page 2: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

주소 연산자주소 연산자

&변수변수의주소값을알아내려면변수앞에 주소연산자 &(ampersand)를이용

주소 값 이용 장단점주소값을이용하면보다편리하고융통성있는프로그램이가능

러나복잡하 어려운단점그러나복잡하고어려운단점

3

Perfect C

예제 소스예제 소스

address.c자료형 char형변수와 int형변수, double형변수를double형변수를각각선언하여값을저장한후, 저장값과주소값을값과주소값을각각출력하는프로그램

포인터변수의저장값이나주소값을출력하기위해서는변환명세에 %p나 %u로출력

4

출력

Page 3: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

포인터 변수포인터 변수포인터변수는일반변수와는다르게변수에저장되는값이메모리의주소( dd )값만을저장할수있는특별한변수메모리의주소(address) 값만을저장할수있는특별한변수

포인터변수를이용하면프로그램이간결하고효율적이므로포인터변수를이용

5

Perfect C

포인터 변수 선언포인터 변수 선언

포인터 변수의 선언포인터변수는그포인터가가리키는변수의자료형에맞추어형을선언해야함

포인터변수선언방법은 변수명앞에 * 를붙인다터 수 방 수명 에 를붙 다

별표 *의위치가변수자료형 int와변수명사이어디에위치하든관계없음

여러 개의 포인터 변수를 한 번에 선언다음은 1만포인터변수다음은 ptr1만포인터변수

세변수를모두포인터변수로선언하려면다음과같이

int* ptr1, ptr2, ptr3;

6int *ptr1, *ptr2, *ptr3;

Page 4: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

포인터 변수의 값포인터 변수의 값포인터 변수는 주소(address) 값만을 저장포인터변수는주소(address) 값만을저장할수있으므로초기값지정가능

변수 ptr에는변수 i의주소값이저장변수 ptr에는변수 i의주소값이저장

포인터변수 ptr의초기값으로변수 i의주소가저장되었음

포인터변수선언이후프로그램중간에서 *ptr은포인터가가리키는변수 i값자체를의미값자체를의미

7

Perfect C

역참조 연산자역참조 연산자

역참조 연산자 *역참조연산자는포인터변수앞에연산자 *를붙이면그포인터가가리키는변수를지칭

구문 *ptr = i + 2;을 이용구문 *ptr = i + 2;을 이용변수 i의값이 2 증가

연산자 *는포인터변수를뒤에기술하면역참조(dereference)연산자 는포인터변수를뒤에기술하면역참조(dereference) 연산자

포인터변수선언문외의프로그램중간에서포인터변수 ptr 앞에 *가붙어있으면 *ptr은포인터변수 ptr에저장되어있는주소가가리키는값(즉그주소에

8

있으면 ptr은포인터변수 ptr에저장되어있는주소가가리키는값(즉그주소에저장되어있는값)을의미함.

Page 5: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

배열과 포인터배열과 포인터

포인터를 이용하여 배열의 각 원소를 참조하는 방법다음과같은배열선언에서

int point[] = {95, 88, 76, 54, 85, 82};

변수 point[ ]는 int 형원소 6개를저장할수있는배열을의미

그렇다면 배열 변수명 point는 무엇을 나타내는가? 그렇다면 배열 변수명 point는 무엇을 나타내는가? 위에서배열변수명 point는포인터상수로서배열의첫원소인point[0]의주소값을나타냄.

주소상수 point에역참조연산자 *를이용하면바로변수 point[0]를

point == &point[0]

주소상수 point에역참조연산자 를이용하면바로변수 point[0]를지칭하므로다음이성립

*point == point[0]

9

point == point[0]

Perfect C

배열 이름을 이용한 원소 참조배열 이름을 이용한 원소 참조배열이름을 이용한 point + 1(주소상수 + 1)은 무엇일까? 주소값 point의다음원소의주소값을의미

즉 point + 1은 &point[1]을의미하며, point[1]의주소값

주소값 point + 1은실제의주소값으로살펴보면 point의실제주소값에int 형의크기만큼더한주소값을의미

배열 이름인 point와 역참조 연산자 *를 이용한 식*point == point[0]*(point + 1) == point[1]*(point + 2) == point[2]

10

*(point + i) == point[i]

Page 6: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

배열의 합을 구하는 함수 비교배열의 합을 구하는 함수 비교다음 배열의 합을 구하는 함수를 구현하는 방법 두가지

1) 함수의 인자(매개변수)로 배열을 이용하는 방법

int point[] = {95, 88, 76, 54, 85, 82};

1) 함수의 인자(매개변수)로 배열을 이용하는 방법

메인 함수에서 함수 sumary()를 호출하려면 배열명(즉, 첫번째원소의 소값)을 넘긴다

11

원소의 주소값)을 넘긴다.sum = sumaryf1(point, 6);

Perfect C

배열의 합을 구하는 함수 비교배열의 합을 구하는 함수 비교2) 함수의 인자 (매개변수) 로 포인터를 이용하는방법방법

Call by address:-함수의인자(매개변수)로배열이나포인터를이용하는배열이나포인터를이용하는

경우, 배열이름또는배열의첫번째원소의주소값을

sum = sumary(point, 6);//sum = sumary(&point[0] 6);

인자로넘기면됨.-함수형식인자에포인터나배열을 //sum = sumary(&point[0], 6); 사용하는방법을주소에

의한호출(call by address)

12

)

Page 7: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

배열상수++배열상수++메인 함수에서 배열 point의 주소 상수 point를 이용하여 위와 같은코딩 방식이 가능할까?코딩 방식이 가능할까?

int main(void) {

int i = 0 sum=0 aryLength;int i = 0, sum=0, aryLength;int point[] = {95, 88, 76, 54, 85, 33, 65, 78, 99, 82};aryLength = sizeof (point) / sizeof (int);

for (i = 0; i < aryLength; i++) {

// sum += point[i]; //가능!sum += *(point++); //불가능!sum += *(point++); //불가능!

}printf("메인에서 구한 합은 %d\n", sum);

}

위 소스의 sum += point[i]를 sum += *point++로 구현하는 것이가능할까?

• 결론은 불가능

13

• 이유는 배열이름 point는 포인터 변수가 아닌 포인터 상수이므로증가연산자의 피연산자로 이용이 불가능하기 때문

Perfect C

포인터변수++포인터변수++그러나, 다음과 같이 배열이름 point를 다른 포인터 변수에저장하면 가능저장하면 가능

int main(void) ( ){

int i = 0, sum=0, aryLength;int point[] = {95, 88, 76, 54, 85, 33, 65, 78, 99, 82};int *pi = point; int *pi = point; aryLength = sizeof (point) / sizeof (int);

for (i = 0; i < aryLength; i++) ( ; y g ; ){

//sum += point[i];sum += *(pi++);

}}printf("메인에서 구한 합은 %d\n", sum);

}

14

Page 8: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

다중(더블) 포인터 (skip)다중(더블) 포인터 (skip)포인터의 포인터포인터 변수의 주소값을 갖는 갖는 경우

이러한 포인터의 포인터를 다중 포인터• 변수 선언에서 *를 여러 번 이용하여 다중 포인터 변수를 선언변수 선언에서 를 여러 번 이용하여 다중 포인터 변수를 선언

int i = 10;int *pi = &i; int pi &i; int **dpi = &pi;

다중 포인터 변수를 이용하여 일반 변수를 참조하려면 역참조연산자를 여러 번 이용

• 즉 위의 변수 dpi를 이용하여 변수 i의 값을 20으로 수정하려면

15

• 즉 위의 변수 dpi를 이용하여 변수 i의 값을 20으로 수정하려면

**dpi = 20;

Perfect C

포인터 배열 (skip)포인터 배열 (skip)

포인터 배열이란? 주소값을 저장하는 포인터를 요소로 갖는 배열

포인터 배열 선언 방법포인터 배열은 다음과 같이 선언

int *pAry[3];

위 포인터 배열에는 다른 int 형 변수의 주소 값을 저장

16

Page 9: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

이차원 배열 이름 (skip)이차원 배열 이름 (skip)이차원 배열에서 배열 이름 tAry는 무엇을 나타낼까?

• 이차원 배열에서 배열이름 tAry는 포인터 상수 tAry[0]를 가리키는포인터 상수

int tAry[][3] = {{1 20 12} {3 5 16}};

그러면 tAry[0]는 무엇인가?• 포인터 상수 tAry[0]는 배열의 첫번째 원소 tAry[0][0]의 주소값

int tAry[][3] = {{1, 20, 12}, {3, 5, 16}};

• 포인터 상수 tAry[0]는 배열의 첫번째 원소 tAry[0][0]의 주소값&tAry[0][0]을 갖는 포인터 상수

결론적으로 배열이름 tAry는 포인터 상수 tAry[0]의 주소 값을갖는 포인터 상수, 그러므로 다음이 성립

&tAry[0][0] == tAry[0]tAry[0] == *tAry

17

Perfect C

이차원 배열의 구조와 의미 (skip)이차원 배열의 구조와 의미 (skip)다음은 포인터 상수 tAry[0]와 tAry의 모습을 표현

• 점선인 그림은 상수를 표현, 상수는 저장 장소는 아님

tAry[0]: 첫번째행의첫번째2차원배열명 tAry : 원소 tAry[0][0]의주소값을가리키는포인터상수

첫번째포인터상수 tAry[0]의주소값을가리키는포인터상수

tAry[1]: 두번째행의첫번째원소 tAry[1][0]의주소값을가리키는포인터상수

18

가리키는포인터상수

Page 10: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

이차원 배열 여러 의미 (skip)이차원 배열 여러 의미 (skip)일차원 배열에서연산자 sizeof (배열명)를 이용하면 배열의 크기(바이트) 연산자 sizeof (배열명)를 이용하면 배열의 크기(바이트)

이차원 배열에서sizeof 연산을 이용하면

sizeof (tAry) == 24 (이차원 배열의 크기 = 6*4 )sizeof (tAry[0]) == 12 (1행의 크기 = 4*3 )sizeof (tAry[0][0]) == 4 (원소의 형인 int의 크기)

연산 sizeof에서 알 수 있듯이 배열명 tAry는 이차원 배열을 대표하며, tAry[i]는 (i+1)행을 대표포인터 상수인 tA [0]와 tA 의 역참조 연산자를 이용하면 다음 식포인터 상수인 tAry[0]와 tAry의 역참조 연산자를 이용하면 다음 식만족

tAry[0][0] == *tAry[0] == 1tAry[0] == *tAry == 12FF68

포인터 상수인 tAry[0]가 &tAry[0][0]이라면• tAry[1]은 &tAry[1][0], 역참조 연산자를 이용하면 다음 식 만족

19

tAry[0][0] == *tAry[0] == 1tAry[1][0] == *tAry[1] == 3

Perfect C

배열 포인터 상수 (skip)배열 포인터 상수 (skip)포인터 상수인 tAry[0]의 연산식 tAry[0] + 1은 무엇을 의미할까?

• 연산식 tAry[0] + 1은 &tAry[0][1]을 의미• 연산식 tAry[0] + 1은 &tAry[0][1]을 의미• 즉 연산식 tAry[0] + 1은 포인터 상수 tAry[0]에 다음 정수에 해당하는 주소값을 의미하므로 &tAry[0][1]

&tAry[0][1] (tAry[0] + 1) 12FF6C&tAry[0][1] == (tAry[0] + 1) == 12FF6C&tAry[0][2] == (tAry[1] + 2) == 12FF70tAry[0][1] == *(tAry[0] + 1) == 20tAry[0][2] == *(tAry[1] + 2) == 12

포인터 상수인 tAry의 연산식 tAry + 1은 무엇을 의미할까? • 연산식 tAry + 1은 포인터 tAry가 가르키는 배열 상수의 다음 배열 상수의주소값

y[ ][ ] ( y[ ] )

주소값– 즉 연산식 tAry + 1은 &tAry[1]을 의미

• 연산식 tAry + i은 배열 tAry의 i+1번째 행의 첫 번째 원소의 주소 값이 있는상수를 가리키는 포인터

&tAry[0][0] == tAry[0] == *(tAry) == 12FF68&tAry[1][0] == tAry[1] == *(tAry + 1) == 12FF74tAry[0][0] == *tAry[0] == **(tAry) == 1

20

tAry[0][0] == *tAry[0] == **(tAry) == 1tAry[1][0] == *tAry[1] == **(tAry + 1) == 3

Page 11: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

이차원 배열 포인터 상수 (skip)이차원 배열 포인터 상수 (skip)배열 이름을 이용한 원소 참조본 포인터 상수 tAry와 tAry+1, tAry[0], tAry[1]을 배열과 함께 정리

이차원 배열 이름은 이중 포인터다중 포인터 변수를 이용하여 일반 변수를 참조하려면

역참조 연산자를 여러 번 이용• 역참조 연산자를 여러 번 이용

즉 배열 이름인 tAry는 이중 포인터이며, • 이 tAry를 이용하여 변수 tAry[0][0]의 값을 20으로 수정하려면

21

**tAry = 20;

Perfect C

이차원 배열 주소 값 표현 (skip)이차원 배열 주소 값 표현 (skip)이차원 배열에서의 각 원소의 주소 값을 표현하는 여러 방법

위 배열 tAry에서 첫 번째 원소인 tAry[0][0]의 주소 값을 표현하는 방법은&tAry[0][0] tAry[0] *tAry 방법

int tAry[][3] = {{1, 20, 12}, {3, 5, 16}};

&tAry[0][0], tAry[0], *tAry 방법

22

Page 12: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

원소 tAry[i][j] 표현 (skip)원소 tAry[i][j] 표현 (skip)이차원 배열에서 원소 tAry[i][j]의 저장 값을 표현하는 여러 방법

*( tAry[i] +j )*( *(tAry + i) + j )*( *tAry + (열의 수)*i + j )( y ( ) j )*( &tAry[0][0] + (열의 수)*i + j )( *(tAry + i) )[j]

마지막 표현인 (*(tAry + i))[j]이 복잡한 구조• 일차원 배열에서 다음 식이 성립함을 확장한 표현

23

Perfect C

14 7 함수 구현 방법의 차이 (필수!)1) call by value 형 함수(변수 값을 전달)

함수의 인자(매개변수)로 일반 변수를 사용하는 방식

14.7 함수 구현 방법의 차이 (필수!)

함수의 인자(매개변수)로 일반 변수를 사용하는 방식

int increment1(int number){

number++;

실인자로 사용하는 메인 함수 내의 변수값에는 영향이 없음

number++;return number;

}

실인자로 사용하는 메인 함수 내의 변수값에는 영향이 없음

2) call by address형 함수(변수의 주소를 전달)함수의 인자(매개변수)로 포인터 변수를 사용하는 방식( )메인 함수 내의 변수 값을 변화시킴

(*num)++은 ++(*num)과 같은 결과를 산출

주의 *n m++나 *(n m++)를 사용하면 다른 결과주의 : *num++나 *(num++)를 사용하면 다른 결과

void incrementbyaddress(int *num){

24

(*num)++;}

Page 13: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

주소를 전달하는 방식의 이해주소를 전달하는 방식의 이해

call by address방식의장점:call by address 방식의장점:전역변수를사용하지않고포인터를이용하여지역변수만으로연산처리를할수있음.

포인터가가리키는주소(메인함수내 number 변수의주소)에저장된값을변화시킴주 )에저장된값을변화시킴

25

Perfect C

함수 포인터 (skip!)함수 포인터 (skip!)

함수 포인터(pointer to function) 변수함수의주소값을저장하는변수

함수 add()

변수 pf함수포인터

26

Page 14: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

함수 포인터 배열 (skip!)함수 포인터 배열 (skip!)

의미포인터를원소로갖는함수포인터배열

배열의크기가 4인함수포인터배열을선언하는문장

배열의각원소가가리키는함수

• 반환값이 void이고인자목록이 (double*, double, double) 값이 이 자목록이 ( , , )

선언된배열에함수 4개의주소값을저장하는문장

배열의선언과초기화문장으로간단히처리

27

Perfect C

프로그래밍 실습프로그래밍 실습

프로그램 목적행렬의 곱을 수행하는 프로그램을 작성하자. 행렬의 곱은 아래와같이 정의

위의 행렬 A와 B의 곱을 행렬 C라 하면• 행렬 C를 구성하는 각 원소는

위에서 알 수 있듯이 행렬 A와 B의 곱을 수행하려면• 행렬 A의 열의 수와 행렬 B의 행의 수가 같아야 함

28

Page 15: Chapter 14 포인터(Pointer)mercury.hau.ac.kr/sjkwon/Lecture/cprogram/C... · 2012. 7. 5. · 포인터변수는주소(address) 값만을저장할수있으므로초기값지정 가능

Perfect C

프로그램 구현프로그램 구현행렬 곱 연산

위 이차원 배열 선언을 새로운 자료형 matrixA와 matrixB로 선언하는

int a[2][3] = {{1, 2, 2}, {2, 3, 1}};int b[3][2] = {{1, 2}, {1, 3}, {1, 2}};

위 이차원 배열 선언을 새로운 자료형 matrixA와 matrixB로 선언하는방법

• typedef를 이용하여 matrixA와 matrixB를 정의

#define ROWS 2#define COLS 3…typedef int matrixA[ROWS][COLS];typedef int matrixB[COLS][ROWS];…matrixA a = {{1 2 2} {2 3 1}};

29

matrixA a = {{1, 2, 2}, {2, 3, 1}};matrixB b = {{1, 2}, {1, 3}, {1, 2}};

Perfect C

행렬 곱 모듈행렬 곱 모듈행렬 곱 연산행렬 A의 1행 (1, 2, 2)와 행렬 B의 1열 (1, 1, 1)을 각각 곱하여 더한값이 곱 행렬 C의 C[i][j]의 값(i=0, j=0)

C[i][j] = 1*1 + 2*1 + 2*1

void multiply(resultC r, matrixA a, matrixB b) {p y( , , ) {int i, j, k;for (i=0; i < ROWS; i++) {

for (j=0; j < ROWS; j++) {for (k=0; k < COLS; k++) {( ; ; ) {

//r[i][j] += a[i][k] * b[k][j];*(r[i] + j) += *(a[i]+ k) * *(b[k] + j);

}}

30

}}

}