본문 바로가기

C++ 일기

10. 배열 (array[])

자료형을 선언하다보면, 다음과 같이 여러 자료형들을 관리할 필요가 생긴다.

#include<iostream>

int main()
{
   int num0 = 1;
   int num1 = 2;
   int num2 = 3;
   int num3 = 4;
   int num4 = 5;
   // ...
}

이렇게 자료형이 같으면서, 여러 자료형을 다룰 때 배열을 사용할 수 있다.

 

배열은 서로 같은 자료형들의 연속된 메모리 공간이다.

배열은 여러 자료형들을 관리할 때 사용할 수 있는 자료구조 중 하나이며, 가장 기초적인 자료구조이다.

이는 후에 다룰 메모리 주소와 포인터, 참조의 개념에 밀접한 관계가 있으며,

배열의 사용을 익히면 효과적인 자료관리가 가능해진다.

 

 

배열의 선언은 배열에 넣을 여러 데이터들의 자료형, 배열의 이름, 배열의 크기순으로 선언할 수 있다.

#include<iostream>

int main()
{
   int arr[5] = { 0, 1, 2, 3, 4 };
}

이는 가장 기초적인 배열 선언으로, int자료형들의 값을 arr이라는 이름의 배열에 총 5개를 담겠다고 선언하는 것이다.

이렇게 선언된 배열은 이름 뒤 대괄호 안의 값을 index로 가지며, index는 배열의 몇번째 순서에 담긴 데이터인지 

구분하는 역할을 한다.

위의 arr[5]배열을 예로 들자면,

위와 같이 선언했을 경우 중괄호 맨 앞의 데이터가 arr[0]부터 담겨 순서대로 arr[4]까지 저장된다.

(arr[0] = 0, arr[1] = 1, arr[2] = 2 ...)

 

 

 

 

 

배열을 선언하는 방법은 여러가지 있는데, 아래의 코드로 설명하겠다.

#include<iostream>

int main()
{
   // 1. 배열의 크기를 명시하고 그 즉시 초기화
   int arr1[4] = { 0, 1, 2, 3 };
   
   // 2. 배열의 크기를 생략하고 초기화
   int arr2[] = { 0, 1, 2, 3, 4 };
   // 배열 안에 데이터가 몇개가 있는지를 바탕으로 배열의 크기를 자동으로 추론
   
   // 3. 크기를 지정한 후, 일부 요소만 초기화
   int arr3[5] = { 10, 20, 34 };
   // arr3[0] = 10, arr3[1] = 20, ... arr3[3] = 0, arr4[4] = 0;
   // 초기화하지 않은 요소들은 자동으로 0으로 초기화
   
   int arr4[10] = {};
   // 저장값: {0,0,0,0,0,0,0,0,0,0}
   
   int arr5[5];
   // 저장값 : -81248921, -8125912 등의 쓰레기값.
}

1. 배열의 크기를 명시하고 그 즉시 초기화하는 방법이다.

위 처럼 배열의 크기를 4로 명시하고, 그 즉시 = { }; 를 통해 배열 안의 데이터를 초기화하는 방법이다.

바로 위의 arr[5] 배열의 선언이 이와 같다.

 

2. 배열의 크기를 생략하고 초기화하는 방법이다.

위의 arr2[] 처럼 배열의 크기를 명시하지 않고, 배열의 초기화를 하더라도, 초기화한 값의 갯수 만큼

자동으로 배열의 크기를 정해준다.

arr2[]는 초기화한 데이터의 갯수가 0부터 4까지 총 5개이기 때문에, arr2[]는 arr2[5]로 배열의 크기가 정해진다.

 

3. 배열의 크기를 지정한 후, 일부 요소만 초기화하는 방법이다.

위 처럼 int자료형 5개를 저장할 수 있는 배열 arr3[5]에 3개의 값만 초기화해 저장한다면,

arr3[0], arr3[1], arr3[2]에만 초기화한 값이 저장되고, 나머지 arr[3], arr[4]에는 0으로 초기화되어 저장된다.

arr4[10] 처럼 일부 요소만 초기화 하는 것이 아니라 모든 값을 공란으로 두어도, 배열의 데이터는 자동으로 0으로

초기화된다.

단, arr5[5]처럼 초기화하지 않고 선언한다면 초기화가 되지 않은 쓰레기 값이 배열 안에 저장되므로,

배열을 통해 자료를 관리하고자 한다면 반드시 초기화하는 과정을 거치고 관리하여야한다.

 

 

 

배열의 초기화를 효율적으로 할 수 있는 방법중 하나가 바로 반복문 for를 사용하는 방법이다.

반복문 for를 통해 배열을 초기화하는 방법은 아래와 같다.

#include<iostream>

int main()
{
   int arr[5];
   
   for(int i = 0; i < 5 ; i++)
   {
      int arr[i] = i;
      std::cout << arr[i] << ' ' ;
   }
   // 출력값 0 1 2 3 4
}

일정한 규칙을 가진 자료형의 배열은 위처럼 반복문을 통해서 그 규칙에 맞게 배열을 선언해줄 수 있다.

 

 

 

 

 

#include<iostream>

int main()
{
   int mulArr[4][3] =
   { 1, 2, 3,
     4, 5, 6,
     7, 8, 9,
     10, 11, 12
   };
   std::cout << "0행 출력결과 :" << mulArr[0][0] << ',' << mulArr[0][1] << ',' << mulArr[0][2] << std::endl;
   std::cout << "1행 출력결과 :" << mulArr[1][0] << ',' << mulArr[1][1] << ',' << mulArr[1][2] << std::endl;
   std::cout << "2행 출력결과 :" << mulArr[2][0] << ',' << mulArr[2][1] << ',' << mulArr[2][2] << std::endl;
   std::cout << "3행 출력결과 :" << mulArr[3][0] << ',' << mulArr[3][1] << ',' << mulArr[3][2] << std::endl;
   // 출력값 : 0행 출력결과 : 1, 2, 3
   //          1행 출력결과 : 4, 5, 6
   //          2행 출력결과 : 7, 8, 9
   //          3행 출력결과 : 10, 11, 12
}

위와 같이, 배열의 선언을 다차원으로 할 수 있다.

위의 배열은 2차원 배열로, 행과 열로 구성하여 자료를 관리할 필요가 있을 시에 선언할 수 있다.

이처럼 arr[0] 행의 각 [0], [1], [2] 행에 1, 2, 3의 값이 담기게 되고,

이 특성을 이용하여 각 행의 값만 관리하거나, 각 열의 값만 관리하는 등 다양하게 이용할 수 있다.

 

 

 

 

 

 

 

배열은 연속된 메모리 공간에 같은 자료형들을 저장하는 것으로, 아래와 같이 주소값을 출력하게 함으로써

배열의 메모리 공간이 연속되어있는지를 알 수 있다.

#include<iostream>

int main()
{
   int arr[4] = { 0, 1, 2, 3 };
   
   for(int i = 0; i < 4; i++)
   {
      std::cout << "arr[" << i <<"] 에 저장되어있는 값 : "<< arr[i] << std::endl;
   }
   
   
   for(int i = 0; i < 4; i++)
   {
      std::cout << "arr[" << i <<"] 가 저장되어있는 메모리의 주소값 : "<< &arr[i] << std::endl;
   }
   /* 출력값
   arr[0] 에 저장되어있는 값 : 0
   arr[1] 에 저장되어있는 값 : 1
   arr[2] 에 저장되어있는 값 : 2
   arr[3] 에 저장되어있는 값 : 3
   arr[0] 가 저장되어있는 메모리의 주소값 : 0000007CB59CF4D8
   arr[1] 가 저장되어있는 메모리의 주소값 : 0000007CB59CF4DC
   arr[2] 가 저장되어있는 메모리의 주소값 : 0000007CB59CF4E0
   arr[3] 가 저장되어있는 메모리의 주소값 : 0000007CB59CF4E4
   */
}

메모리 공간의 주소값은 16진수로 표현되어있다. 16진수의 값의 차이를 알아보기위해 맨 뒤 두자리를 보면,

D8, DC, E0, E4로, 16진수는 9다음의 수를 알파벳 A부터 F까지 표현하므로 각각 4의 차이가 나는 것을 확인할 수 있다.

즉, 주소값을 저장하는 메모리 공간은 4바이트인 int형이고, 서로 연속되어있다는 것을 알 수 있다.

 

 

 

 

위의 다차원 배열의 주소값을 확인하기 위하여 아래와 같이 코드를 변형하였다.

#include<iostream>

int main()
{
   int mulArr[2][3] =
   { 1, 2, 3,
     4, 5, 6
   };
   std::cout << "0행 주소값 :" << &mulArr[0][0] << ',' << &mulArr[0][1] << ',' << &mulArr[0][2] << std::endl;
   std::cout << "1행 주소값 :" << &mulArr[1][0] << ',' << &mulArr[1][1] << ',' << &mulArr[1][2] << std::endl;
   /*
   0행 주소값 :000000B261FEF618,000000B261FEF61C,000000B261FEF620
   1행 주소값 :000000B261FEF624,000000B261FEF628,000000B261FEF62C
   */
}

위 다차원 배열의 주소값의 뒤 두자리를 보면, 0행 2열의 주소값 20과 1행 0열의 주소값 24로 4의 차이가 나며,

1행 0열의 주소값 24와 1행 1열의 주소값 28로 4의 차이가 나는 것으로 보아,

배열의 선언 자체는 다차원으로 선언할 수 있으나, 컴퓨터가 배열의 데이터를 저장하는 메모리는 연속된 공간으로,

병렬이 아닌 직렬로 메모리 공간을 연속해서 할당한다는 것을 알 수 있다.

 

즉, 사람에게는 mulArr[2][3]으로 편리하게 다차원 배열로 선언을 하였지만,

정작 컴퓨터에게는 mulArr[2][3]과 mulArr[6]은 같은 방식으로 메모리의 공간을 연속해서 할당한

동일한 배열이라는 것이다.

 

 

 

 

 

 

 

 

for문을 통한 배열의 관리 중, 배열 안의 값끼리 서로 비교하는 알고리즘을 구현할 수 있다고

9 - 2. 반복문 for를 통해 이야기한 적이 있다.

#include<iostream>

int main()
{
   int arr[6] = { 1, 1, 2, 2, 3, 4 };
   
   for(int i = 0; i < 6; i++)
   {
      for(int k = 0; k < i; k++)
      {
         if(arr[i] == arr[k])
            std::cout << arr[i] << ", ";
      }
   }
   // 출력값 : 1, 2
}

위는 arr[6]배열 안에서 각 인덱스 끼리 서로 비교하여 같은 값을 찾으면 그 값을 출력시키는 알고리즘이다.

하나의 인덱스에 저장된 값에 다른 인덱스에 저장되어있는 값 모두를 대입시켜 비교하는 것으로,

arr[0]의 값 1에 arr[1]의 값 1, arr[2]의 값 2, arr[3]의 값 2 .... 를 대입하여 검사하는 것이다.

'C++ 일기' 카테고리의 다른 글

11 - 2. 함수 오버로딩  (2) 2024.02.26
11 - 1. 함수  (2) 2024.02.26
9 - 2. 반복문 for  (0) 2024.02.23
9 - 1. 반복문 while  (0) 2024.02.23
8. switch문  (0) 2024.02.21