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 |