[C] 배열을 처리하려면..

장세민·2022년 9월 10일
0

📝 TIL

목록 보기
19/40

배열의 데이터를 처리하는 함수는 많은 양의 배열 데이터를 효과적으로 공유하는 방법이 필요하다.
함수로 배열을 처리하려면 포인터가 필요하다.

앞에서, 배열명첫 번째 배열 요소의 주소라고 했다.

이 주소 값을 함수의 인수로 주면,
함수는 이 값을 받아 주소 연산을 통해 모든 배열 요소를 사용할 수 있다.

이때 배열명을 받을 함수의 매개변수 자리에 포인터가 필요한 것이다!

📌 배열의 값을 출력하는 함수

배열의 값을 확인하려면 그 기능을 함수로 만들어 호출하면 쉬워진다
첫 번째 배열 요소의 주소만 알면 나머지 배열 요소는 포인터 연산으로 모두 사용할 수 있다.

따라서 함수를 호출할 때는 배열명을 주고 함수의 매개변수로 포인터를 선언한다.

그리고 함수 안에서 포인터를 배열명처럼 사용한다.

  1. # include <stdio.h>
  2.  
  3. void print_ary(int *pa);
  4.  
  5. int main(void)
  6. {
  7. int ary[5] = {10, 20, 30, 40, 50};
  8.  
  9. print_ary(ary);
  10.  
  11. return 0;
  12. }
  13.  
  14. void print_ary(int *pa)
  15. {
  16. int i;
  17.  
  18. for (i=0; i<5; i++)
  19. {
  20. printf("%d ", pa[i]);
  21. }
  22. }

배열 요소를 출력하는 print_ary 함수를 만들었다면
9행처럼

print_ary(ary);
다음과 같이 호출할 수 있다.

배열명은 첫 번째 배열 요소의 주소이며, 첫 번째 요소는 int형이므로
배열명을 함수의 인수로 준다는 건 int형 변수의 주소를 전달하는 것과 같다.

따라서 14행에서 매개변수로 int형 변수의 주소를 저장할 포인터를 선언한다.

배열이 메모리 100번지부터 할당되었다고 가정해보자.

그렇다면 print_ary 함수에서 ary 배열에 관해 알고 있는 유일한 정보는
pa에 받은 첫 번째 배열 요소의 주소 100번지 뿐이다.

이미 배열의 크기를 알고 있다고 가정하면
앞서 배운 내용처럼


  pa + 1		// 두 번째 배열 요소의 주소 104번지
*(pa + 1)		// 두 번째 배열 요소
   pa[1]		// 두 번째 배열 요소

나머지 배열 요소의 주소도 구할 수 있고,
배열 요소의 값도 사용할 수 있으며,
배열 요소 표현식을 통해 마치 pa도 배열명인 것처럼 사용할 수 있다.

위 예제에서는

print_ary 함수는 주소를 매개변수로 받아서 main 함수에 있는 배열의 값을 출력하는데,
쉽게 말해 동일한 배열의 데이터를 2개의 함수가 공유하고 있다는 것이다.

이와 같은 처리 방식은 배열에 있는 대량의 데이터를 다른 함수로 복사하지 않고 접근하므로 더 효율적!

🚨 함수 안에 선언된 변수나 배열 이름은 사용 범위가 중괄호 블록으로 제한되는 것 주의하자!


📌 배열 요소의 개수가 다른 배열도 출력하는 함수

배열의 값을 출력하는 함수는 첫 번째 배열 요소의 주소(=배열명)만 알면 되므로
배열 요소의 개수가 달라도 함수의 구현 방법은 똑같다.

  1. # include <stdio.h>
  2.  
  3. void print_ary(int *pa, int size);
  4.  
  5. int main(void)
  6. {
  7. int ary1[5] = {10, 20, 30, 40, 50};
  8. int ary2[7] = {10, 20, 30, 40, 50, 60, 70};
  9.  
  10. print_ary(ary1, 5);
  11. printf("\n");
  12. print_ary(ary2, sizeof(ary2) / sizeof(ary2[0]));
  13.  
  14. return 0;
  15. }
  16.  
  17. void print_ary(int *pa, int size)
  18. {
  19. int i;
  20.  
  21. for (i=0; i<size; i++)
  22. {
  23. printf("%d ", pa[i]);
  24. }
  25. }

10행과 12행에서 같은 함수를 호출하지만,
배열 요소의 개수를 달리하여 다른 배열을 출력한다.

함수가 호출되면 17행의 매개변수 size는 배열 요소의 개수를 받아 저장하고
21행에서 그만큼 반복하므로 출력할 배열 요소의 개수에 맞춰 모든 값을 출력할 수 있다.

함수를 호출할 때 주는 배열 요소의 개수는 sizeof 연산자로도 구할 수 있다.

print_ary(ary2, sizeof(ary) / sizeof(ary2[0]));

sizeof 연산자에 배열명을 사용하면 배열 전체의 크기를 계산하므로
이 값을 배열 요소 하나의 크기나누어 배열 요소의 개수를 구할 수 있다.


📌 배열에 값을 입력하는 함수

배열에 값을 입력하는 함수도 출력하는 함수와 구현 방법은 같지만,
입력함수는 데이터를 저장할 배열의 위치가 필요하므로 함수 안에서 포인터를 직접 사용한다.

  1. # include <stdio.h>
  2.  
  3. void input_ary(double *pa, int size);
  4. double find_max(double *pa, int size);
  5.  
  6. int main(void)
  7. {
  8. double ary[5];
  9. double max;
  10. int size = sizeof(ary) / sizeof(ary[0]); // 배열 요소의 개수 계산
  11.  
  12. input_ary(ary, size);
  13. max = find_max(ary, size);
  14. printf("배열의 최댓값: %.1lf\n", max);
  15.  
  16. return 0;
  17. }
  18.  
  19. void input_ary(double *pa, int size)
  20. {
  21. int i;
  22.  
  23. printf("%d개의 실수값 입력 : ", size);
  24. for (i=0; i<size; i++)
  25. {
  26. scanf("%lf", pa + i);
  27. }
  28. }
  29.  
  30. double find_max(double *pa, int size)
  31. {
  32. double max;
  33. int i;
  34.  
  35. max = pa[0];
  36. for (i=1; i<size; i++)
  37. {
  38. if (pa[i] > max) max = pa[i];
  39. }
  40.  
  41. return max;
  42. }

앞에서의 출력함수와 크게 다르지 않지만,
26행에서 각 배열 요소의 주소를 구하고 그 값을 그대로 scanf 함수에 사용하는 특징이 있다.

scanf 함수는 입력한 값을 저장할 배열의 위치를 알아야 하므로 인수로 받은 pa의 값을 그대로 사용한다.

30행의 find_max 함수는 배열에서 가장 큰 값을 찾아 반환하는 함수이다.
예전에 배웠던 내용에 포인터를 적용시킨 것 뿐이다.


+ 함수의 매개변수 자리에 배열을 선언하는 경우

void func(int pa[5])
void func(int pa[10])
void func(int pa[])
void func(double pa[5])

위 예시처럼 함수의 매개변수 자리에 배열을 선언하면 배열의 저장 공간이 할당되지 않으며,
배열명은 컴파일 과정에서 첫 번째 배열 요소를 가리키는 포인터로 바뀐다.

따라서 매개변수 자리에 선언된 배열에서 배열 요소의 개수는 의미가 없어 생략도 가능!

또한 매개변수 자리에 선언된 배열은 포인터로 바뀌므로
sizeof 연산을 수행하면 포인터 하나의 크기만 구해진다는 것도 기억하자.

profile
분석하는 남자 💻

0개의 댓글