프로그래밍/C

배열을 처리하는 함수

길냥이 2025. 6. 6. 23:41
728x90

목차

  1. 배열과 함수
  2. 배열을 출력하는 함수
  3. 배열 요소의 가변 출력 함수
  4. 배열 입력 함수
  5. 매개변수를 배열로 선언하는 함수

 

1. 배열과 함수

배열과 포인터를 배웠지만, 배열은 배열 그 자체로도 사용할 수 있고, 포인터도 배열과 연결해서 사용할 수 있었습니다.

뭐, 어느 방법으로든 쓸 수 있다는 거죠.

 

하지만 함수로 배열을 처리하려면 포인터가 필요합니다.

만약 함수로 배열을 그냥 넘겨버리면 어떻게 될까요?

 

함수는 배열을 받는 것이 아니라, 실질적으로 배열 첫 번째 요소의 주소(포인터)가 전달됩니다.

즉, 배열을 함수가 받으면 포인터를 받기 때문에 함수로 배열을 편집하면 실제 배열도 편집된다는 것이죠.

뭐, 그 자체만으로 메모리를 효율적으로 사용한다는 장점이 있지만, 원본 배열의 변형을 막을 수 없다는 위험성이 있겠네요.

 

원본 배열의 변형을 막고 싶다면, 이전에도 자주 사용했던 const를 이용하면 됩니다.

이러면 배열을 읽거나 출력할 수는 있지만, 수정은 불가능해요.

 

2. 배열을 출력하는 함수

그동안 배열을 만들고 출력하는 건 꽤나 귀찮은 일이었습니다.

for문을 사용한다던지, while문을 사용한다는지..

이걸 함수로 처리해보죠.

#include <stdio.h>

void print_array(int* p_array);   //함수 선언

int main(void) 
{
    int array[10] = { 10,20,30,40 };  //배열의 앞 4개의 값을 초기화하고, 나머지는 0으로 초기화합니다.

    print_array(array);  //배열 이름은 배열 첫 번째 요소의 주소(포인터)이므로 int*로 전달

    return 0;
}

void print_array(int* p_array)
{
    for (int i = 0; i < 10; i++)      //10번 반복
        printf("%d  ", p_array[i]);   //배열 요소에 접근할 때, p_array[i] 는 *(p_array + i)와 동일
}

출력은 다음과 같아요.

 

10  20  30  40  0  0  0  0  0  0

좋아요.

 

하지만 이 코드는 배열의 값이 늘어나면 함수의 for문 내의 크기를 수정해야 합니다.

배열의 값에 따라 함수 내의 순환 횟수를 정하는 방법은 없을까요?

 

3. 배열 요소의 가변 출력 함수

한번 sizeof를 이용해서 수정해 볼까요?

 

size = sizeof(p_array) / sizeof(p_array[0]);

를 이용해 보도록 합시다.

 

#include <stdio.h>

void print_array(int* p_array);   //함수 선언

int main(void)
{
    int array[10] = { 10,20,30,40 };  //배열의 앞 4개의 값을 초기화하고, 나머지는 0으로 초기화합니다.

    print_array(array);  //배열 이름은 배열 첫 번째 요소의 주소(포인터)이므로 int*로 전달

    return 0;
}

void print_array(int* p_array)
{
    int size = 0;

    size = sizeof(p_array) / sizeof(p_array[0]);  //배열의 크기를 배열 요소 하나로 나눕니다..?

    for (int i = 0; i < 10; i++)      //10번 반복
        printf("%d  ", p_array[i]);   //배열 요소에 접근할 때, p_array[i] 는 *(p_array + i)와 동일
}

자.. 아무래도 잘 돌아갈 거 같아요.

 

출력은 다음과 같습니다.

10 20

...

어라?

에.. 이거 왜 이래?

 

위에도 말했지만, 함수는 배열을 포인터로 받습니다. 

즉, p_array는 겉보기에는 배열같지만 실제로는 포인터형이라는 것이죠.

포인터형(8바이트)를 int형(4바이트)로 쪼개면.. size는 2가 나오고, 결과적으로 배열 요소는 2개만 출력됩니다.

 

여기선 다른 방법을 사용하죠. 매개변수를 2개 받아 봅시다.

#include <stdio.h>

void print_array(int* p_array, int size);   //함수 선언

int main(void)
{
    int array[10] = { 10,20,30,40 };  //배열의 앞 4개의 값을 초기화하고, 나머지는 0으로 초기화합니다.
    int size;

    size = sizeof(array) / sizeof(array[0]);  //배열의 크기를 배열 요소 하나로 나눕니다.

    print_array(array, size);  //배열 이름은 배열 첫 번째 요소의 주소(포인터)이므로 int*로 전달

    return 0;
}

void print_array(int* p_array, int size)
{
    for (int i = 0; i < size; i++)      //10번 반복
        printf("%d  ", p_array[i]);   //배열 요소에 접근할 때, p_array[i] 는 *(p_array + i)와 동일
}

이제 아주 편안해집니다.

 

출력은 다음과 같아요.

10  20  30  40  0  0  0  0  0  0

 

4. 배열 입력 함수

배열에 값을 입력하는 함수

 

배열에 값을 입력하는 함수와 배열의 값을 출력하는 함수의 구동 방법은 같습니다.

다만 입력받는 함수는 데이터를 저장할 배열의 위치를 찾아야 하므로, 함수 안에서 포인터 참조를 직접 사용해야 합니다.

 

한번 정수 배열에 값을 입력받고, 이 중 함수의 최대값과 최소값을 찾아볼까요..?

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

void insult_array(int* p_array, int size);   //함수 선언
int array_max(int* p_array, int size);
int array_min(int* p_array, int size);

int main(void)
{
    int array[10] = { 0 };  //배열의 앞 4개의 값을 초기화하고, 나머지는 0으로 초기화합니다.
    int size, max, min;

    size = sizeof(array) / sizeof(array[0]);  //배열의 크기를 배열 요소 하나로 나눕니다.

    insult_array(array, size);   //배열 이름은 배열 첫 번째 요소의 주소(포인터)이므로 int*로 전달
    max = array_max(array, size);     //최대를 계산할 함수 전달
    min = array_min(array, size);     //최소를 계산할 함수 전달

    printf("최대값 : %d\n", max);    //출력
    printf("최소값 : %d\n", min);

    return 0;
}

void insult_array(int* p_array, int size)
{
    printf("정수를 10개 입력하세요 : ");
    for (int i = 0; i < size; i++)      //size만큼 반복
        scanf("%d", &p_array[i]);    //배열 요소에 접근할 때, p_array[i] 는 *(p_array + i)와 동일
}

int array_max(int* p_array, int size)
{
    int max = p_array[0];     //배열 요소의 값으로 초기화

    for (int i = 0; i < size; i++)      //size만큼 반복
    {
        if (max < p_array[i])   //최대값 비교 연산
            max = p_array[i];
    }
    return max;
}

int array_min(int* p_array, int size)
{
    int min = p_array[0];     //배열 요소의 값으로 초기화

    for (int i = 0; i < size; i++)      //size만큼 반복
    {
        if (min > p_array[i])   //최소값 비교 연산
            min = p_array[i];
    }
    return min;
}

좋아요.

 

출력은 다음과 같습니다.

정수를 10개 입력하세요 : 34 7 56 12 89 23 45 78 5 16
최대값 : 89
최소값 : 5

 

이 코드는 본질적으로 위의 코드와 비슷합니다만..

 

scanf문 내에서 p_array[i]가 아닌 &p_array[i]를 이용합니다. 이유가 뭘까요?

음, 함수 내에서 p_array는 사실 배열이 아니라 int* 형입니다.

즉, 배열의 첫 번째 요소를 가리키는 포인터죠.

 

scanf는 메모리 주소를 필요로 합니다. 그래서 일반적으로 &을 요구하죠.

그래서 scanf의 인자로는 메모리 주소를 받아야 합니다.

p_array[i]는 값(value)이기 때문에 주소가 아닙니다.

 

배열은 주소라매요! 포인터랑 같이 쓴다매요!

하지만 뒤에 [i]가 붙어 있잖아요? 

따라서 저건 배열이 아닌 배열이 가진 값인  p_array[i]이고, 이는 배열이나 포인터가 아닌 int형이죠.

p_array[i] == *(p_array+ i) 와 같다는 걸 기억하세요.

 

따라서 scnaf에는 scanf("%d", p_array + i) 가 들어가야 합니다.

(배열값(포인터)에 i만큼 더함, 포인터 이동 연산)

 

혹은 scanf("%d", &p_array[i]) 라던가 말이죠.

(배열에 해당하는 값으로 이동, 이후 포인터 주소 추출)

 

뭐, 둘 모두 동일한 결과를 내니 편한 쪽을 사용하도록 하세요.

여담으로, &(참조 연산자)와 *(역참조 연산자)는 각각 같은 번 사용하면 달라지는게 없으므로 유의해주시길 바랍니다.

 

p_array[i] == *(p_array+ i) 이고 (배열의 요소 값)

&p_array[i] == p_array+ i 이죠! (배열 요소의 주소)

 

5. 매개변수를 배열로 선언하는 함수

흠, 함수의 매개변수 자리에 배열을 선언하면 어떨까요?

 

그동안 함수 매개변수 자리에는 정수, 실수, 문자열 등이 들어갔지만.. 배열을 직접 넣으면 어떨까요?

다음과 같이 만들 수 있습니다.

void print_array(int arr[])
{

}

 

함수는 배열을 받을 때 포인터를 받는다고 했죠, 따라서 함수의 매개변수 자리에 배열을 선언하면 실제 배열의 저장공간이 할당되지 않으며, 배열명은 컴파일 과정에서 포인터가 된답니다.

 

그래서 저런 매개변수 선언은 사실...

void print_array(int arr[]);

void print_array(int* arr);

와 의미가 동일하답니다.

 

따라서 매개변수 자리에 선언된 배열에서 배열 요소의 개수는 의미가 없습니다. 그냥 포인터가 되니까요..

 

하지만 여기 사소한 문제가 생기는데, 배열명을 매개변수로 받아버리면 배열의 크기를 구할 방도가 없어져 버리기 때문에..

배열 요소의 개수를 따로 받아야 합니다.

728x90