본문 바로가기

C언어

Chapter 15. 함수 인자 포인터

Chapter 15.함수 인자 포인터

함수에 인자 넘기는 포인터는 지칭한다.

이것을 잘 모르면변수를 잘 정의하고 사용할 지라도 다른 함수에 넘길 수 없기때문에 현재의 함수 안에서만 포인터 변수를 사용하게 될지도 모른다.

1차원 함수 인자 포인터

15_1.c

#include <stdio.h>

main()
{
void add(int *);
int imsi;

imsi = 100;
add(&imsi);

printf("imsi : %d\n", imsi);
}

void add(int *imsi)
{
*imsi = 1024;
}

gcc-o 15_1 15_1.c

./15_1

imsi : 1024

위 프로그램은 포인터를 다른 함수에 넘기기 위해서 어떻게 함수의 원형을 선언하고

본체는 어떻게 작성해야 하는지 그리고 호출할 때 주의할 것은 없는지 등을 알 수 있게 해준다.

1. 함수 원형

void add(int *);

인자로 포인터를 받아야 하므로 "int *"로 지정했다. 주소값을 받을때는 항상 '*'를 잊지 말자.

2. 함수 호출

add(&imsi);

호출 시에는 번지를 전달해야 하기 때문에&(주소연산자)를 사용해야 한다.

3. 함수 본체

void add(int *imsi);

main() 함수에서 정의한 것에 이름만 추가하면 된다.

main() 함수에서도add() 함수를 정의할 때 이름까지 추가해서 인자를 지정해도 되지만 컴파일러에 의해 무시된다.

컴파일러는 인자의 형(type)에만 관심을 있을 뿐이다. 하지만, 본체에서는 생략하면사용할 수 없다는것을잊지말자.

인자로 포인트를 넘기지 않으면 함수에 전달된변수의 값은 변화가 없다.

chapter 12에서의값에 의한 호출(call by value)참조에의한 호출(call by reference)를 기억하자.

int형 배열

15_4.c

#include <stdio.h>

main()
{
void add(int *, int);

int imsi[3] = {7, 4, 5};
int *imsip;
int i;
int length;

imsip = imsi;

length = sizeof(imsi)/sizeof(int);

add(imsip, length);
add(imsi, length);

printf("imsip : %d %d %d\n", // (1)
*imsip,
*(imsip + 1),
*(imsip + 2));

printf("imsi : %d %d %d\n", // (2)
*imsi,
*(imsi + 1),
*(imsi + 2));

printf("imsi : %d %d %d\n", // (3)
imsi[0],
imsi[1],
imsi[2]);

for(i=0;i<length;i++, imsip++)
printf("%d ", *imsip); // (4)

putchar('\n');

for(i=0;i<length;i++)
printf("%d ", imsi[i]); // (5)

putchar('\n');

//for(i=0;i<length;i++, imsi++)
//printf("%d ", *imsi); // (6)
}

void add(int *imsip, int length)
{
int i;
for(i=0;i<length;i++, imsip++)
*imsip += 10;
}

gc -o 15_3 15_3.c

./15_3

imsip : 27 24 25
imsi : 27 24 25
imsi : 27 24 25
27 24 25
27 24 25

//15_3.c: In function 'main'=>
//15_3.c: 44: error: invalid lvalue in increment

imsip를 사용하든 imsi를사용하든 모두 같은 값을 출력하고 있다.

조심할 것은 imsi는 배열명이기 때문에 imsi++ 같은 수식은 사용하지 못한다는 것이다.

문자열 포인터

15_4.c

#include <stdio.h>

main()
{
void incode(char *);
char imsi[] = "My name is archie";
char *imsip;

imsip = imsi;

printf("source : %s\n", imsip);
incode(imsip);
printf("incode : %s\n", imsip);
}

void incode(char *source)
{
while(*source)
{
*source = *source + 1;
source++;
}
}

gcc -o 15_415_4.c

./15_4

source : My name is archie
incode : Nz!obnf!jt!bsdijf

incode()함수 호출 시에 주소 값을 넘겨야 하며 imsip는 포인터 변수이므로 주소 값이 담겨져 있기 때문에 '&' 연산자가 필요없다.

1차원포인터 배열

15_5.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

main()
{
char *my_copy(char *);
void change(char **);
char *imsip[3];

imsip[0] = my_copy("Kim");
imsip[1] = my_copy("Soong");
imsip[2] = my_copy("Sun");

printf("source : %s %s %s\n", imsip[0], imsip[1], imsip[2]);
change(imsip);

printf("change : %s %s %s\n", imsip[0], imsip[1], imsip[2]);
}

char *my_copy(char *source)
{
char *temp;
temp = (char *)malloc(strlen(source)+1);

strcpy(temp, source);
return temp;
}

void change(char **temp)
{
*temp++ = "Jung";
*temp++ = "Jae";
*temp = "Une";
}

gcc -o 15_5 15_5.c

./15_5

source : Kim Soong Sun
change : Jung Jae Une

함수 원형에서 1차원 배열을받기 위해서는'*' 연산자가 두 개 필요하다.

함소 본체에서 1차원 배열을 넘겨 받기 위해서 '*' 연산자를 두 개 이용하였다.

배열이 포인터 변수일 때 이중 포인터를 사용한다는 것을 알아두자.

이중 포인터를 2차원과 연관지어 생각하는 사람이많은데 이중 포인터는 1차원과 밀접한 관련이 있는 포인터이다.

2차원 포인터 배열

잘 쓰이지는 않지만꼭알아두자.

int imsi[2][3] ={ {67, 54, 7}, {7, 4, 32} };

위의 2차원배열을 다루기 위한 포인터 변수는 아래와 같이 정의한다.

int (*imsi)[3];

주의할 것은 위의 포인터 변수는 딱 한개 생성된다는 것이다(3개가 아니다).

15_6.c

#include <stdio.h>

main()
{
void view(int (*)[3]);

int imsi[2][3] = { {67, 54, 7}, {7, 4, 32} };
int (*imsip)[3];

imsip = imsi;

view(imsip);
view(imsi);
}

void view(int (*temp)[3])
{
int i, j;

for(i=0;i<2;i++)
for(j=0;j<3;j++)
printf("[%d][%d] : %d\n", i, j, *(*(temp + i) + j));

puts("--------------");

for(i=0;i<2;i++)
for(j=0;j<3;j++)
printf("[%d][%d] : %d\n", i, j, *(temp[i] + j));

puts("--------------");

for(i=0;i<2;i++)
for(j=0;j<3;j++)
printf("[%d][%d] : %d\n", i, j, temp[i][j]);

putchar('\n');
}

gcc -o15_6 15_6.c

./15_6

[0][0] : 67
[0][1] : 54
[0][2] : 7
[1][0] : 7
[1][1] : 4
[1][2] : 32
--------------
[0][0] : 67
[0][1] : 54
[0][2] : 7
[1][0] : 7
[1][1] : 4
[1][2] : 32
--------------
[0][0] : 67
[0][1] : 54
[0][2] : 7
[1][0] : 7
[1][1] : 4
[1][2] : 32

[0][0] : 67
[0][1] : 54
[0][2] : 7
[1][0] : 7
[1][1] : 4
[1][2] : 32
--------------
[0][0] : 67
[0][1] : 54
[0][2] : 7
[1][0] : 7
[1][1] : 4
[1][2] : 32
--------------
[0][0] : 67
[0][1] : 54
[0][2] : 7
[1][0] : 7
[1][1] : 4
[1][2] : 32

보통 초보자나 중급자 반열에들어선 사람들에게 "2차원 배열을 함수에 넘길 때 어떻게 선언하느냐"고 질문하면 대부분 다음과 같이 대답한다.

voidview(int **temp);

1차원일때는 '*'연산자가 1개 였으니 2차원일 때는2개라고 생각한다.

포인터의 포인터는 포인터 배열을 다루기 위해서 사용되는 것이지 2차원 배열을 다루기 위해 사용되는 것이 아니다.

위의 예제를1차원으로 함수에넘길 수 있을까? 다음예제를보면 가능함을 알 수 있다.

15_7.c

#include <stdio.h>

main()
{
void change(int *);

int imsi[2][3] = { {67, 54, 7}, {7, 4, 32} };
int *imsip;

imsip = &imsi[0][0];
change(imsip);
}

void change(int *temp)
{
int i, j;

for(i=0;i<2;i++)
for(j=0;j<3;j++)
printf("[%d][%d] : %d\n", i, j, *temp++);
}

gcc -o15_7 15_7.c

./15_7

[0][0] : 67
[0][1] : 54
[0][2] : 7
[1][0] : 7
[1][1] : 4
[1][2] : 32

imsip가 가리킬 수 있는 대상체는 1차원이어야 하므로 imsi가 아닌 imsi[0][0]의 주소를 넘기고 있다.

2차원 배열이기때문에 포인터 변수를꼭 2차원으로 할 필요는 없지만, 위 프로그램처럼2차원 배열을 1차원적으로 받았기 때문에

"*temp++"를"temp[i][j]"와 같이 사용할 수 없게 된다.

단순출력에선 상관없지만 특정 배열 요소를 뽑아내기 위해선 계산이 복잡하다.

2차원 배열은 2차원적으로 처리하는 것이좋다.

'C언어' 카테고리의 다른 글

Chapter 18. 메모리 할당과 해제  (0) 2011.10.16
Chapter 19. 라이브러리  (0) 2011.10.16
Chapter 16. 함수 포인터  (0) 2011.10.16
Chapter 17. 구조체와 포인터  (0) 2011.10.16
Chapter 13. (int *)pointer  (0) 2011.10.16