[C] ???: 체력 측정 결과 종합해라.

장세민·2022년 10월 16일
1

📝 TIL

목록 보기
25/40
post-thumbnail

귀찮은 일이 생겼다.
중대장님이 실망하지 않게 서두르자.

Before Starting

한 명의 팔굽혀펴기, 윗몸일으키기, 뜀걸음 등급을
배열로 처리해보면 다음과 같을 것이다.

만약 여러 명의 측정 결과를 처리하려면 같은 형태의 배열이 명 수 만큼 필요할 것이다.

인원이 적다면 괜찮겠지만,
그렇지 않다면 이렇게 따로 배열을 만들어서 관리하기는 힘들 것이다.

이럴 때 2차원 배열을 사용한다.


🔔 2차원 배열은 행렬의 구조와 같다.

이게 무슨 말 인지 한 번 알아보자.



📌 다차원 배열

📖 2차원 배열 선언과 요소 사용

형태가 같은 배열이 여러 개 필요한 경우 이들을 모아 배열을 만들 수 있다.
이 배열을 2차원 배열이라고 하고,

2차원 배열은 1차원 배열을 요소로 갖는 배열이다.

예를 들어, 한 명의 측정 결과를 처리할 때는 요소가 3개인 int형 배열 하나면 되지만,
3명으로 늘어나면 같은 형태의 1차원 배열이 3개 필요하다.

이렇게 2차원 배열을 선언하면 메모리 주소에 변화가 생긴다.

1차원 배열을 하나씩 선언했을 때는 각각의 배열이
앞의 그림처럼 각기 다른 메모리 주소에 할당될 수 있지만,

2차원 배열로 한 번에 선언하면 각 배열은 연속성을 지니게 된다.

병사 4명의 3 종목 평균을 구해보자.

  1. #include <stdio.h>
  2.  
  3. int main(void)
  4. {
  5. int rank[4][3];
  6. int total, avg;
  7. int i, j;
  8.  
  9. for (i = 0; i < 4; i++)
  10. {
  11. printf("3종목 등급 입력 : ");
  12. for (j = 0; j < 3; j++)
  13. {
  14. scanf("%d", &rank[i][j]);
  15. }
  16. }
  17.  
  18. for (i = 0; i < 4; i++)
  19. {
  20. total = 0;
  21. for (j = 0; j < 3; j++)
  22. {
  23. total += rank[i][j];
  24. }
  25. avg = total / 3;
  26. printf("평균: %d\n", avg);
  27. }
  28.  
  29. return 0;
  30. }
  31.  

rank[4][3]에서 3은 1차원 배열 요소의 개수,
4는 1차원 배열을 요소로 가지는 2차원 배열 요소의 개수이다.

20행의 total 변수는 병사별로 총 등급을 누적해야 하므로
이전 병사의 총 등급이 함께 누적되지 않도록 0으로 초기화해야 한다.

행렬로 이해하자!

결국 rank 배열은 등급을 저장할 수 있는 int형 변수가 12개 있는 셈이며,
배열명에 행 첨자열 첨자를 지정하여 각 요소를 지목할 수 있다.

이때 위치를 지정하는 규칙은
행 첨자와 열 첨자는 0부터 시작하며,
최댓값은 행의 수 -1열의 수 -1이다.


세 번째 병사의 윗몸 일으키기 등급 -> rank[2][1]


예를 들어, 세 번째 병사의 윗몸 일으키기 등급은
3행 2열의 요소가 되며 행 첨자는 2, 열 첨자는 1을 사용한다.


메모리에서의 2차원 배열

2차원 배열은 논리적으로는 행렬의 구조를 가지고 있지만,
물리적으로는 1차원 배열의 형태로 메모리에 할당된다.

할당되는 방법은 한 행씩 차례로 할당된다.

예를 들어, 2차원 배열 int rank[2][2];은 다음과 같이 메모리에 할당된다.

이렇게 물리적으로 [2][2] 위치에 있는 요소가 rank 배열의 몇 번 첨자인지는
간단한 배열에서는 세기 쉽지만, [99][99] 정도의 배열이라면
하나씩 세기 어려울 것이다.

🔔 Tip: 첨자는 0부터 시작하니 9번째 있으면 위치 값은 8

행 첨자

1차원 배열로 계산했을 때의 위치 / 열의 수

8 / 3 = 2

열 첨자

1차원 배열로 계산했을 때의 위치 % 열의 수

8 % 3 = 2

결국 3개씩 끊었을 때 몇 번째 그룹인지가 행 첨자가 되고
나머지가 그 그룹에서 몇 번째에 있는지 해당되므로 열 첨자가 된다.

할당된 메모리의 9번째 공간의 첨자는

rank[(9-1) / 3] [(9-1) % 3] → rank[2][2]

다음과 같이 계산할 수 있다.



📖 2차원 배열 초기화

2차원 배열을 함수 내에서 선언하면 자동 변수와 같이 메모리에 남아 있는 쓰레기 값을 지니게 된다.

따라서 선언과 동시에 초기화해야 한다.
2차원 배열의 초기화는 중괄호 쌍 2개를 써서 행 부분을 표시한다.

  1. #include <stdio.h>
  2.  
  3. int main(void)
  4. {
  5. int num[3][4] = {
  6. {1, 2, 3, 4},
  7. {5, 6, 7, 8},
  8. {9, 10, 11, 12}
  9. };
  10. // int num[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };와 같은 문장
  11.  
  12. int i, j;
  13.  
  14. for (i = 0; i < 3; i++)
  15. {
  16. for (j = 0; j < 4; j++)
  17. {
  18. printf("%5d", num[i][j]);
  19. }
  20. printf("\n");
  21. }
  22.  
  23. return 0;
  24. }
  25.  

10행과 같이 한 줄로 작성해도 되지만 행렬 구조를 코드에 표현하는 것이 좋다.



일부 초깃값 생략

기본 배열 전체 초기화 이외에도 일부 초깃값을 생략하는 것도 가능하다.
5~9행을 다음과 같이 초깃값을 부족하게 수정 후 컴파일을 진행하면,

int num[3][4] = { {1}, {5, 6}, {9, 10, 11} };

각 행의 앞에서부터 차례로 값을 저장하고 남는 요소는 0으로 자동 초기화한다.



행의 수 생략

또한, 행의 수를 아예 생략하고 선언할 수 있다.

int num[][4] = { {1}, {2, 3}, {4, 5, 6} };

이 경우 컴파일러는 행의 중괄호의 개수를 행으로 결정하고,
한 행의 크기는 열의 수로 결정한다.

따라서 초기화할지라도 열의 개수는 생략할 수 없다!



1차원 배열처럼 초기화

2차원 배열은 물리적으로 1차원 배열의 나열이기 때문에
초기화할 때 행 초기화 괄호를 생략하고 1차원 배열을 초기화하는 방식으로 같게 할 수 있다.

이 경우 전체 저장 공간의 수만큼 초깃값을 나열하며, 행 단위로 차례로 저장한다.

int num[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

🔔 정리

저장 공간의 수보다 초깃값이 적은 경우는 남는 저장공간은 모두 0으로 초기화!



1차원 배열 = 부분 배열

2차원 배열은 1차원 배열을 요소로 갖는 1차원 배열이므로

배열 요소의 개수 = 행의 개수
배열 요소의 형태 = 열의 개수

임을 기억하자!

이때 각 행은 1차원 배열의 형태를 가지며, 2차원 배열의 부분배열이다.
부분배열은 2차원 배열에서 하나의 배열 요소가 되므로
배열명과 첨자를 사용하여 표현한다.

부분배열명은 1차원 배열의 배열명이며, 각 행의 단위를 독립적으로 처리할 때 배열명의 역할을 수행!

따라서 행의 수(부분배열의 수)를 계산하고 싶으면

행의 수 = 배열 전체의 크기 / 부분배열 하나의 크기

기억하자!

📖 2차원 char 배열

하나의 문자열을 저장하기 위해 1차원 char 배열이 필요하듯이
2차원 char 배열은 여러 개의 문자열을 처리할 때 사용한다.

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5. char animal[5][20] = {};
  6. int i;
  7. int count;
  8.  
  9. count = sizeof(animal) / sizeof(animal[0]);
  10. for (i = 0; i < count; i++)
  11. {
  12. scanf("%s", animal[i]);
  13. }
  14.  
  15. for (i = 0; i < count; i++)
  16. {
  17. printf("%s", animal[i]);
  18. }
  19.  
  20. return 0;
  21. }

5행에서 animal 배열을 선언하면 다음과 같이 100개의 char형 저장 공간이 생긴다.
한 행은 하나의 문자열을 저장하는 부분배열이고, 부분배열명이 각 행의 배열명의 기능을 한다.

scanf("%s", animal[0]);

animal[0]은 배열명으로 부분배열의 시작 위치 값이다.
따라서 앞에 주소 연산자 &를 붙일 필요가 없다.


2차원 char 배열 초기화

2차원 char 배열을 초기화하는 방법은 두 가지가 있다.

1. 다른 2차원 배열처럼 배열 요소를 하나씩 초기화

2. 각 행의 단위를 문자열로 초기화

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5. char animal1[5][20] = {
  6. {'d', 'o', 'g', '\0'},
  7. {'t', 'i', 'g', 'e', 'r', '\0'},
  8. {'r', 'a', 'b', 'b', 'i', 't', '\0'},
  9. {'h', 'o', 'r', 's', 'e', '\0'},
  10. {'c', 'a', 't', '\0'}
  11. };
  12.  
  13. char animal2[][10] = {"dog", "tiger", "rabbit", "horse", "cat"};
  14. int i;
  15.  
  16. for (i = 0; i < 5; i++)
  17. {
  18. printf("%s ", animal1[i]);
  19. }
  20. printf("\n");
  21. for (i = 0; i < 5; i++)
  22. {
  23. printf("%s ", animal2[i]);
  24. }
  25.  
  26. return 0;
  27. }
  28.  

2차원 char 배열은 char형 변수들의 집합이므로 문자 상수로 초기화할 수 있다.
또는 1차원 char 배열을 요소로 가지므로 각 행이 되는 1차원 char 배열을 문자열로 초기화할 수 있다.



📖 3차원 배열

1차원 배열에서 2차원 배열을 만드는 과정을 이해하면 3차원 이상의 배열도 가능하다.
마찬가지로, 3차원 배열은 2차원 배열을 요소로 가지며, 3개의 첨자를 사용하여 선언한다.


2개 생활관 병사 4명의 3종목 등급을 저장하는 3차원 배열을 만들어보자.

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5. char rank[2][4][3] = {
  6. { { 1, 1, 2 }, { 1, 2, 3 }, { 1, 1, 1 }, { 2, 2, 2 } },
  7. { { 3, 3, 3 }, { 2, 1, 1 }, { 3, 2, 2 }, { 1, 2, 2 } }
  8. };
  9.  
  10. int i, j, k;
  11.  
  12. for (i = 0; i < 2; i++)
  13. {
  14. printf("%d 생활관 등급...\n", i + 1);
  15. for (j = 0; j < 4; j++)
  16. {
  17. for (k = 0; k < 3; k++)
  18. {
  19. printf("%5d", rank[i][j][k]);
  20. }
  21. printf("\n");
  22. }
  23. printf("\n");
  24. }
  25.  
  26. return 0;
  27. }

1 생활관이 체력 수준이 더 높다.



🔔 정리

2차원 배열에서 각 행은 1차원 배열로서 하나의 2차원 배열의 부분배열이 되고,
3차원 배열에서는 2차원 배열이 부분배열이 된다.

2차원 배열을 행렬 구조로 본다면 3차원 배열은 , , 의 구조가 된다.

따라서 3차원 배열 rank에는 rank[0], rank[1]의 2개의 면부분배열
각 면부분배열을 구분하는 행부분배열이 존재한다.


3차원 배열의 초기화는 면을 구분하는 중괄호가 추가되어 중괄호 3쌍을 사용한다.

초깃값이 저장 공간에 채워지는 순서나 초깃값이 부족한 경우
남는 저장 공간을 채우는 방식은 2차원 배열과 같다.

각 저장 공간을 사용하는 방법은 , , 순서로 3개의 첨자를 사용하며,
각 첨자들은 0부터 사용하므로 사용한 요소 수보다 하나 적은 값이 최댓값이 됨!



3차원 배열을 처리할 때는 논리적 구조를 잘 따져보자!

profile
분석하는 남자 💻

0개의 댓글