SlideShare une entreprise Scribd logo
1  sur  74
Télécharger pour lire hors ligne
배열과 포인터

Software Engineering Lab
김영기 책임
resious@gmail.com
Contents

1.

포인터

2.

배열

3.

배열과 포인터

4.

2차원 배열과 포인터 배열

5.

응용 포인터
포인터란 무엇인가?
 프로그램이 기억공간을 참조하는 2가지 방법
 1. 변수명을 사용하는 방법
이 4byte의 기억 공간은
지금부터 var라는
이름으로 사용이 가능하다.

변수 선언

int var ;

var

메모리에 기억 공간이 할당된다.

변수명으로 기억공간을 사용한다.
var = 10;
value = var;

할당된 기억 공간에 10을 저장한다.
var 값을 다른 기억 공간에 복사한다.
포인터란 무엇인가?
 프로그램이 기억공간을 참조하는 2가지 방법
 2. 변수가 할당된 메모리의 실제 주소(포인터)를 사용하는 방법

int var ;

변수 선언

메모리에 4byte의 기억 공간이 할당된다.

var

99

100

101

포인터

102

103

104

105

106

107

108

시작 주소값이다.

 포인터를 사용하여 변수명과 같이 할당된 기억 공간에 값을 저장하거나 저장된 값을 꺼내어 쓸 수 있다.
주소 연산자 –

포인터를 구하자.

 프로그램에서 변수명은 알 수 있지만 그 변수의 실제 주소값은 알 수 없다.
따라서, 포인터를 사용하기 위해서는 먼저 그 주소값을 알아내는 과정이 필요하다.

 특정 변수의 포인터를 구하기 위해서는 주소 연산자(&)를 사용한다.

& var
주소 연산자

포인터를 구해준다. !

변수명

Sample Code
char ch;
int in;
double dbl;

// char형 변수 선언, 크기 1byte
// int형 변수 선언, 크기 4byte
// double형 변수 선언, 크기 8byte

printf(“ch의 포인터 : %un”, &ch);
printf(“in의 포인터 : %un”, &in);
printf(“dbl의 포인터 : %un”, &dbl);

결과를 Memory Map으로
표시하여 보자.
주소 연산자 –

포인터를 구하자

Sample Code 실행 결과 분석 예
:
..052
..051
..050
..049
..048
..047
..046
..045
..044
..043
..042
..041
..040
..039
..038
..037
..036

ch
in

포인터에는 자신이 어떤 자료형으로 부터
만들어졌는지에 대한 정보를 가지고 있다.
포인터

dbl

주소값

정보

&ch

..052

char형 기억 공간의 주소값이다.

&in

..048

int형 기억 공간의 시작 주소값이다.

&db

..040

double형 기억 공간의 시작 주소값이다.

 포인터의 크기는 자료형에 상관없이 동일한가?
참조 연산자 – 포인터를 사용하자.
 포인터를 통해서 기억 공간을 사용하기 위해서는 참조 연산자(*)를 사용한다.

* &var
참조 연산자

포인터가 가리키는
기억 공간을 사용한다. !

포인터

참조 연산자로 포인터를 사용하는 방법
 포인터가 가리키는 기억 공간을 사용한다.

 포인터가 가리키는 기억 공간의 값을 사용한다.

Sample Code
int a = 10, b = 20;
*&a = *&b
printf(“a의 값 : %dn”, a);

기억 공간을 사용

// 변수 b에 저장된 값을 변수 a의 기억 공간에 기억

*&a = *&b ;

기억 공간의 값을 사용
포인터 변수 – 포인터를 저장하자.
포인터의 저장
int a;
int ap;
ap = &a;

// 포인터를 구할 변수
// 포인터를 저정할 변수
// a의 포인터를 구하여 ap에 저장한다.

변수 a

변수 ap

99

100

101

102

103

104

105

106

 error C2440 : ‘=‘ : cannot convert from ‘int *’ to ‘int’

107

108

109

포인터에는 자료형에
대한 정보가 함께 있다.

포인터 변수

int *ap
가리키는 자료형을
앞에 붙여준다.

포인터 변수 ap는 int형 변수의
시작 주소값만을 저장할 수 있다.

변수명 앞에 별표를 붙여
포인터 변수임을 표시한다.
포인터 변수 – 포인터를 저장하자.
포인터의 저장
int a;
int *ap;
ap = &a;

// 포인터를 구할 변수
// 포인터를 저장할 변수
// a의 포인터를 구하여 포인터 변수 ap에 저장한다.
ap가 포인터를 저장하면

100

100

가리킨다.

포인터 변수 ap

int 형 변수 a

Sample Code
int a ;
int *ap = &a;
*ap = 10;

// int 형 변수 선언
// 포인터 변수 선언과 동시에 초기화
// 포인터 변수가 가리키는 공간에 10 저장

printf(“변수명을 사용한 출력 : %dn”, a);
printf(“포인터 변수를 사용한 출력 : %dn”, *ap);
포인터는 왜 필요한가? (1)
함수들은 독립된 기억 공간을 가진다.

#include <stdio.h>

main 함수영역

void assign();
int main()
{
int var = 0;

}

assign 함수영역

var

var ??

0

assign();
printf(“ 함수 호출 후 var에 저장된 값 : %d n”, var);
return 0;

void assign()
{
var = 100;
}
 error C2065 : ‘var‘ : undeclared identifier

void assign()
{
int var ;
var = 100;
}

결과는 ?
포인터는 왜 필요한가? (2)
포인터로 다른 함수의 기억공간을 사용한다.
main 함수영역
#include <stdio.h>
void assign(int *);
int main()
{
int var = 0;

}

assign 함수영역

포인터를 넘겨준다.

200 var
0

200

Ip가 포인터가 저장하여 var를 가리킨다.
(var 변수의 시작 주소값은 200)

assign(&var);
printf(“ 함수 호출 후 var에 저장된 값 : %d n”, var);
return 0;

void assign(int *ip)
{
*ip = 100;
}

ip

void assign()
{
return 100;
}

결과는 동일한가 ?
변수가 여러 개일 경우는?
포인터는 왜 필요한가? (3)
두 변수의 값을 서로 바꾸는 함수를 만들어 보도록 하자.
 void exchange(int *, int *) ;
#include <stdio.h>
int main()
{
int var1 = 10, var2 = 20;

}

printf(“바꾸기 전 : %d , %d n”, var1, var2);
exchange(&var1, &var2);
printf(“바꾼 후 : %d, %d n”, var1, var2);
return 0;

void exchange(int *cp, int *mp)
{
// 구현하시오..
}

 void exhange(int c, int m)로
구현할 경우 값이 바뀌는가?
바뀌지 않는 이유는 ?
포인터와 포인터 변수의 크기
Sample Code
char ch;
int in;
double dbl;

printf(“char 형 변수의 포인터 크기 : %d n”, sizeof(&ch);
printf(“ int 형 변수의 포인터 크기 : %d n”, sizeof(&int);
printf(“ double 형 변수의 포인터 크기 : %d n”

가리키는 자료형의 크기는
달라도 모든 포인터 변수의
크기는 4 바이트이다.

ch (1byte)
char 형 포인터 변수

in (4byte)
int 형 포인터 변수

dbl (8byte)
double 형 포인터 변수
포인터와 포인터 변수의 형변환
Sample Code
int *ip;
double dbl=6.4;
ip = &dbl;

// int 형 변수를 가리키는 포인터 변수
// double 형 변수
// double형 변수의 포인터를 int형 포인터 변수에 대입

 error C2440 : ‘=‘ : cannot convert from ‘double * ‘ to ‘int *’
int *ip;
double dbl=6.4;
ip = (int *) &dbl;

//(double *)를 (int *)로 강제 형변환한다.
Contents

1.

포인터

2.

배열

3.

배열과 포인터

4.

2차원 배열과 포인터 배열

5.

응용 포인터
배열이란?
배열이란
 동일한 자료형으로 된 기억 장소들의 모임
 배열을 사용하는 목적은 기억 장소의 일괄 처리에 있다.

배열의 선언

int ages[5];
배열의 형태

배열의 이름

변수의 갯수

배열 ages
블록은 하나의 int형 변수

int

int

int

int

int

 다섯 개의 변수가 연속으로 이어짐
배열의 사용
배열의 사용
 배열내의 각각에 기억 공간은 별도로 붙여진 이름이 없다.
따라서 개별적인 이름이 아닌 배열에서 차지하는 위치를 이용한다.
 배열을 구성하는 기억 공간들을 배열의 요소(element)라고 하고, 각 요소가 배열에서 차지하는
위치를 첨자(index)라고 한다.

 기억 공간의 사용 : 배열명 + 배열에서의 위치

배열 요소의 표현

배열명[첨자]

첫번째 배열 요소
두번째 배열 요소

배열 ages

ages[0]

ages[1]

세번째 배열 요소

ages[2]

네번째 배열 요소

ages[3]

다섯번째 배열 요소

ages[4]
* 배열의 첨자는 0부터 시작한다.
배열의 사용
배열요소의 표현은 하나의 변수명과 똑같이 사용된다.
score[3]

하나의 변수명과 같다.
따라서 일반 변수와 같이 사용한다. Ex) scanf(“%d”, &ages[3]);

첨자는 0부터 시작하므로 최대값이 배열 요소의 개수보다 하나 작다.

ages[5]

0

1

2

다섯개만 쓰기로 정의

3

4

score[5] = 34;

5
허락되지 않은
기억 공간을
사용하게 된다.
배열과 반복문
 모든 배열요소는 배열명이 같고 첨자가 하나씩 증가하는 규칙을 가지고 있기 때문에

반복문을 이용하면 각 배열 요소를 간단하게 처리할 수 있다.
i=0일때 : scanf(“%d”, &ages[0]);

for(i=0; i<5; i++)
scanf(“%d”, &ages[0]);
}

i=1 일때 : scanf(“%d”, &ages[1]);
i=2 일때 : scanf(“%d”, &ages[2]);
i=3 일때 : scanf(“%d”, &ages[3]);
i=4 일때 : scanf(“%d”, &ages[4]);

배열과 반복문울 이용하여 다섯 명의 나이를 입력 받고,
평균을 구하는 프로그램을 작성하여 보자. (시간 15분)
배열의 초기화
배열을 선언하면 그 안에 쓰레기값이 존재하게 된다.
int nums[5];
int i, total =0;
for(i=0; i<5; i++)
total+=nums[i]
}
printf(“total : %dn”, total);

배열 nums
?

?

?

?

?

+

출력 결과는 ?
결과가 시스템의 상황에 따라 달라진다.

배열은 선언과 동시에 초기화 하는 것이 좋다.

int nums[5] = {1,3,5,15,30};
1
순서대로
저장된다.

3

7

15

30

nums[0] nums[1] nums[2] nums[3] nums[4]
배열의 초기화
배열의 초기화 시 편리한 자동 기능
 배열 요소의 수보다 초기화 값이 적으면 남은 공간은 0으로 채워진다.

배열 nums

int nums[5] = {1,3};
1

3

0

0

0

자동으로 0으로 채워진다.

 배열 선언시 초기화를 하면 배열 요소를 생략할 수 있다.

배열 nums

int nums[] = {1,3,7,15,30};
1
숫자 생략가능

3

7

15

30

자동으로 다섯 개의 기억 공간이 할당된다.
배열의 크기
배열의 크기를 계산해야 하는 경우가 많이 생긴다.
 배열의 크기를 자동으로 계산하는 방법은 ?

전체 20 bytes

int nums[5];

int

int

int

int

int

4byte

배열 요소의 개수 = sizeof(nums) / sizeof(nums[0])
배열 전체의 크기

배열 요소 하나의 크기
배열 예제
int
int
int
int

nums[] = {1,2,3,4,5} ;
total = 0;
i;
size ;

// 배열의 초기화
// 합을 저장한 누적 변수
// 반복 제어 변수
// 배열 요소의 개수를 저장할 변수

size = sizeof(nums) / sizeof(nums[0]);
for(i=0; i<size; i++) {
total += nums[i];
}
 배열 요소를 각각 초기화한 경우와 비교해 보자.
 size를 사용하지 않은 경우와 비교해 보자.
문자 배열과 null
문자 배열의 선언과 사용

char word[4];

배열명 word

char

char

char

4byte

word[0] = ‘L’;
word[1]

char

= ‘o’;

word[2] = ‘v’;

‘L’

‘o’

‘v’

‘e’

word[3] = ‘e’;

출력은?
for(i=0; i<4; i++)
print(“%c”, word[i]);
}

같은 의미

printf(“%s”, word);
문자 배열과 null
배열의 끝 ?
char word[50]; // 배열 선언

char word[50]; // 배열 선언

word[0] = ‘L’;
word[1] = ‘o’;
word[2] = ‘v’;
word[3] = ‘e’;
word[4] = ‘0’;
printf(“%s”, word); //문자열 출력

word[0] = ‘L’;
word[1] = ‘o’;
word[2] = ‘v’;
word[3] = ‘e’;
printf(“%s”, word); //문자열 출력

word

L

o

v

e

?

?

?

?

여기에 있는 것도 출력할 문자열들인가?

word

L

o

v

e

0

?

?

여기까지가 출력한 문자열이군…

?
scanf 함수를 이용한 문자열 입력
char word[50];

char word[4];

printf(“Input String is : “);
printf(“%s”, word);

printf(“Input String is : “);
printf(“%s”, word);

printf(“input string : “);
scanf(“%s”, word);

word

L

i

printf(“input string : “);
scanf(“%s”, word);

n

u

x

/0

L

i

n

?

마지막에 널 문자를 넣어 문자열을 완성한다.

할당 영역

word

?

u

x

/0

?

이웃한 메모리 영역을 침범하게 된다.

?
문자배열의 초기화
문자 배열 초기화  문자열 상수의 대입은 선언과 동시에 초기화하는 경우만 가능

char str[10] = {‘d’, ‘r’, ‘e’, ‘a’, ‘m’, ‘0’};
d

r

e

a

초기화한 문자열

m

0

0

0

0

남는 배열 요소

일반 변수
int val = 10;
val = 20;

// 변수 선언과 동시에 초기화 (0)
//초기화 된 이후 다른 값을 저장 (0)

문자 배열
char str[80] = “dream” ;
str = “world“ ;

// 변수 선언과 동시에 초기화 (0)
//초기화 된 이후 다른 값을 저장 (x)

0
문자배열의 초기화
문자 배열 값 지정

w

o

r

l

d

0

0

0

0

0

한 byte 씩 모두 복사해야 한다.

d

r

e

a

m

0

초기화 시 배열 요소의 개수 생략

char str[] = “I love you”;
 몇 byte의 기억 공간이 잡힐까?

0

0

0

0
Contents

1.

포인터

2.

배열

3.

배열과 포인터

4.

2차원 배열과 포인터 배열

5.

응용 포인터
포인터로 배열요소의 참조
배열은 많은 양의 데이터를 효율적으로 처리할 수 있다.
 반복문의 사용

배열은 같은 형태의 변수가 연속된 메모리 공간에 할당된다.
 첫번째 배열요소의 위치를 알면 나머지도 알 수 있다.

x의 값을 알면 나머지는 자동으로 구해진다.

x

int ary[5];

int
ary[0]

x+4

int
ary[1]

x+8

int
ary[2]

x+12

int
ary[3]

x+16

int
ary[4]
포인터로 배열요소의 참조 (예제)
Example Code
int ary[5] = {10, 20, 30, 40, 50};
int *ap;
ap=&ary[0];
printf(“ 1st 배열 요소의 주소값 : %u n”, ap);
printf(“ 1st 배열 요소의 값 : %d n”, *ap);
ap=&ary[0]+4 ;
printf(“ 2nd 배열 요소의 주소값 : %u n”, ap);
printf(“ 2nd 배열 요소의 값 : %d n”, *ap);
출력 결과
1st 배열 요소의 주소값 : 1245036
1st 배열 요소의 값 : 10
2nd 배열 요소의 주소값 : 1245052
2nd 배열 요소의 값 : 50

36

// 첫 번째 배열 요소의 포인터를 포인터 변수에 저장
// 첫 번째 요소의 주소값 출력
// 배열 요소에 저장된 값 출력
// 두 번째 배열 요소의 포인터를 구한다.
// 첫 번째 요소의 주소값 출력
// 배열 요소에 저장된 값 출력

52 ??

10

20

30

40

50

ary[0]

ary[1]

ary[2]

ary[3]

ary[4]
포인터로 배열요소의 참조 (예제 계속)
왜 원하지 않는 결과가 나왔는가?
 포인터는 어떤 자료형으로 부터 계산되었는지에 대한 정보를 가지고 있다.

따라서 포인터에 정수값을 더할 때는 포인터가 가리키는 자료형의 크기가 곱해지게 된다.

포인터+정수값

포인터 + (정수값+포인터가 가리키는 자료형의 크기)
&ary[0]+4=&ary[0]+(4*sizeof(int)) = 36+16=52

&ary[0] + 0 = 36

10

ary[0]

&ary[0] + 1 = 40

20

ary[1]

&ary[0] + 2 = 44

30

ary[2]

&ary[0] + 3 = 48

40

ary[3]

50

ary[4]

포인터가 가리키는 기억 공간 참조

&ary[0] + 4 = 52

포인터는 4바이트씩 증가한다.

*(&ary[0]+i)
각 배열요소를 가르키는 포인터를 차례로 계산

for(i=0; i<5; i++){
printf(“%dn”, *(ary[0]+i));
}
배열명은 포인터!
C언어는 첫 번째 배열요소의 포인터를 쉽게 사용할 수 있도록 배열명으로 표현한다.
 배열명은 첫 번째 배열 요소를 가리키는 포인터이다.
첫번재 기억 공간의 시작주소값
같다.

배열명

ary

36

10
ary[0]

44

48

52

20

30

40

50

ary[1]

ary[2]

ary[3]

ary[4]

포인터표현

배열표현
ary[0]
ary[1]
ary[2]
ary[3]
ary[4]

40

==

*(ary+0)
*(ary+1)
*(ary+2)
*(ary+3)
*(ary+4)

for(i=0; i<5; i++){
printf(“%dn”, *(ary+i));
}
포인터 변수로 배열 요소 참조
int *ap = ary ; 배열명을 포인터 변수에 저장
36

36
포인터변수 ap

40

44

48

52

10

ary ==

20

30

40

50

ary[1]

ary[2]

ary[3]

ary[4]

ary[0]

*(ap + 1)  40번지에 있는 배열 요소를 참조한다.
36+(1*sizeof(int)) = 36+4=40번지

int ary[5] = {10, 20, 30, 40, 50};
int *ap = ary;
int i;
for(i=0; i<5; i++) {
printf(“%5d”, *(ap+1));
}

배열표현 포인터표현
ary[0]
ary[1]
ary[2]
ary[3]
ary[4]

==

*(ap+0)
*(ap+1)
*(ap+2)
*(ap+3)
*(ap+4)

int ary[5] = {10, 20, 30, 40, 50};
int *ap = ary;
int i;
for(i=0; i<5; i++) {
printf(“%5d”, ap[i]);
}
배열 요소 참조 방법 정리
배열요소의 참조 방법
 1. 배열명을 사용한 배열 표현
 2. 배열명을 사용한 포인터 표현
 3. 배열명을 저장한 포인터 변수를 사용한 포인터 표현
 4. 배열명을 저장한 포인터 변수를 사용한 배열 표현
ary ==

36
포인터변수 ap

36

10
(1) ary[0]

40

44

48

52

20

30

40

50

ary[1]

ary[2]

ary[3]

ary[4]

(2) *(ary+0) *(ary+1) *(ary+2) *(ary+3) *(ary+4)
(3) *(ap+0)
(4) *(ap[0])

*(ap+1)

*(ap+2)

*(ap+3)

*(ap+4)

*(ap[1])

*(ap[2])

*(ap[3])

*(ap[4])

모두 첫번째 배열 요소를 참조하는 표현식이다.
배열명은 포인터 변수가 아니다.
포인터  주소값을 나타낸다.
 상수이므로 변경할 수 없다.

ary = ary + 2;
ary ++ ;

배열명은 변수가 아니므로 자신의 값을
바꿀 수 없다.

포인터 변수
 변수이므로 가르키는 대상을 바꿀 수 있다.

포인터

오직 하나만..

포인터 변수

많을수록 ..
배열 처리 함수 – 값 출력
모든 배열요소는 포인터로 참조할 수 있으므로 배열을 처리하는데 필요한 것은 배열에

있는 데이터가 아니라, 배열이 메모리의 어디에 있는지에 대한 주소값이면 충분하다.
 int ary[5] = {10, 20, 30, 40, 50};의 모든 값을 출력하는 함수를 만들어 보자.
1. void ary_prn(int *ap)
{
int i;
for(i=0; i<5; i++){
printf(“%d”, *(ap+i));
}
}
 호환성 있는 함수를 만들기 위해서는 배열명과 배열요소의 개수를 함께 전달인자로 사용해야 한다.
// ary_prn(ary, sizeof(ary)/sizeof(ary[0]));
2. void ary_print(int *ap, int an)
{
int i;
for(i=0; i<an; i++){
printf(“%5d”, ap[i]);
}
}
배열 처리 함수 – 값 입력
배열의 위치를 알아야 한다.
 int ary[5] ;의 값을 입력하는 함수를 만들어 보자.
1.

void ary_input(int *ap)
{
int i;
for(i=0; i<5; i++){
scanf(“%d”, ap+1);
}
}

 printf는 배열 요소에 저장된 값을 필요로 하므로 참조 연산자를 사용했지만,
scanf는 참조연산자를 사용할 필요가 없다.
Contents

1.

포인터

2.

배열

3.

배열과 포인터

4.

2차원 배열과 포인터 배열

5.

응용 포인터
2차원 배열의 선언과 초기화
1차원 배열  복잡하고 많은 데이터 처리에 한계
배열을 하나의 요소로 하는 또 다른 배열  2차원 배열

첫 번째 배열 요소

두 번째 배열 요소

+
배열 요소가 세 개인 새로운 배열.

세 번째 배열 요소
2차원 배열의 선언과 초기화
2차원 배열의 선언

배열의 형태

int score[3][4];
배열의 이름

int 형 변수 4개짜리 1차원 배열이
2차원 배열의 배열 요소가 된다.

변수요소의 갯수

부분 배열 : 2차원 배열은 논리적으로 행렬로 표현된다.
부분배열명
첫번째 부분배열

ages[0]

두번째 부분배열

ages[1]

세번째 부분배열

ages[2]

2차원 배열 SCORE
2차원 배열의 선언과 초기화
2차원 배열 요소의 참조

score[0][0] = 10 ;

첫번째 부분 배열의 첫번째 배열 요소에 10을 저장한다.

score[0]
score[0][0]
score[0][1]

score[0][2]
score[0][3]
2차원 배열의 선언과 초기화
2차원 배열의 처리  2중 for 문
int score[3][4];
int i, j;
i는 0부터 2까지 세 번 반복된다.

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

학생 한 명의 점수를
입력 받는 과정

printf(“네 과목의 점수를 입력하세요 : “);
for( j=0 ; j<4 ; j++) {
scanf(“%d”, &score[i][j]);

}

부분배열명의 첨자를 제어변수로 사용하여
새로운 부분 배열에 점수를 입력 받도록 한다.

}
j 반복문

i 반복문

j가 0 일때

j가 1 일때

j가 2 일때

j가 3 일때

i가 0 일때

score[0][0]

score[0][1]

score[0][2]

score[0][3]

i가 1 일때

score[1][0]

score[1][1]

score[1][2]

score[1][3]

i가 2 일때

score[2][0]

score[2][1]

score[2][2]

score[2][3]
2차원 배열의 선언과 초기화
예제 – 3명의 학생에 대한 4과목 점수 처리 예제
#include <stdio.h>

int main()
{
int score[3][4];
int i, j;
int tot;
double avg;
for(i=0; i<3; i++){
printf(“네 과목의 점수를 입력하시오 : “);
for( j=0; j<4; j++){
scanf(“%d ”, &score[i][j]);
}
}
for(i=0; i<3; i++){
tot=0;
for( j=0; j<4; j++){
tot+=score[i][j];
}
avg=tot/4.0;
//한 명의 총점을 모두 누적한 후에 평균 계산
printf(“총점 : %d, 평균 : %21fn”, tot, avg); //총점, 평균 출력

}

}
return 0;
2차원 배열의 선언과 초기화
2차원 배열의 초기화 – case 1

int nums[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int nums[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
1

3

4

5

6

7

8

9

2차원 배열 nums

2
10

11

12

//논리적 구조에 맞게 행을 구분

첫번째 행이 초기화 된 후에
두 번째, 세 번째 행이 차례로
초기화 된다.

2차원 배열의 초기화 – case 2
 기억 공간보다 초기화 값이 적은 경우 남은 공간은 0으로 초기화 된다.

int nums[3][4]={1,2,3,4,5,6};
1
2차원 배열 nums

2

3

4

5

6

0

0

0

0

0

0

 첫 번째 기억 공간만 초기화 하면
모든 기억 공간이 0으로 초기화 된다.

int nums[100][200]={0} ;
// 모든 공간이 0으로 초기화
2차원 배열의 선언과 초기화
2차원 배열의 초기화 – case 3

int nums[3][4]={{1},{5,6},{9,10,11}};
0

0

0

5

6

0

0

9

2차원 배열 nums

1

10

11

0

2차원 배열의 초기화 – case 4

int nums[][4]={{1},{2,3},{4,5,6}};
행의 수가 세 개
행 첨자 생략

열 첨자 생략 불가능

2차원 배열 nums

1

0

0

0

2

3

0

0

4

5

6

0

3행 4열의 기억 공간 할당
2차원 배열의 선언과 초기화
2차원 배열의 초기화 – case 5

int nums[][4]={1,2,3,4,5,6};
첫번째 행 초기값

2차원 배열 nums

두 번째 행 초기값

1

2

3

4

5

6

0

0

2행 4열의 기억 공간 할당
2차원 문자 배열
각 행이 하나의 문자열을 저장한다.

char animal[5][20];

//5개의 문자열을 저장할 2차원 문자배열

부분배열명
animal[0]
animal[1]
animal[2]
animal[3]
animal[4]

Scanf(“%s”, animal[4]);
전체가 배열명

//gets함수를 사용하면 gets(animal[4]);

char animal[5][20];
int i;

//2차원 문자 배열 선언
//반복 제어 문자

for(i=0; i<5; i++);{
printf (“문자열을 입력하세요 : ”);
scanf(“%s”, animal[i]);
//i값이 변하면서 각 부분배열명이 된다.
}
2차원 문자 배열의 초기화
2차원 문자 배열의 초기화 case 1
char animal[5][10] = {{‘c’,’a’,’t’,‘0’}, {‘h’,’o’,’r’,’s’,’e’,’0’},
{‘d’,’o’,’g’,’0’}, {‘t’,’I’,’g’,’e’,’r’,’0’},
{‘e’,’l’,’e’,’p’,’h’,’a’,’n’,’t’,’0’}};
2차원 문자 배열의 초기화 case 2
char str[10] = “cat” ;  하나의 문자열 상수는 1차원 문자 배열을 초기화 할 수 있다.

char animal[5][10] = {“cat”, ”horse”, “dog”, “tiger”, “elephant”};

c a t

0 0 0 0 0 0 0

h o r s e
d o g

0 0 0 0 0

0 0 0 0 0 0 0

t i g e r

0 0 0 0 0

e l e p h a n t

0 0
포인터 배열
포인터 변수를 통한 문자열 처리
char *cp = “tiger”; //포인터를 포인터변수에 저장한다.
printf (“%s”, cp);

//포인터변수로 문자열을 출력한다.

배열의 선언

char* ptr_ary[5];
배열요소의 자료형

배열의 이름

변수의 갯수

char * char * char * char * char *
모든 배열 요소가 포인터 변수이다.

ptr_ary[2] = “tiger” ; // 세 번째 배열 요소에 문자열 상수를 대입한다.
printf(“%s”, ptr_ary[2]); // 배열요소를 참조하여 문자열을 출력한다.
포인터 배열
예제
#include <stdio.h>
int main()
{
char * ptr_ary[5];
int i;

// 포인터 배열 선언

ptr_ary[0]=“dog”;
ptr_ary[1]=“elephant”;
ptr_ary[2]=“horse”;
ptr_ary[3]=“tiger”;
ptr_ary[4]=“lion”;

}

for(i=0; i<5 ; i++) {
printf(“%sn”, ptr_ary[i]);
}
return 0;

ptr_ary
ptr_ary[0]

d o g

ptr_ary[1]

e l e p h a n t

ptr_ary[2]

h o r s e

0

ptr_ary[3]

t i g e r

0

ptr_ary[4]

l

스택 영역

0

i o n

0

0

데이터의변경이 불가능한 메모리 영역
포인터 배열의 초기화
포인터 배열의 초기화 방법

char animal[5][10]
char *ptr_ary[5]

= {“dog”, “elephant”, “horse”, “tiger”, “lion”};
= {“dog”, “elephant”, “horse”, “tiger”, “lion”};

배열의 형태에 따라 문자열을 복사하거나
포인터를 저장한다.

초기화 방법은 같다..

포인터 배열은 2차원 배열인가?
 포인터 배열은 첨자를 하나 사용하는 1차원 배열이다. 그러나 배열 요소가 포인터 변수이므로
2차원 배열처럼 활용하는 것이 가능하다.
포인터 배열 사용 예제
#include <stdio.h>
int main()
{
int ary1 [4] = {1, 2, 3, 4} ;
int ary2 [4] = {11, 12, 13, 14} ;
int ary3 [4] = {21, 22, 23, 24};
int *ptr_ary[3] = {ary1, ary2, ary3} ;
int i, j;

}

for(i=0; i<3; i++) {
for( j=0; j<4; j++) {
printf(“%5d”, ptr_ary[i],[j]);
}
}
return 0;

ary1 == 100

ptr_ary
500

[출력 결과]
1
2
3
11 12 13
21 22 23

4
14
24

504
508

100
200
300

104

1
ary2 == 200

11
ary3 == 300

21

108

2
204

3
208

12
304

22

112

4
212

13
308

14

312

23

24
포인터 배열 사용 예제 (계속)
ptr_ary[2][2]가 어떻게 23의 값을 참조할 수 있는가?
ptr_ary[2][2]

PTR[2]

* (PTR + 2 )

PTR로 치환

포인터 표현으로 바꿈

PTR값 다시 대입

* ( ptr_ary[2] +2 )

* ( * ( ptr_ary+2 ) +2 )

포인터 표현으로 바꿈

연산 순서

* ( * ( ptr_ary+2 ) +2 )
(1)
(2)
(3)
(4)
포인터 배열 사용 예제 (계속)
(1)
ptr_ary + 2 = ptr_ary + (2*sizeof(ptr_ary[0])) = 500 + (2*4) = 508
ptr_ary == 500

504

100

508

200

300

(2)

 참조 연산자 사용 : 세 번째 배열요소에 저장된 값은 300

(3)

 ary3의 세번째 기억 공간의 주소는 308

ptr_ary == 500

100

504

508

200

300
ary3 == 300

21
(4)

 참조 연산자 이용 저장된 값(23)을 구한다.

304

22

308

23

312

24
Contents

1.

포인터

2.

배열

3.

배열과 포인터

4.

2차원 배열과 포인터 배열

5.

응용 포인터
포인터 응용을 위한 2가지 원칙
첫째, 포인터가 가리키는 자료형은 무엇인가?
int val;

&val

double val;

int형 변수

&val

포인터 &val은 int형을 가리킨다.

double형 변수

포인터 &val은 double형을 가리킨다.

둘째, 포인터는 같은 자료형을 가리키는 포인터 변수에 저장해야 한다.
가리키는 자료형

int * ip ;
ip는 포인터 변수

변수이름

ip = &var;

//포인터를 포인터 변수에 대입

가리키는 자료형은 모두 int 형이다.
다중 포인터
다중 포인터

 포인터 변수를 가리키는 포인터
int *ip;

&ip
이중 포인터

(int *)형 변수

// 포인터 &ip는 (int *) 형을 가리킨다.

포인터 변수

이중 포인터 사용한 변수 참조

int val = 10;
int *ip = &val;

// int형 변수의 선언과 초기화
// 포인터 변수의 선언과 초기화
포인터 변수의 시작 주소
(200)

&ip
(200)

100
포인터 변수 ip

변수의 시작 주소
(100)

10
int형 변수 val
다중 포인터
이중 포인터 사용한 변수 참조 (계속)

* * &ip
(200)

#include <stdio.h>

int main()
{
int val=10;
int *ip ;

}

(100)
(10)

//포인터 변수의 선언과 동시에 초기화 가능 (int * ip=&val)

ip = &val;
printf(“변수 val의 값 : %d n”, **&ip);
return 0;

이중 포인터 변수
가리키는 자료형

int* * ipp ;
ipp는 포인터 변수 변수이름

ipp = &var;

//이중포인터를 이중 포인터 변수에 대입
가리키는 자료형은 모두 int * 형이다.
다중 포인터
이중 포인터 변수 (계속)

int val = 10;
int *ip ;
int **ipp ;

// int형 변수의 선언과 초기화
// 포인터 변수의 선언
// 이중 포인터 변수 선언

ip = &val ;
// int 변수의 포인터를 포인터 변수에 저장
ipp = &ip ;
// 포인터 변수의 포인터를 이중 포인터 변수에 저장
printf(“변수 val의 값 : %dn”, **ipp);

이중 포인터 변수 ipp
(300)

200

(200)

포인터 변수 ip

(100)

100
**ipp == ip

10
*ip == val

**ipp == val

int형 변수 val
배열 포인터
배열명의 역할
 1) 첫번째 배열 요소를 가리키는 포인터로서의 기능
ex) int nums[5] = {10, 20, 30, 40, 50} ;
int ip* = nums ;

// 배열명은 포인터이므로 포인터 변수에 저장한다.

printf(“%d n”, *nums);

// 첫번째 기억 공간을 참조하여 10이 출력된다.

printf(“%d n”, *(nums+4));

// nums의 값이 100이면 116번지 참조

nums

10

20

30

40

50

 2) 배열의 기억공간 전체를 나타내는 논리적 변수의 기능
ex) int ary[5];
ary = 10;

(0)

// 배열명에 직접 값을 대입할 수 없다.

ary[0] = 10;

(x)

// 특정 기억공간을 첨자로 지정하여 값을 대입해야 한다.

ary

int ary[5];
크기 : 20byte
형태 : int형 변수
5개

int

int

int

int

전체 20 byte

int
배열 포인터
배열 포인터

배열 전체를 가리킨다.

&ary

ary

36

int

int

int

int

int

int

ary+1

40

int

&ary

44

int

48

52

int

56

int

60

int

64

int

int형 다섯 개의 배열을
가리키는 배열 포인터

68

int

72

…

int

int

&ary+1

• ary + 1  1245036 + (1*sizeof(ary[0])  1245036+(1*4)  1245040

• &ary + 1  1245036 + (1*sizeof(ary)  1245036+(1*20)  1245056

……
배열 포인터
첫번째 기억공간

두번째 기억공간

세번째 기억공간

*(ary+0)

*(ary+1)

*(ary+2)

배열요소의 참조는 배열명을 사용한다.

 1차원 배열에서는 배열명으로 각 기억공간을 참조하므로 배열포인터를 구하는 것이 의미가 없다.

2차원 배열의 경우

int ary[3][4];
ary[0]
ary[1]
ary[2]

배열명 ary는 첫번째 부분 배열을
가리키는 배열포인터이다. !

ary

int

int

int

int

int

int

int

int

int

int

int

배열 요소는 세 개
각 배욜 요소의 형태는
“int형 변수 네 개의 배열형”

int

부분배열명은 각 부분배열의 첫번째
배열요소를 가리키는 포인터이다. !
배열 포인터
배열포인터 변수
가리키는 자료형
int형 변수 네 개의 1차원 배열

int (* ap) [4] ;
ap는 포인터 변수다.

예제)

변수의 이름

괄호가 생략되면
포인터 배열(포인터 변수들의 배열)을
선언하는 형식이 되므로 주의 !!!

# include <stdio.h>
int main()
{
int ary[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*ap) [4] ; //int형 변수 네 개의 배열을 가리키는 배열 포인터 변수
int i, j;
ap = ary;
for(i=0; i<3; i++) {
for(j=0; j<4; j++) {
printf(“%5d”, ap[i][j]);
}
printf(“n”);
}
return 0;
}
배열 포인터
2차원 배열에서 배열명으로 기억공간을 참조하는 원리
 2차원 배열은 논리적으로는 2차원이지만 물리적으로는 1차원의 형태로 기억공간에 할당

ary

배열명 ary의 값은 배열의
시작위치값 100과 같다.
100

ary[0]

1
116

부분 배열명은 각 부분 배열의
시작 위치 값이다.

ary[1]

5
132

ary[2]

9

104

2
120

6
136

10

• ary +1  100 + (1*sizeof(ary[0]))  100 + (1*16)  116
부분 배열명 ary[0]는
변수의 기능을 하며
부분배열 전체의 크기를 계산한다.

• *(ary+1)  ary[1]

//두 번째 부분 배열명

108

3

112

4

124

7
140

11

128

8
144

12
함수 포인터
함수명는 포인터
 프로그램 실행시 함수가 존재하는 메모리의 위치값이 함수명이다.
 함수를 (*sum)(10,20)과 같은 형태로 호출하는 것이 가능하다.  함수명이 포인터라는 증거 !
함수의 정의
함수포인터(함수명)

sum
함수명은 함수를 가리킨다.

int sum(int a, int b)
{
int res;
res = a + b;
return res;
}

함수 포인터 변수
함수의 형태

int sum (int, int) ;
(리턴값의 형태)

(매개변수의 객수와 형태)

int (* fp) (int, int) ;

• 가리키는 함수의 형태
Int형 값 두개를 전달 인자로 받고
Int형 값을 리턴하는 함수

변수의 이름
Fp는 포인터 변수다.

• int *fp(int,int);  괄호가 없으면 포인터를 리턴하는 함수
함수 포인터
사용 예제
#include <stdio.h>
int sum (int, int)

// 함수의 선언

int main()
{
int (*fp) (int, int) ;

// 함수 포인터변수 선언

int res;

// 리턴값을 저장할 변수

fp = sum;

// 함수명을 함수포인터변수에 저장한다.

res = fp(10,20);

// 함수포인터변수로 함수를 호출한다.

printf(“result : %d n”, res);

// 리턴값 출력

return 0;
}
int sum (int a, int b)
{
return a+b;
}

// 함수의 정의
함수 포인터
함수포인터의 사용
 형태가 같은 다양한 기능의 함수를 선택적으로 호출하는데 사용

• int sum(int, int) ; // 두 정수값을 더해서 리턴하는 함수

형태가 같다.

• int mul(int, int) ;

// 두 정수값을 곱해서 리턴하는 함수

• int max(int, int) ; // 두 정수값 중에서 큰 값을 리턴하는 함수

• fp = sum ;

int (*fp) (int, int);

정수의 합 계산
(sum)

func( );

//func(sum);
//func(mul);
//fucn(max);

• fp = mul ;
• fp = max ;
정수의 곱 계산
(mul)

모두 사용 가능하다.

큰 값 계산
(max)

필요에 따라 원하는 긴으의 함수명을
전달인자로 주고 호출한다.

void func(int (*fp)(int, int))
{
…
fp(a,b);
…
}
함수 포인터
사용 예제
#include <stdio.h>
void func(int (*)(int, int));

// func 함수의 선언, 매개변수는 함수포인터 변수

int sum(int, int);

// 두 정수값을 더하는 함수의 선언

int mul(int, int);

// 두 정수값을 곱하는 함수의 선언

int max(int, int);

// 두 정수값 중에서 큰 값을 구하는 함수의 선언

int main()
{
int sel ;

// 메뉴 선택 번호를 저장할 변수

printf(“1. 두 정수의 합 n”);

// 메뉴 출력

printf(“2. 두 정수의 곱 n”);
printf(“3. 두 정수중 큰 값 선택 n”);
printf(“ 원하는 작업을 선택하시오 : “ );
scanf (“%d”, &sel);

switch(sel) {
case 1: func(sum); break;
case 2: func(mul); break;
case 3: func(max); break;
}
return 0;
}
함수 포인터
사용 예제 (계속)
void func(int (*fp) (int, int)) {
int a, b;
int res;
printf(“ 두 정수값을 입력 하시요 : “);
scanf(“%d %d”, &a, &b);
res = fp(a, b);
printf(“결과값은 : %d n”, res);
}

왜 함수 포인터를 사용하는가?

int sum(int a, int b) {

 프로그램의 유지 보수가 쉽다.

return a+b ;
}
int mul (int a, int b) {

return a*b ;
}
int max (int a, int b) {
if(a >b) return a;
else return b;
}
void 포인터
void 포인터
 자료형에 대한 정보가 없다. (특별한 경우를 제외하고 사용할 경우가 거의 없다. --;)
 다른 포인터에 형변환 연산자를 사용하여 강제로 만들어주어야 한다.

int a ;
(void * ) &a ;

// int형 변수 선언
// int형 변수의 포인터를 void 포인터로 강제 형 변환

void 포인터 변수
가리키는 자료형이 정해져 있지 않다.

void * vp;
int in ;
double db ;
void *vp ;
vp = & in ;
vp = & db ;

변수의 이름.
vp는 포인터 변수

// int형 변수
// double형 변수
// void 포인터 변수
// int형 변수의 포인터를 저장할 수도 있고,
// double형 변수의 포인터도 저장할 수 있다.

 vp는 자료형에 대한 정보가 없으므로 사용시 원하는 형태로 변환해야 한다. !!!
printf(“%d n”, *(int *) vp);
vp = (int * ) vp +1;
void 포인터
사용 예제
#include <stdio.h>
#include <string.h>

void exchange(char *, void *, void * ) ;

// 함수 선언

int main()
{
int a=10; b=20;

// 정수형 변수 a, b

double da=1.5, db=2.5;

// 실수형 변수 da, db

exchange(“int”, &a, &b);

// 두 정수값의 교환

printf(“정수값 교환 후 : %d, %d n”, a, b);

// 교환 후 결과 출력

exchange(“double”, &da, &db);
printf( “실수값 교환 후 : %.11f,
}

// 두 실수값을 교환한다.
%.11f n”, da, db)

//교환 후 결과 출력
void 포인터
사용 예제 (계속)
void exchange (char *type, void *vp1, void *vp2)

// 함수의 정의

{
int itp;

// 정수형 임시 변수

double dtp;

// 실수형 임시 변수

if(strcmp(type, “int”) == 0) {
itp=*(int *) vp1;
*(int *) vp1 = * (int *) vp2;
*(int *) vp2 = itp;
}

* (int *) vp1

if(strcmp(type, “double”) == 0)
vp1을 (int *)형으로 변환.

{
dtp=*(double *)vp1;

*(double *)vp1 = *(double *)vp2;
*(double *)vp2 = dtp;
}
}

변환된 vp1이 가리키는 기억공간 참조
배열과 포인터

Contenu connexe

Tendances

Major themes oedipus rex
Major themes oedipus rexMajor themes oedipus rex
Major themes oedipus rexFRK NIAZI
 
The standard of morality in Tom Jones
The  standard  of  morality  in  Tom  JonesThe  standard  of  morality  in  Tom  Jones
The standard of morality in Tom JonesAnkita Gohel
 
Earliest heroes
Earliest heroesEarliest heroes
Earliest heroescamearl
 
Language acquisition
Language acquisitionLanguage acquisition
Language acquisitionHome
 
Dr. Faustus themes and symbols
Dr. Faustus themes and symbolsDr. Faustus themes and symbols
Dr. Faustus themes and symbolsIzzati Zaiton
 

Tendances (6)

Major themes oedipus rex
Major themes oedipus rexMajor themes oedipus rex
Major themes oedipus rex
 
The standard of morality in Tom Jones
The  standard  of  morality  in  Tom  JonesThe  standard  of  morality  in  Tom  Jones
The standard of morality in Tom Jones
 
Earliest heroes
Earliest heroesEarliest heroes
Earliest heroes
 
Seven Against Thebes
Seven Against ThebesSeven Against Thebes
Seven Against Thebes
 
Language acquisition
Language acquisitionLanguage acquisition
Language acquisition
 
Dr. Faustus themes and symbols
Dr. Faustus themes and symbolsDr. Faustus themes and symbols
Dr. Faustus themes and symbols
 

En vedette

스크럼(Scrum)
스크럼(Scrum)스크럼(Scrum)
스크럼(Scrum)영기 김
 
린 소프트웨어 개발(Lean software development)
린 소프트웨어 개발(Lean software development)린 소프트웨어 개발(Lean software development)
린 소프트웨어 개발(Lean software development)영기 김
 
[Visual studio camp #1] Enterprise Software Testing
[Visual studio camp #1] Enterprise Software Testing[Visual studio camp #1] Enterprise Software Testing
[Visual studio camp #1] Enterprise Software Testing준일 엄
 
[SWMaestro 100+ 발표자료] 테스트하기
[SWMaestro 100+ 발표자료] 테스트하기[SWMaestro 100+ 발표자료] 테스트하기
[SWMaestro 100+ 발표자료] 테스트하기Luavis Kang
 
소프트웨어 아키텍처 평가(Atam)
소프트웨어 아키텍처 평가(Atam)소프트웨어 아키텍처 평가(Atam)
소프트웨어 아키텍처 평가(Atam)영기 김
 
애자일 코치
애자일 코치애자일 코치
애자일 코치영기 김
 
Linux containers
Linux containersLinux containers
Linux containersLuavis Kang
 
[오픈소스컨설팅]소프트웨어테스팅전략
[오픈소스컨설팅]소프트웨어테스팅전략[오픈소스컨설팅]소프트웨어테스팅전략
[오픈소스컨설팅]소프트웨어테스팅전략Ji-Woong Choi
 
소프트웨어 테스팅
소프트웨어 테스팅소프트웨어 테스팅
소프트웨어 테스팅영기 김
 
칸반(Kanban)
칸반(Kanban)칸반(Kanban)
칸반(Kanban)영기 김
 
Istqb 4-테스트설계기법-2015-1
Istqb 4-테스트설계기법-2015-1Istqb 4-테스트설계기법-2015-1
Istqb 4-테스트설계기법-2015-1Jongwon Lee
 
익스트림 프로그래밍(Xp)
익스트림 프로그래밍(Xp)익스트림 프로그래밍(Xp)
익스트림 프로그래밍(Xp)영기 김
 

En vedette (13)

스크럼(Scrum)
스크럼(Scrum)스크럼(Scrum)
스크럼(Scrum)
 
린 소프트웨어 개발(Lean software development)
린 소프트웨어 개발(Lean software development)린 소프트웨어 개발(Lean software development)
린 소프트웨어 개발(Lean software development)
 
[Visual studio camp #1] Enterprise Software Testing
[Visual studio camp #1] Enterprise Software Testing[Visual studio camp #1] Enterprise Software Testing
[Visual studio camp #1] Enterprise Software Testing
 
[SWMaestro 100+ 발표자료] 테스트하기
[SWMaestro 100+ 발표자료] 테스트하기[SWMaestro 100+ 발표자료] 테스트하기
[SWMaestro 100+ 발표자료] 테스트하기
 
What is agile
What is agileWhat is agile
What is agile
 
소프트웨어 아키텍처 평가(Atam)
소프트웨어 아키텍처 평가(Atam)소프트웨어 아키텍처 평가(Atam)
소프트웨어 아키텍처 평가(Atam)
 
애자일 코치
애자일 코치애자일 코치
애자일 코치
 
Linux containers
Linux containersLinux containers
Linux containers
 
[오픈소스컨설팅]소프트웨어테스팅전략
[오픈소스컨설팅]소프트웨어테스팅전략[오픈소스컨설팅]소프트웨어테스팅전략
[오픈소스컨설팅]소프트웨어테스팅전략
 
소프트웨어 테스팅
소프트웨어 테스팅소프트웨어 테스팅
소프트웨어 테스팅
 
칸반(Kanban)
칸반(Kanban)칸반(Kanban)
칸반(Kanban)
 
Istqb 4-테스트설계기법-2015-1
Istqb 4-테스트설계기법-2015-1Istqb 4-테스트설계기법-2015-1
Istqb 4-테스트설계기법-2015-1
 
익스트림 프로그래밍(Xp)
익스트림 프로그래밍(Xp)익스트림 프로그래밍(Xp)
익스트림 프로그래밍(Xp)
 

Similaire à 배열과 포인터

포인터의기초 (2) - 포인터 사용하기1
포인터의기초 (2) - 포인터 사용하기1포인터의기초 (2) - 포인터 사용하기1
포인터의기초 (2) - 포인터 사용하기1Hoyoung Jung
 
The C++ Programming Language 5장 포인터, 배열, 구조체
The C++ Programming Language 5장 포인터, 배열, 구조체The C++ Programming Language 5장 포인터, 배열, 구조체
The C++ Programming Language 5장 포인터, 배열, 구조체해강
 
2015 Kitel C 언어 강좌3
2015 Kitel C 언어 강좌32015 Kitel C 언어 강좌3
2015 Kitel C 언어 강좌3ssuseraf62e91
 
포인터와 배열
포인터와 배열포인터와 배열
포인터와 배열Kim YoSep
 
Multithread programming 20151206_서진택
Multithread programming 20151206_서진택Multithread programming 20151206_서진택
Multithread programming 20151206_서진택JinTaek Seo
 
04장 고급변수 사용
04장 고급변수 사용04장 고급변수 사용
04장 고급변수 사용유석 남
 
코딩인카페 C&JAVA 기초과정 C프로그래밍(3)
코딩인카페 C&JAVA 기초과정 C프로그래밍(3)코딩인카페 C&JAVA 기초과정 C프로그래밍(3)
코딩인카페 C&JAVA 기초과정 C프로그래밍(3)유익아카데미
 
Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리ETRIBE_STG
 
게임프로그래밍입문 3주차
게임프로그래밍입문 3주차게임프로그래밍입문 3주차
게임프로그래밍입문 3주차Yeonah Ki
 
10장 문자열 클래스와 파일 클래스
10장 문자열 클래스와 파일 클래스10장 문자열 클래스와 파일 클래스
10장 문자열 클래스와 파일 클래스유석 남
 
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기Chris Ohk
 
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)Sang Don Kim
 
More effective c++ chapter1,2
More effective c++ chapter1,2More effective c++ chapter1,2
More effective c++ chapter1,2문익 장
 
포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++KWANGIL KIM
 

Similaire à 배열과 포인터 (20)

C review
C  reviewC  review
C review
 
포인터의기초 (2) - 포인터 사용하기1
포인터의기초 (2) - 포인터 사용하기1포인터의기초 (2) - 포인터 사용하기1
포인터의기초 (2) - 포인터 사용하기1
 
The C++ Programming Language 5장 포인터, 배열, 구조체
The C++ Programming Language 5장 포인터, 배열, 구조체The C++ Programming Language 5장 포인터, 배열, 구조체
The C++ Programming Language 5장 포인터, 배열, 구조체
 
2015 Kitel C 언어 강좌3
2015 Kitel C 언어 강좌32015 Kitel C 언어 강좌3
2015 Kitel C 언어 강좌3
 
포인터와 배열
포인터와 배열포인터와 배열
포인터와 배열
 
Multithread programming 20151206_서진택
Multithread programming 20151206_서진택Multithread programming 20151206_서진택
Multithread programming 20151206_서진택
 
3.포인터
3.포인터3.포인터
3.포인터
 
06장 함수
06장 함수06장 함수
06장 함수
 
6 function
6 function6 function
6 function
 
9. pointer
9. pointer9. pointer
9. pointer
 
04장 고급변수 사용
04장 고급변수 사용04장 고급변수 사용
04장 고급변수 사용
 
코딩인카페 C&JAVA 기초과정 C프로그래밍(3)
코딩인카페 C&JAVA 기초과정 C프로그래밍(3)코딩인카페 C&JAVA 기초과정 C프로그래밍(3)
코딩인카페 C&JAVA 기초과정 C프로그래밍(3)
 
Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리
 
게임프로그래밍입문 3주차
게임프로그래밍입문 3주차게임프로그래밍입문 3주차
게임프로그래밍입문 3주차
 
10장 문자열 클래스와 파일 클래스
10장 문자열 클래스와 파일 클래스10장 문자열 클래스와 파일 클래스
10장 문자열 클래스와 파일 클래스
 
java_2장.pptx
java_2장.pptxjava_2장.pptx
java_2장.pptx
 
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
 
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
 
More effective c++ chapter1,2
More effective c++ chapter1,2More effective c++ chapter1,2
More effective c++ chapter1,2
 
포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++
 

Plus de 영기 김

Ms Azure fundamentals
Ms Azure fundamentalsMs Azure fundamentals
Ms Azure fundamentals영기 김
 
AWS Certified Cloud Practitioner
AWS Certified Cloud PractitionerAWS Certified Cloud Practitioner
AWS Certified Cloud Practitioner영기 김
 
Microservices
Microservices Microservices
Microservices 영기 김
 
Dev ops Introduction
Dev ops IntroductionDev ops Introduction
Dev ops Introduction영기 김
 
통신시스템(Wcdma network)
통신시스템(Wcdma network)통신시스템(Wcdma network)
통신시스템(Wcdma network)영기 김
 
통신시스템(Cdma network)
통신시스템(Cdma network)통신시스템(Cdma network)
통신시스템(Cdma network)영기 김
 
통신시스템(Gprs network)
통신시스템(Gprs network)통신시스템(Gprs network)
통신시스템(Gprs network)영기 김
 
소프트웨어 아키텍처 문서화
소프트웨어 아키텍처 문서화소프트웨어 아키텍처 문서화
소프트웨어 아키텍처 문서화영기 김
 
통신시스템(Gsm network)
통신시스템(Gsm network)통신시스템(Gsm network)
통신시스템(Gsm network)영기 김
 
소프트웨어 아키텍처
소프트웨어 아키텍처소프트웨어 아키텍처
소프트웨어 아키텍처영기 김
 
통신시스템(Cellular concepts)
통신시스템(Cellular concepts)통신시스템(Cellular concepts)
통신시스템(Cellular concepts)영기 김
 
알고리즘과 자료구조
알고리즘과 자료구조알고리즘과 자료구조
알고리즘과 자료구조영기 김
 
애자일 S/W 개발
애자일 S/W 개발애자일 S/W 개발
애자일 S/W 개발영기 김
 

Plus de 영기 김 (13)

Ms Azure fundamentals
Ms Azure fundamentalsMs Azure fundamentals
Ms Azure fundamentals
 
AWS Certified Cloud Practitioner
AWS Certified Cloud PractitionerAWS Certified Cloud Practitioner
AWS Certified Cloud Practitioner
 
Microservices
Microservices Microservices
Microservices
 
Dev ops Introduction
Dev ops IntroductionDev ops Introduction
Dev ops Introduction
 
통신시스템(Wcdma network)
통신시스템(Wcdma network)통신시스템(Wcdma network)
통신시스템(Wcdma network)
 
통신시스템(Cdma network)
통신시스템(Cdma network)통신시스템(Cdma network)
통신시스템(Cdma network)
 
통신시스템(Gprs network)
통신시스템(Gprs network)통신시스템(Gprs network)
통신시스템(Gprs network)
 
소프트웨어 아키텍처 문서화
소프트웨어 아키텍처 문서화소프트웨어 아키텍처 문서화
소프트웨어 아키텍처 문서화
 
통신시스템(Gsm network)
통신시스템(Gsm network)통신시스템(Gsm network)
통신시스템(Gsm network)
 
소프트웨어 아키텍처
소프트웨어 아키텍처소프트웨어 아키텍처
소프트웨어 아키텍처
 
통신시스템(Cellular concepts)
통신시스템(Cellular concepts)통신시스템(Cellular concepts)
통신시스템(Cellular concepts)
 
알고리즘과 자료구조
알고리즘과 자료구조알고리즘과 자료구조
알고리즘과 자료구조
 
애자일 S/W 개발
애자일 S/W 개발애자일 S/W 개발
애자일 S/W 개발
 

배열과 포인터

  • 1. 배열과 포인터 Software Engineering Lab 김영기 책임 resious@gmail.com
  • 3. 포인터란 무엇인가?  프로그램이 기억공간을 참조하는 2가지 방법  1. 변수명을 사용하는 방법 이 4byte의 기억 공간은 지금부터 var라는 이름으로 사용이 가능하다. 변수 선언 int var ; var 메모리에 기억 공간이 할당된다. 변수명으로 기억공간을 사용한다. var = 10; value = var; 할당된 기억 공간에 10을 저장한다. var 값을 다른 기억 공간에 복사한다.
  • 4. 포인터란 무엇인가?  프로그램이 기억공간을 참조하는 2가지 방법  2. 변수가 할당된 메모리의 실제 주소(포인터)를 사용하는 방법 int var ; 변수 선언 메모리에 4byte의 기억 공간이 할당된다. var 99 100 101 포인터 102 103 104 105 106 107 108 시작 주소값이다.  포인터를 사용하여 변수명과 같이 할당된 기억 공간에 값을 저장하거나 저장된 값을 꺼내어 쓸 수 있다.
  • 5. 주소 연산자 – 포인터를 구하자.  프로그램에서 변수명은 알 수 있지만 그 변수의 실제 주소값은 알 수 없다. 따라서, 포인터를 사용하기 위해서는 먼저 그 주소값을 알아내는 과정이 필요하다.  특정 변수의 포인터를 구하기 위해서는 주소 연산자(&)를 사용한다. & var 주소 연산자 포인터를 구해준다. ! 변수명 Sample Code char ch; int in; double dbl; // char형 변수 선언, 크기 1byte // int형 변수 선언, 크기 4byte // double형 변수 선언, 크기 8byte printf(“ch의 포인터 : %un”, &ch); printf(“in의 포인터 : %un”, &in); printf(“dbl의 포인터 : %un”, &dbl); 결과를 Memory Map으로 표시하여 보자.
  • 6. 주소 연산자 – 포인터를 구하자 Sample Code 실행 결과 분석 예 : ..052 ..051 ..050 ..049 ..048 ..047 ..046 ..045 ..044 ..043 ..042 ..041 ..040 ..039 ..038 ..037 ..036 ch in 포인터에는 자신이 어떤 자료형으로 부터 만들어졌는지에 대한 정보를 가지고 있다. 포인터 dbl 주소값 정보 &ch ..052 char형 기억 공간의 주소값이다. &in ..048 int형 기억 공간의 시작 주소값이다. &db ..040 double형 기억 공간의 시작 주소값이다.  포인터의 크기는 자료형에 상관없이 동일한가?
  • 7. 참조 연산자 – 포인터를 사용하자.  포인터를 통해서 기억 공간을 사용하기 위해서는 참조 연산자(*)를 사용한다. * &var 참조 연산자 포인터가 가리키는 기억 공간을 사용한다. ! 포인터 참조 연산자로 포인터를 사용하는 방법  포인터가 가리키는 기억 공간을 사용한다.  포인터가 가리키는 기억 공간의 값을 사용한다. Sample Code int a = 10, b = 20; *&a = *&b printf(“a의 값 : %dn”, a); 기억 공간을 사용 // 변수 b에 저장된 값을 변수 a의 기억 공간에 기억 *&a = *&b ; 기억 공간의 값을 사용
  • 8. 포인터 변수 – 포인터를 저장하자. 포인터의 저장 int a; int ap; ap = &a; // 포인터를 구할 변수 // 포인터를 저정할 변수 // a의 포인터를 구하여 ap에 저장한다. 변수 a 변수 ap 99 100 101 102 103 104 105 106  error C2440 : ‘=‘ : cannot convert from ‘int *’ to ‘int’ 107 108 109 포인터에는 자료형에 대한 정보가 함께 있다. 포인터 변수 int *ap 가리키는 자료형을 앞에 붙여준다. 포인터 변수 ap는 int형 변수의 시작 주소값만을 저장할 수 있다. 변수명 앞에 별표를 붙여 포인터 변수임을 표시한다.
  • 9. 포인터 변수 – 포인터를 저장하자. 포인터의 저장 int a; int *ap; ap = &a; // 포인터를 구할 변수 // 포인터를 저장할 변수 // a의 포인터를 구하여 포인터 변수 ap에 저장한다. ap가 포인터를 저장하면 100 100 가리킨다. 포인터 변수 ap int 형 변수 a Sample Code int a ; int *ap = &a; *ap = 10; // int 형 변수 선언 // 포인터 변수 선언과 동시에 초기화 // 포인터 변수가 가리키는 공간에 10 저장 printf(“변수명을 사용한 출력 : %dn”, a); printf(“포인터 변수를 사용한 출력 : %dn”, *ap);
  • 10. 포인터는 왜 필요한가? (1) 함수들은 독립된 기억 공간을 가진다. #include <stdio.h> main 함수영역 void assign(); int main() { int var = 0; } assign 함수영역 var var ?? 0 assign(); printf(“ 함수 호출 후 var에 저장된 값 : %d n”, var); return 0; void assign() { var = 100; }  error C2065 : ‘var‘ : undeclared identifier void assign() { int var ; var = 100; } 결과는 ?
  • 11. 포인터는 왜 필요한가? (2) 포인터로 다른 함수의 기억공간을 사용한다. main 함수영역 #include <stdio.h> void assign(int *); int main() { int var = 0; } assign 함수영역 포인터를 넘겨준다. 200 var 0 200 Ip가 포인터가 저장하여 var를 가리킨다. (var 변수의 시작 주소값은 200) assign(&var); printf(“ 함수 호출 후 var에 저장된 값 : %d n”, var); return 0; void assign(int *ip) { *ip = 100; } ip void assign() { return 100; } 결과는 동일한가 ? 변수가 여러 개일 경우는?
  • 12. 포인터는 왜 필요한가? (3) 두 변수의 값을 서로 바꾸는 함수를 만들어 보도록 하자.  void exchange(int *, int *) ; #include <stdio.h> int main() { int var1 = 10, var2 = 20; } printf(“바꾸기 전 : %d , %d n”, var1, var2); exchange(&var1, &var2); printf(“바꾼 후 : %d, %d n”, var1, var2); return 0; void exchange(int *cp, int *mp) { // 구현하시오.. }  void exhange(int c, int m)로 구현할 경우 값이 바뀌는가? 바뀌지 않는 이유는 ?
  • 13. 포인터와 포인터 변수의 크기 Sample Code char ch; int in; double dbl; printf(“char 형 변수의 포인터 크기 : %d n”, sizeof(&ch); printf(“ int 형 변수의 포인터 크기 : %d n”, sizeof(&int); printf(“ double 형 변수의 포인터 크기 : %d n” 가리키는 자료형의 크기는 달라도 모든 포인터 변수의 크기는 4 바이트이다. ch (1byte) char 형 포인터 변수 in (4byte) int 형 포인터 변수 dbl (8byte) double 형 포인터 변수
  • 14. 포인터와 포인터 변수의 형변환 Sample Code int *ip; double dbl=6.4; ip = &dbl; // int 형 변수를 가리키는 포인터 변수 // double 형 변수 // double형 변수의 포인터를 int형 포인터 변수에 대입  error C2440 : ‘=‘ : cannot convert from ‘double * ‘ to ‘int *’ int *ip; double dbl=6.4; ip = (int *) &dbl; //(double *)를 (int *)로 강제 형변환한다.
  • 16. 배열이란? 배열이란  동일한 자료형으로 된 기억 장소들의 모임  배열을 사용하는 목적은 기억 장소의 일괄 처리에 있다. 배열의 선언 int ages[5]; 배열의 형태 배열의 이름 변수의 갯수 배열 ages 블록은 하나의 int형 변수 int int int int int  다섯 개의 변수가 연속으로 이어짐
  • 17. 배열의 사용 배열의 사용  배열내의 각각에 기억 공간은 별도로 붙여진 이름이 없다. 따라서 개별적인 이름이 아닌 배열에서 차지하는 위치를 이용한다.  배열을 구성하는 기억 공간들을 배열의 요소(element)라고 하고, 각 요소가 배열에서 차지하는 위치를 첨자(index)라고 한다.  기억 공간의 사용 : 배열명 + 배열에서의 위치 배열 요소의 표현 배열명[첨자] 첫번째 배열 요소 두번째 배열 요소 배열 ages ages[0] ages[1] 세번째 배열 요소 ages[2] 네번째 배열 요소 ages[3] 다섯번째 배열 요소 ages[4] * 배열의 첨자는 0부터 시작한다.
  • 18. 배열의 사용 배열요소의 표현은 하나의 변수명과 똑같이 사용된다. score[3] 하나의 변수명과 같다. 따라서 일반 변수와 같이 사용한다. Ex) scanf(“%d”, &ages[3]); 첨자는 0부터 시작하므로 최대값이 배열 요소의 개수보다 하나 작다. ages[5] 0 1 2 다섯개만 쓰기로 정의 3 4 score[5] = 34; 5 허락되지 않은 기억 공간을 사용하게 된다.
  • 19. 배열과 반복문  모든 배열요소는 배열명이 같고 첨자가 하나씩 증가하는 규칙을 가지고 있기 때문에 반복문을 이용하면 각 배열 요소를 간단하게 처리할 수 있다. i=0일때 : scanf(“%d”, &ages[0]); for(i=0; i<5; i++) scanf(“%d”, &ages[0]); } i=1 일때 : scanf(“%d”, &ages[1]); i=2 일때 : scanf(“%d”, &ages[2]); i=3 일때 : scanf(“%d”, &ages[3]); i=4 일때 : scanf(“%d”, &ages[4]); 배열과 반복문울 이용하여 다섯 명의 나이를 입력 받고, 평균을 구하는 프로그램을 작성하여 보자. (시간 15분)
  • 20. 배열의 초기화 배열을 선언하면 그 안에 쓰레기값이 존재하게 된다. int nums[5]; int i, total =0; for(i=0; i<5; i++) total+=nums[i] } printf(“total : %dn”, total); 배열 nums ? ? ? ? ? + 출력 결과는 ? 결과가 시스템의 상황에 따라 달라진다. 배열은 선언과 동시에 초기화 하는 것이 좋다. int nums[5] = {1,3,5,15,30}; 1 순서대로 저장된다. 3 7 15 30 nums[0] nums[1] nums[2] nums[3] nums[4]
  • 21. 배열의 초기화 배열의 초기화 시 편리한 자동 기능  배열 요소의 수보다 초기화 값이 적으면 남은 공간은 0으로 채워진다. 배열 nums int nums[5] = {1,3}; 1 3 0 0 0 자동으로 0으로 채워진다.  배열 선언시 초기화를 하면 배열 요소를 생략할 수 있다. 배열 nums int nums[] = {1,3,7,15,30}; 1 숫자 생략가능 3 7 15 30 자동으로 다섯 개의 기억 공간이 할당된다.
  • 22. 배열의 크기 배열의 크기를 계산해야 하는 경우가 많이 생긴다.  배열의 크기를 자동으로 계산하는 방법은 ? 전체 20 bytes int nums[5]; int int int int int 4byte 배열 요소의 개수 = sizeof(nums) / sizeof(nums[0]) 배열 전체의 크기 배열 요소 하나의 크기
  • 23. 배열 예제 int int int int nums[] = {1,2,3,4,5} ; total = 0; i; size ; // 배열의 초기화 // 합을 저장한 누적 변수 // 반복 제어 변수 // 배열 요소의 개수를 저장할 변수 size = sizeof(nums) / sizeof(nums[0]); for(i=0; i<size; i++) { total += nums[i]; }  배열 요소를 각각 초기화한 경우와 비교해 보자.  size를 사용하지 않은 경우와 비교해 보자.
  • 24. 문자 배열과 null 문자 배열의 선언과 사용 char word[4]; 배열명 word char char char 4byte word[0] = ‘L’; word[1] char = ‘o’; word[2] = ‘v’; ‘L’ ‘o’ ‘v’ ‘e’ word[3] = ‘e’; 출력은? for(i=0; i<4; i++) print(“%c”, word[i]); } 같은 의미 printf(“%s”, word);
  • 25. 문자 배열과 null 배열의 끝 ? char word[50]; // 배열 선언 char word[50]; // 배열 선언 word[0] = ‘L’; word[1] = ‘o’; word[2] = ‘v’; word[3] = ‘e’; word[4] = ‘0’; printf(“%s”, word); //문자열 출력 word[0] = ‘L’; word[1] = ‘o’; word[2] = ‘v’; word[3] = ‘e’; printf(“%s”, word); //문자열 출력 word L o v e ? ? ? ? 여기에 있는 것도 출력할 문자열들인가? word L o v e 0 ? ? 여기까지가 출력한 문자열이군… ?
  • 26. scanf 함수를 이용한 문자열 입력 char word[50]; char word[4]; printf(“Input String is : “); printf(“%s”, word); printf(“Input String is : “); printf(“%s”, word); printf(“input string : “); scanf(“%s”, word); word L i printf(“input string : “); scanf(“%s”, word); n u x /0 L i n ? 마지막에 널 문자를 넣어 문자열을 완성한다. 할당 영역 word ? u x /0 ? 이웃한 메모리 영역을 침범하게 된다. ?
  • 27. 문자배열의 초기화 문자 배열 초기화  문자열 상수의 대입은 선언과 동시에 초기화하는 경우만 가능 char str[10] = {‘d’, ‘r’, ‘e’, ‘a’, ‘m’, ‘0’}; d r e a 초기화한 문자열 m 0 0 0 0 남는 배열 요소 일반 변수 int val = 10; val = 20; // 변수 선언과 동시에 초기화 (0) //초기화 된 이후 다른 값을 저장 (0) 문자 배열 char str[80] = “dream” ; str = “world“ ; // 변수 선언과 동시에 초기화 (0) //초기화 된 이후 다른 값을 저장 (x) 0
  • 28. 문자배열의 초기화 문자 배열 값 지정 w o r l d 0 0 0 0 0 한 byte 씩 모두 복사해야 한다. d r e a m 0 초기화 시 배열 요소의 개수 생략 char str[] = “I love you”;  몇 byte의 기억 공간이 잡힐까? 0 0 0 0
  • 30. 포인터로 배열요소의 참조 배열은 많은 양의 데이터를 효율적으로 처리할 수 있다.  반복문의 사용 배열은 같은 형태의 변수가 연속된 메모리 공간에 할당된다.  첫번째 배열요소의 위치를 알면 나머지도 알 수 있다. x의 값을 알면 나머지는 자동으로 구해진다. x int ary[5]; int ary[0] x+4 int ary[1] x+8 int ary[2] x+12 int ary[3] x+16 int ary[4]
  • 31. 포인터로 배열요소의 참조 (예제) Example Code int ary[5] = {10, 20, 30, 40, 50}; int *ap; ap=&ary[0]; printf(“ 1st 배열 요소의 주소값 : %u n”, ap); printf(“ 1st 배열 요소의 값 : %d n”, *ap); ap=&ary[0]+4 ; printf(“ 2nd 배열 요소의 주소값 : %u n”, ap); printf(“ 2nd 배열 요소의 값 : %d n”, *ap); 출력 결과 1st 배열 요소의 주소값 : 1245036 1st 배열 요소의 값 : 10 2nd 배열 요소의 주소값 : 1245052 2nd 배열 요소의 값 : 50 36 // 첫 번째 배열 요소의 포인터를 포인터 변수에 저장 // 첫 번째 요소의 주소값 출력 // 배열 요소에 저장된 값 출력 // 두 번째 배열 요소의 포인터를 구한다. // 첫 번째 요소의 주소값 출력 // 배열 요소에 저장된 값 출력 52 ?? 10 20 30 40 50 ary[0] ary[1] ary[2] ary[3] ary[4]
  • 32. 포인터로 배열요소의 참조 (예제 계속) 왜 원하지 않는 결과가 나왔는가?  포인터는 어떤 자료형으로 부터 계산되었는지에 대한 정보를 가지고 있다. 따라서 포인터에 정수값을 더할 때는 포인터가 가리키는 자료형의 크기가 곱해지게 된다. 포인터+정수값 포인터 + (정수값+포인터가 가리키는 자료형의 크기) &ary[0]+4=&ary[0]+(4*sizeof(int)) = 36+16=52 &ary[0] + 0 = 36 10 ary[0] &ary[0] + 1 = 40 20 ary[1] &ary[0] + 2 = 44 30 ary[2] &ary[0] + 3 = 48 40 ary[3] 50 ary[4] 포인터가 가리키는 기억 공간 참조 &ary[0] + 4 = 52 포인터는 4바이트씩 증가한다. *(&ary[0]+i) 각 배열요소를 가르키는 포인터를 차례로 계산 for(i=0; i<5; i++){ printf(“%dn”, *(ary[0]+i)); }
  • 33. 배열명은 포인터! C언어는 첫 번째 배열요소의 포인터를 쉽게 사용할 수 있도록 배열명으로 표현한다.  배열명은 첫 번째 배열 요소를 가리키는 포인터이다. 첫번재 기억 공간의 시작주소값 같다. 배열명 ary 36 10 ary[0] 44 48 52 20 30 40 50 ary[1] ary[2] ary[3] ary[4] 포인터표현 배열표현 ary[0] ary[1] ary[2] ary[3] ary[4] 40 == *(ary+0) *(ary+1) *(ary+2) *(ary+3) *(ary+4) for(i=0; i<5; i++){ printf(“%dn”, *(ary+i)); }
  • 34. 포인터 변수로 배열 요소 참조 int *ap = ary ; 배열명을 포인터 변수에 저장 36 36 포인터변수 ap 40 44 48 52 10 ary == 20 30 40 50 ary[1] ary[2] ary[3] ary[4] ary[0] *(ap + 1)  40번지에 있는 배열 요소를 참조한다. 36+(1*sizeof(int)) = 36+4=40번지 int ary[5] = {10, 20, 30, 40, 50}; int *ap = ary; int i; for(i=0; i<5; i++) { printf(“%5d”, *(ap+1)); } 배열표현 포인터표현 ary[0] ary[1] ary[2] ary[3] ary[4] == *(ap+0) *(ap+1) *(ap+2) *(ap+3) *(ap+4) int ary[5] = {10, 20, 30, 40, 50}; int *ap = ary; int i; for(i=0; i<5; i++) { printf(“%5d”, ap[i]); }
  • 35. 배열 요소 참조 방법 정리 배열요소의 참조 방법  1. 배열명을 사용한 배열 표현  2. 배열명을 사용한 포인터 표현  3. 배열명을 저장한 포인터 변수를 사용한 포인터 표현  4. 배열명을 저장한 포인터 변수를 사용한 배열 표현 ary == 36 포인터변수 ap 36 10 (1) ary[0] 40 44 48 52 20 30 40 50 ary[1] ary[2] ary[3] ary[4] (2) *(ary+0) *(ary+1) *(ary+2) *(ary+3) *(ary+4) (3) *(ap+0) (4) *(ap[0]) *(ap+1) *(ap+2) *(ap+3) *(ap+4) *(ap[1]) *(ap[2]) *(ap[3]) *(ap[4]) 모두 첫번째 배열 요소를 참조하는 표현식이다.
  • 36. 배열명은 포인터 변수가 아니다. 포인터  주소값을 나타낸다.  상수이므로 변경할 수 없다. ary = ary + 2; ary ++ ; 배열명은 변수가 아니므로 자신의 값을 바꿀 수 없다. 포인터 변수  변수이므로 가르키는 대상을 바꿀 수 있다. 포인터 오직 하나만.. 포인터 변수 많을수록 ..
  • 37. 배열 처리 함수 – 값 출력 모든 배열요소는 포인터로 참조할 수 있으므로 배열을 처리하는데 필요한 것은 배열에 있는 데이터가 아니라, 배열이 메모리의 어디에 있는지에 대한 주소값이면 충분하다.  int ary[5] = {10, 20, 30, 40, 50};의 모든 값을 출력하는 함수를 만들어 보자. 1. void ary_prn(int *ap) { int i; for(i=0; i<5; i++){ printf(“%d”, *(ap+i)); } }  호환성 있는 함수를 만들기 위해서는 배열명과 배열요소의 개수를 함께 전달인자로 사용해야 한다. // ary_prn(ary, sizeof(ary)/sizeof(ary[0])); 2. void ary_print(int *ap, int an) { int i; for(i=0; i<an; i++){ printf(“%5d”, ap[i]); } }
  • 38. 배열 처리 함수 – 값 입력 배열의 위치를 알아야 한다.  int ary[5] ;의 값을 입력하는 함수를 만들어 보자. 1. void ary_input(int *ap) { int i; for(i=0; i<5; i++){ scanf(“%d”, ap+1); } }  printf는 배열 요소에 저장된 값을 필요로 하므로 참조 연산자를 사용했지만, scanf는 참조연산자를 사용할 필요가 없다.
  • 40. 2차원 배열의 선언과 초기화 1차원 배열  복잡하고 많은 데이터 처리에 한계 배열을 하나의 요소로 하는 또 다른 배열  2차원 배열 첫 번째 배열 요소 두 번째 배열 요소 + 배열 요소가 세 개인 새로운 배열. 세 번째 배열 요소
  • 41. 2차원 배열의 선언과 초기화 2차원 배열의 선언 배열의 형태 int score[3][4]; 배열의 이름 int 형 변수 4개짜리 1차원 배열이 2차원 배열의 배열 요소가 된다. 변수요소의 갯수 부분 배열 : 2차원 배열은 논리적으로 행렬로 표현된다. 부분배열명 첫번째 부분배열 ages[0] 두번째 부분배열 ages[1] 세번째 부분배열 ages[2] 2차원 배열 SCORE
  • 42. 2차원 배열의 선언과 초기화 2차원 배열 요소의 참조 score[0][0] = 10 ; 첫번째 부분 배열의 첫번째 배열 요소에 10을 저장한다. score[0] score[0][0] score[0][1] score[0][2] score[0][3]
  • 43. 2차원 배열의 선언과 초기화 2차원 배열의 처리  2중 for 문 int score[3][4]; int i, j; i는 0부터 2까지 세 번 반복된다. for(i=0 ; i< 3) ; i++) { 학생 한 명의 점수를 입력 받는 과정 printf(“네 과목의 점수를 입력하세요 : “); for( j=0 ; j<4 ; j++) { scanf(“%d”, &score[i][j]); } 부분배열명의 첨자를 제어변수로 사용하여 새로운 부분 배열에 점수를 입력 받도록 한다. } j 반복문 i 반복문 j가 0 일때 j가 1 일때 j가 2 일때 j가 3 일때 i가 0 일때 score[0][0] score[0][1] score[0][2] score[0][3] i가 1 일때 score[1][0] score[1][1] score[1][2] score[1][3] i가 2 일때 score[2][0] score[2][1] score[2][2] score[2][3]
  • 44. 2차원 배열의 선언과 초기화 예제 – 3명의 학생에 대한 4과목 점수 처리 예제 #include <stdio.h> int main() { int score[3][4]; int i, j; int tot; double avg; for(i=0; i<3; i++){ printf(“네 과목의 점수를 입력하시오 : “); for( j=0; j<4; j++){ scanf(“%d ”, &score[i][j]); } } for(i=0; i<3; i++){ tot=0; for( j=0; j<4; j++){ tot+=score[i][j]; } avg=tot/4.0; //한 명의 총점을 모두 누적한 후에 평균 계산 printf(“총점 : %d, 평균 : %21fn”, tot, avg); //총점, 평균 출력 } } return 0;
  • 45. 2차원 배열의 선언과 초기화 2차원 배열의 초기화 – case 1 int nums[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; int nums[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 1 3 4 5 6 7 8 9 2차원 배열 nums 2 10 11 12 //논리적 구조에 맞게 행을 구분 첫번째 행이 초기화 된 후에 두 번째, 세 번째 행이 차례로 초기화 된다. 2차원 배열의 초기화 – case 2  기억 공간보다 초기화 값이 적은 경우 남은 공간은 0으로 초기화 된다. int nums[3][4]={1,2,3,4,5,6}; 1 2차원 배열 nums 2 3 4 5 6 0 0 0 0 0 0  첫 번째 기억 공간만 초기화 하면 모든 기억 공간이 0으로 초기화 된다. int nums[100][200]={0} ; // 모든 공간이 0으로 초기화
  • 46. 2차원 배열의 선언과 초기화 2차원 배열의 초기화 – case 3 int nums[3][4]={{1},{5,6},{9,10,11}}; 0 0 0 5 6 0 0 9 2차원 배열 nums 1 10 11 0 2차원 배열의 초기화 – case 4 int nums[][4]={{1},{2,3},{4,5,6}}; 행의 수가 세 개 행 첨자 생략 열 첨자 생략 불가능 2차원 배열 nums 1 0 0 0 2 3 0 0 4 5 6 0 3행 4열의 기억 공간 할당
  • 47. 2차원 배열의 선언과 초기화 2차원 배열의 초기화 – case 5 int nums[][4]={1,2,3,4,5,6}; 첫번째 행 초기값 2차원 배열 nums 두 번째 행 초기값 1 2 3 4 5 6 0 0 2행 4열의 기억 공간 할당
  • 48. 2차원 문자 배열 각 행이 하나의 문자열을 저장한다. char animal[5][20]; //5개의 문자열을 저장할 2차원 문자배열 부분배열명 animal[0] animal[1] animal[2] animal[3] animal[4] Scanf(“%s”, animal[4]); 전체가 배열명 //gets함수를 사용하면 gets(animal[4]); char animal[5][20]; int i; //2차원 문자 배열 선언 //반복 제어 문자 for(i=0; i<5; i++);{ printf (“문자열을 입력하세요 : ”); scanf(“%s”, animal[i]); //i값이 변하면서 각 부분배열명이 된다. }
  • 49. 2차원 문자 배열의 초기화 2차원 문자 배열의 초기화 case 1 char animal[5][10] = {{‘c’,’a’,’t’,‘0’}, {‘h’,’o’,’r’,’s’,’e’,’0’}, {‘d’,’o’,’g’,’0’}, {‘t’,’I’,’g’,’e’,’r’,’0’}, {‘e’,’l’,’e’,’p’,’h’,’a’,’n’,’t’,’0’}}; 2차원 문자 배열의 초기화 case 2 char str[10] = “cat” ;  하나의 문자열 상수는 1차원 문자 배열을 초기화 할 수 있다. char animal[5][10] = {“cat”, ”horse”, “dog”, “tiger”, “elephant”}; c a t 0 0 0 0 0 0 0 h o r s e d o g 0 0 0 0 0 0 0 0 0 0 0 0 t i g e r 0 0 0 0 0 e l e p h a n t 0 0
  • 50. 포인터 배열 포인터 변수를 통한 문자열 처리 char *cp = “tiger”; //포인터를 포인터변수에 저장한다. printf (“%s”, cp); //포인터변수로 문자열을 출력한다. 배열의 선언 char* ptr_ary[5]; 배열요소의 자료형 배열의 이름 변수의 갯수 char * char * char * char * char * 모든 배열 요소가 포인터 변수이다. ptr_ary[2] = “tiger” ; // 세 번째 배열 요소에 문자열 상수를 대입한다. printf(“%s”, ptr_ary[2]); // 배열요소를 참조하여 문자열을 출력한다.
  • 51. 포인터 배열 예제 #include <stdio.h> int main() { char * ptr_ary[5]; int i; // 포인터 배열 선언 ptr_ary[0]=“dog”; ptr_ary[1]=“elephant”; ptr_ary[2]=“horse”; ptr_ary[3]=“tiger”; ptr_ary[4]=“lion”; } for(i=0; i<5 ; i++) { printf(“%sn”, ptr_ary[i]); } return 0; ptr_ary ptr_ary[0] d o g ptr_ary[1] e l e p h a n t ptr_ary[2] h o r s e 0 ptr_ary[3] t i g e r 0 ptr_ary[4] l 스택 영역 0 i o n 0 0 데이터의변경이 불가능한 메모리 영역
  • 52. 포인터 배열의 초기화 포인터 배열의 초기화 방법 char animal[5][10] char *ptr_ary[5] = {“dog”, “elephant”, “horse”, “tiger”, “lion”}; = {“dog”, “elephant”, “horse”, “tiger”, “lion”}; 배열의 형태에 따라 문자열을 복사하거나 포인터를 저장한다. 초기화 방법은 같다.. 포인터 배열은 2차원 배열인가?  포인터 배열은 첨자를 하나 사용하는 1차원 배열이다. 그러나 배열 요소가 포인터 변수이므로 2차원 배열처럼 활용하는 것이 가능하다.
  • 53. 포인터 배열 사용 예제 #include <stdio.h> int main() { int ary1 [4] = {1, 2, 3, 4} ; int ary2 [4] = {11, 12, 13, 14} ; int ary3 [4] = {21, 22, 23, 24}; int *ptr_ary[3] = {ary1, ary2, ary3} ; int i, j; } for(i=0; i<3; i++) { for( j=0; j<4; j++) { printf(“%5d”, ptr_ary[i],[j]); } } return 0; ary1 == 100 ptr_ary 500 [출력 결과] 1 2 3 11 12 13 21 22 23 4 14 24 504 508 100 200 300 104 1 ary2 == 200 11 ary3 == 300 21 108 2 204 3 208 12 304 22 112 4 212 13 308 14 312 23 24
  • 54. 포인터 배열 사용 예제 (계속) ptr_ary[2][2]가 어떻게 23의 값을 참조할 수 있는가? ptr_ary[2][2] PTR[2] * (PTR + 2 ) PTR로 치환 포인터 표현으로 바꿈 PTR값 다시 대입 * ( ptr_ary[2] +2 ) * ( * ( ptr_ary+2 ) +2 ) 포인터 표현으로 바꿈 연산 순서 * ( * ( ptr_ary+2 ) +2 ) (1) (2) (3) (4)
  • 55. 포인터 배열 사용 예제 (계속) (1) ptr_ary + 2 = ptr_ary + (2*sizeof(ptr_ary[0])) = 500 + (2*4) = 508 ptr_ary == 500 504 100 508 200 300 (2)  참조 연산자 사용 : 세 번째 배열요소에 저장된 값은 300 (3)  ary3의 세번째 기억 공간의 주소는 308 ptr_ary == 500 100 504 508 200 300 ary3 == 300 21 (4)  참조 연산자 이용 저장된 값(23)을 구한다. 304 22 308 23 312 24
  • 57. 포인터 응용을 위한 2가지 원칙 첫째, 포인터가 가리키는 자료형은 무엇인가? int val; &val double val; int형 변수 &val 포인터 &val은 int형을 가리킨다. double형 변수 포인터 &val은 double형을 가리킨다. 둘째, 포인터는 같은 자료형을 가리키는 포인터 변수에 저장해야 한다. 가리키는 자료형 int * ip ; ip는 포인터 변수 변수이름 ip = &var; //포인터를 포인터 변수에 대입 가리키는 자료형은 모두 int 형이다.
  • 58. 다중 포인터 다중 포인터  포인터 변수를 가리키는 포인터 int *ip; &ip 이중 포인터 (int *)형 변수 // 포인터 &ip는 (int *) 형을 가리킨다. 포인터 변수 이중 포인터 사용한 변수 참조 int val = 10; int *ip = &val; // int형 변수의 선언과 초기화 // 포인터 변수의 선언과 초기화 포인터 변수의 시작 주소 (200) &ip (200) 100 포인터 변수 ip 변수의 시작 주소 (100) 10 int형 변수 val
  • 59. 다중 포인터 이중 포인터 사용한 변수 참조 (계속) * * &ip (200) #include <stdio.h> int main() { int val=10; int *ip ; } (100) (10) //포인터 변수의 선언과 동시에 초기화 가능 (int * ip=&val) ip = &val; printf(“변수 val의 값 : %d n”, **&ip); return 0; 이중 포인터 변수 가리키는 자료형 int* * ipp ; ipp는 포인터 변수 변수이름 ipp = &var; //이중포인터를 이중 포인터 변수에 대입 가리키는 자료형은 모두 int * 형이다.
  • 60. 다중 포인터 이중 포인터 변수 (계속) int val = 10; int *ip ; int **ipp ; // int형 변수의 선언과 초기화 // 포인터 변수의 선언 // 이중 포인터 변수 선언 ip = &val ; // int 변수의 포인터를 포인터 변수에 저장 ipp = &ip ; // 포인터 변수의 포인터를 이중 포인터 변수에 저장 printf(“변수 val의 값 : %dn”, **ipp); 이중 포인터 변수 ipp (300) 200 (200) 포인터 변수 ip (100) 100 **ipp == ip 10 *ip == val **ipp == val int형 변수 val
  • 61. 배열 포인터 배열명의 역할  1) 첫번째 배열 요소를 가리키는 포인터로서의 기능 ex) int nums[5] = {10, 20, 30, 40, 50} ; int ip* = nums ; // 배열명은 포인터이므로 포인터 변수에 저장한다. printf(“%d n”, *nums); // 첫번째 기억 공간을 참조하여 10이 출력된다. printf(“%d n”, *(nums+4)); // nums의 값이 100이면 116번지 참조 nums 10 20 30 40 50  2) 배열의 기억공간 전체를 나타내는 논리적 변수의 기능 ex) int ary[5]; ary = 10; (0) // 배열명에 직접 값을 대입할 수 없다. ary[0] = 10; (x) // 특정 기억공간을 첨자로 지정하여 값을 대입해야 한다. ary int ary[5]; 크기 : 20byte 형태 : int형 변수 5개 int int int int 전체 20 byte int
  • 62. 배열 포인터 배열 포인터 배열 전체를 가리킨다. &ary ary 36 int int int int int int ary+1 40 int &ary 44 int 48 52 int 56 int 60 int 64 int int형 다섯 개의 배열을 가리키는 배열 포인터 68 int 72 … int int &ary+1 • ary + 1  1245036 + (1*sizeof(ary[0])  1245036+(1*4)  1245040 • &ary + 1  1245036 + (1*sizeof(ary)  1245036+(1*20)  1245056 ……
  • 63. 배열 포인터 첫번째 기억공간 두번째 기억공간 세번째 기억공간 *(ary+0) *(ary+1) *(ary+2) 배열요소의 참조는 배열명을 사용한다.  1차원 배열에서는 배열명으로 각 기억공간을 참조하므로 배열포인터를 구하는 것이 의미가 없다. 2차원 배열의 경우 int ary[3][4]; ary[0] ary[1] ary[2] 배열명 ary는 첫번째 부분 배열을 가리키는 배열포인터이다. ! ary int int int int int int int int int int int 배열 요소는 세 개 각 배욜 요소의 형태는 “int형 변수 네 개의 배열형” int 부분배열명은 각 부분배열의 첫번째 배열요소를 가리키는 포인터이다. !
  • 64. 배열 포인터 배열포인터 변수 가리키는 자료형 int형 변수 네 개의 1차원 배열 int (* ap) [4] ; ap는 포인터 변수다. 예제) 변수의 이름 괄호가 생략되면 포인터 배열(포인터 변수들의 배열)을 선언하는 형식이 되므로 주의 !!! # include <stdio.h> int main() { int ary[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int (*ap) [4] ; //int형 변수 네 개의 배열을 가리키는 배열 포인터 변수 int i, j; ap = ary; for(i=0; i<3; i++) { for(j=0; j<4; j++) { printf(“%5d”, ap[i][j]); } printf(“n”); } return 0; }
  • 65. 배열 포인터 2차원 배열에서 배열명으로 기억공간을 참조하는 원리  2차원 배열은 논리적으로는 2차원이지만 물리적으로는 1차원의 형태로 기억공간에 할당 ary 배열명 ary의 값은 배열의 시작위치값 100과 같다. 100 ary[0] 1 116 부분 배열명은 각 부분 배열의 시작 위치 값이다. ary[1] 5 132 ary[2] 9 104 2 120 6 136 10 • ary +1  100 + (1*sizeof(ary[0]))  100 + (1*16)  116 부분 배열명 ary[0]는 변수의 기능을 하며 부분배열 전체의 크기를 계산한다. • *(ary+1)  ary[1] //두 번째 부분 배열명 108 3 112 4 124 7 140 11 128 8 144 12
  • 66. 함수 포인터 함수명는 포인터  프로그램 실행시 함수가 존재하는 메모리의 위치값이 함수명이다.  함수를 (*sum)(10,20)과 같은 형태로 호출하는 것이 가능하다.  함수명이 포인터라는 증거 ! 함수의 정의 함수포인터(함수명) sum 함수명은 함수를 가리킨다. int sum(int a, int b) { int res; res = a + b; return res; } 함수 포인터 변수 함수의 형태 int sum (int, int) ; (리턴값의 형태) (매개변수의 객수와 형태) int (* fp) (int, int) ; • 가리키는 함수의 형태 Int형 값 두개를 전달 인자로 받고 Int형 값을 리턴하는 함수 변수의 이름 Fp는 포인터 변수다. • int *fp(int,int);  괄호가 없으면 포인터를 리턴하는 함수
  • 67. 함수 포인터 사용 예제 #include <stdio.h> int sum (int, int) // 함수의 선언 int main() { int (*fp) (int, int) ; // 함수 포인터변수 선언 int res; // 리턴값을 저장할 변수 fp = sum; // 함수명을 함수포인터변수에 저장한다. res = fp(10,20); // 함수포인터변수로 함수를 호출한다. printf(“result : %d n”, res); // 리턴값 출력 return 0; } int sum (int a, int b) { return a+b; } // 함수의 정의
  • 68. 함수 포인터 함수포인터의 사용  형태가 같은 다양한 기능의 함수를 선택적으로 호출하는데 사용 • int sum(int, int) ; // 두 정수값을 더해서 리턴하는 함수 형태가 같다. • int mul(int, int) ; // 두 정수값을 곱해서 리턴하는 함수 • int max(int, int) ; // 두 정수값 중에서 큰 값을 리턴하는 함수 • fp = sum ; int (*fp) (int, int); 정수의 합 계산 (sum) func( ); //func(sum); //func(mul); //fucn(max); • fp = mul ; • fp = max ; 정수의 곱 계산 (mul) 모두 사용 가능하다. 큰 값 계산 (max) 필요에 따라 원하는 긴으의 함수명을 전달인자로 주고 호출한다. void func(int (*fp)(int, int)) { … fp(a,b); … }
  • 69. 함수 포인터 사용 예제 #include <stdio.h> void func(int (*)(int, int)); // func 함수의 선언, 매개변수는 함수포인터 변수 int sum(int, int); // 두 정수값을 더하는 함수의 선언 int mul(int, int); // 두 정수값을 곱하는 함수의 선언 int max(int, int); // 두 정수값 중에서 큰 값을 구하는 함수의 선언 int main() { int sel ; // 메뉴 선택 번호를 저장할 변수 printf(“1. 두 정수의 합 n”); // 메뉴 출력 printf(“2. 두 정수의 곱 n”); printf(“3. 두 정수중 큰 값 선택 n”); printf(“ 원하는 작업을 선택하시오 : “ ); scanf (“%d”, &sel); switch(sel) { case 1: func(sum); break; case 2: func(mul); break; case 3: func(max); break; } return 0; }
  • 70. 함수 포인터 사용 예제 (계속) void func(int (*fp) (int, int)) { int a, b; int res; printf(“ 두 정수값을 입력 하시요 : “); scanf(“%d %d”, &a, &b); res = fp(a, b); printf(“결과값은 : %d n”, res); } 왜 함수 포인터를 사용하는가? int sum(int a, int b) {  프로그램의 유지 보수가 쉽다. return a+b ; } int mul (int a, int b) { return a*b ; } int max (int a, int b) { if(a >b) return a; else return b; }
  • 71. void 포인터 void 포인터  자료형에 대한 정보가 없다. (특별한 경우를 제외하고 사용할 경우가 거의 없다. --;)  다른 포인터에 형변환 연산자를 사용하여 강제로 만들어주어야 한다. int a ; (void * ) &a ; // int형 변수 선언 // int형 변수의 포인터를 void 포인터로 강제 형 변환 void 포인터 변수 가리키는 자료형이 정해져 있지 않다. void * vp; int in ; double db ; void *vp ; vp = & in ; vp = & db ; 변수의 이름. vp는 포인터 변수 // int형 변수 // double형 변수 // void 포인터 변수 // int형 변수의 포인터를 저장할 수도 있고, // double형 변수의 포인터도 저장할 수 있다.  vp는 자료형에 대한 정보가 없으므로 사용시 원하는 형태로 변환해야 한다. !!! printf(“%d n”, *(int *) vp); vp = (int * ) vp +1;
  • 72. void 포인터 사용 예제 #include <stdio.h> #include <string.h> void exchange(char *, void *, void * ) ; // 함수 선언 int main() { int a=10; b=20; // 정수형 변수 a, b double da=1.5, db=2.5; // 실수형 변수 da, db exchange(“int”, &a, &b); // 두 정수값의 교환 printf(“정수값 교환 후 : %d, %d n”, a, b); // 교환 후 결과 출력 exchange(“double”, &da, &db); printf( “실수값 교환 후 : %.11f, } // 두 실수값을 교환한다. %.11f n”, da, db) //교환 후 결과 출력
  • 73. void 포인터 사용 예제 (계속) void exchange (char *type, void *vp1, void *vp2) // 함수의 정의 { int itp; // 정수형 임시 변수 double dtp; // 실수형 임시 변수 if(strcmp(type, “int”) == 0) { itp=*(int *) vp1; *(int *) vp1 = * (int *) vp2; *(int *) vp2 = itp; } * (int *) vp1 if(strcmp(type, “double”) == 0) vp1을 (int *)형으로 변환. { dtp=*(double *)vp1; *(double *)vp1 = *(double *)vp2; *(double *)vp2 = dtp; } } 변환된 vp1이 가리키는 기억공간 참조