학습 목표 : 배열의 데이터를 처리하는 함수는 많은 양의 데이터를 효과적으로 공유하는 방법이 필요합니다. 이 절에서는 배열명을 인수로 받아 배열을 처리하는 함수에 대해 살펴봅니다.
배열과 포인터에 대해 배웠지만, 배열명을 꼭 포인터에 넣는 방식으로 배열을 처리할 필요는 없었습니다. 하지만 함수로 배열을 처리하려면 포인터가 필요합니다. ary배열에서 배열명 ary는 첫 번째 배열 요소의 주소 입니다. 이 주소 값을 함수의 인수로 주면, 함수는 이 값을 받아 주소 계산을 통해 모든 배열 요소를 사용할 수 있습니다. 이때 배열명을 받을 함수의 매개변수 자리에 포인터가 필요합니다.
int ary[5] = { 10, 20, 30, 40, 50 };
배열 요소를 출력하는 print_ary 함수를 만들었다면 다음과 같이 호출할 수 있습니다.
print_ary(ary);
배열의 모든 요소는 int형이며, 당연히 첫 번째 요소도 int형 입니다. 배열명을 함수의 인수로 준다는 건 결국 int형 변수의 주소를 전달한다는 겁니다. 따라서 매개변수로 받을 때는 int형 변수의 주소를 저장할 포인터를 선언해야 합니다.
void print_sry(int *pa)
배열의 값을 출력하는 함수
배열의 값을 확인하기 위해 수시로 출력해야 한다면 그 기능을 함수로 만들어 호출하면 됩니다. 이때 모든 배열 요소를 함수의 인수로 줘야 할까요? 첫 번째 배열 요소의 주소만 알면 나머지 배열 요소는 포인터 연산으로 모두 사용할 수 있습니다. 따라서 함수를 호출할 때는 배열명을 주고 함수의 매개변수로 포인터를 선언합니다. 그리고 함수 안에서 포인터를 배열명처럼 사용합니다.
배열명 자체가 주소이므로 그 값을 함수의 인수로 주는 것은 얼마든지 가능합니다. 예제를 통해 함수의 구체적인 사용법을 살펴보겠습니다.
#include <stdio.h>
void print_ary(int *pa);
int main(void)
{
int ary[5] = { 10, 20, 30, 40, 50 };
print_ary(ary);
return 0;
}
void print_ary(int *pa)
{
int i;
for (i = 0; i < 5; i++)
{
printf("%d ", pa[i]);
}
}
9행에서 배열명 ary를 주고 함수를 호출합니다. 배열명은 첫 번째 배열 요소의 주소이며, 첫 번째 요소는 int형이므로 결국 int형 변수의 주소가 함수에 전달됩니다. 따라서 14행에서 매개변수로 int형을 가리키는 포인터 pa를 선언합니다. 함수가 호출되어 14행이 실행될 때의 상황은 다음과 같습니다. 배열은 메모리 100번지부터 할당되었다고 가정합니다.
print_ary함수에서 ary배열에 관해 알고 있는 유일한 정보는 pa에 받은 첫 번째 배열 요소의 주소 100번지 뿐 입니다. 이미 배열의 크기를 알고 있다고 가정하면 그걸로 충분합니다. pa에 정수를 더하면 나머지 배열 요소의 주소를 구할 수 있고, 간접 참조 연산으로 가리키는 배열 요소의 값도 사용할 수 있습니다. 이때 배열 요소 표현식을 쓰면 마치 pa도 배열명인 것처럼 사용할 수 있습니다.
정수연산 | pa + 1 | 두 번째 배열 요소의 주소 104번지 |
간접 참조 연산 | *(pa + 1) | 두 번째 배열 요소 |
배열 요소 표현식 | pa[1] | 두 번째 배열 요소 |
결국 20행의 출력문은 i 값이 증가하면서 ary 배열의 모든 값을 출력합니다. 이제 배열의 값을 출력할 때는 언제든지 배열명 ary를 주고 print_ary 함수를 호출하면 됩니다.
눈치가 빠르면 쉽게 짐작하겠지만 이 예제는 동일한 배열의 데이터를 2개의 함수가 공유합니다.
print_ary함수는 주소를 매개변수로 받아서 main 함수에 있는 배열의 값을 출력합니다. 이와 같은 처리 방식은 배열에 있는 대량의 데이터를 다른 함수로 복사하지 않고 접근하므로 더 효율적입니다. 다만 주소만 알면 해당 위치의 값을 바꿀 수도 있으므로 의도치 않게 값을 변형하는 일이 없도록 주의해야 합니다.
배열 요소의 개수가 다른 배열도 출력하는 함수
배열의 값을 출력하는 함수는 첫 번째 배열 요소의 주소만 알면 되므로 배열 요소의 개수가 달라도 함수의 구현 방법은 같습니다. 다만 배열 요소의 개수가 바뀌면 출력문의 반복 횟수가 달라지므로 함수의 수정은 불가피합니다. 이번에는 배열 요소의 개수가 달라도 원하는 배열을 출력할 수 있는 함수를 만들어보겠습니다.
#include <stdio.h>
void print_ary(int *pa, int size);
int main(void)
{
int ary1[5] = { 10, 20, 30, 40, 50 };
int ary2[7] = { 10, 20, 30, 40, 50 };
print_ary(ary1, 5);
printf("\n");
print_ary(ary2, 7);
return 0;
}
void print_ary(int *pa, int size)
{
int i;
for (i = 0; i < size; i++)
{
printf("%d ", pa[i]);
}
}
10행과 12행에서 같은 함수를 호출하여 다른 배열을 출력합니다. 10행은 ary1의 배열 요소의 개수 5를 전달하여 print_ary 함수를 통해 ary1의 배열을 출력합니다.
12행은 ary2의 배열 요소의 개수 7을 전달하여 print_ary 함수를 통해 ary2의 배열을 출력합니다. 함수가 호출되면 17행의 매개변수 size는 배열 요소의 개수를 받아 저장하고 21행에서 그만큼 반복하므로 출력할 배열 요소의 개수가 바뀌어도 그에 맞춰 모든 배열 요소의 값을 출력할 수 있습니다.
함수를 호출할 때 주는 배열 요소의 개수는 sizeof 연산자로 구할 수도 있습니다. sizeof 연산자에 배열명을 사용하면 배열 전체의 크기를 계산하므로 이 값을 배열 요소 하나의 크기로 나누어 배열 요소의 개수를 구합니다. 예를 들어 12행을 다음과 같이 작성할 수 있습니다. 수정한 다음 직접 컴파일 해 보세요.
print_ary(ary2, sizeof(ary2) / sizeof(ary2[0]));
배열에 값을 입력하는 함수
배열에 값을 입력하는 함수도 배열의 값을 출력하는 함수와 구현 방법은 같습니다. 다만 입력 함수는 데이터를 저장할 배열의 위치가 필요하므로 함수 안에서 포인터를 직접 사용합니다. 예제를 통해 실수 배열에 값을 입력하는 함수와 최댓값을 찾는 함수를 살펴보겠습니다.
#include <stdio.h>
void input_ary(double *pa, int size);
double find_max(double *pa, int size);
int main(void)
{
double ary[5];
double max;
int size = sizeof(ary) / sizeof(ary[0]);
input_ary(ary, size);
max = find_max(ary, size);
printf("배열의 최댓값 : %.1lf\n", max);
return 0;
}
void input_ary(double *pa, int size)
{
int i;
printf("%d개의 실수값 입력 : ", size);
for (i = 0; i < size; i++)
{
scanf("%lf", pa + i);
}
}
double find_max(double *pa, int size)
{
double max;
int i;
max = pa[0];
for (i = 1; i < size; i++)
{
if (pa[i] > max) max = pa[i];
}
return max;
}
이 예제는 double형 배열에 값을 입력하는 함수와 입력한 값 중에서 최댓값을 찾아 반환하는 함수를 만듭니다. 이미 살펴본 배열의 값을 출력하는 함수와 크게 다르지 않습니다. 다만 26행에서 pa에 i를 더하여 각 배열 요소의 주소를 구하고 그 값을 그대로 scanf함수에 사용하는 특징이 있습니다.
scanf 함수는 입력한 값을 저장할 때 배열의 위치를 알아야 하므로 인수로 받은 pa의 값을 그대로 사용합니다. 물론 *(pa+i) 의 연산으로 배열요소를 구하고 다시 &(*(pa+i))와 같이 주소 연산을 사용하는 방법도 가능하지만 불필요한 연산은 반복하지 않는 것이 좋습니다. 다만 대괄호를 사용한 배열 요소 표현식이 익숙하다면 &pa[i]의 표현도 나쁘지 않습니다.
30행의 find_max 함수는 배열에서 가장 큰 값을 찾아 반환하는 함수입니다. 우선 35행에서 첫 번째 배열 요소를 가장 큰 값으로 가정하고 변수 max에 저장합니다. 그리고 38행에서 다른 배열 요소와 max의 값을 비교하여 큰 값을 max에 저장합니다. 결국 나머지 배열 요소와 max의 값을 비교하여 큰 값을 max에 저장하는 작업을 반복하면 모든 배열 요소 중에서 가장 큰 값이 max에 저장됩니다. 마지막으로 max의 값을 반환하여 호출한 곳에서 사용합니다. 예제에는 생략되었지만 필요하다면 배열의 값을 출력하는 함수도 만들어보시기 바랍니다.
마무리
- 배열을 출력하는 함수에 필요한 것은 배열명이다.
- 배열에 입력하는 함수에 필요한 것도 배열명이다.
- 배열의 크기가 달라도 입출력이 가능하려면 배열 요소의 개수를 알아야 한다.
'C언어' 카테고리의 다른 글
논리야 놀자 #1 (0) | 2023.09.08 |
---|---|
혼공C 도전실전 예제 내 풀이 (0) | 2023.08.17 |
[C언어] 배열과 포인터 (0) | 2023.08.13 |
[C언어] 포인터 완전 정복하기 (0) | 2023.08.12 |
[C언어] 포인터 (0) | 2023.08.03 |