정신과 시간의 방
작성일
2022. 12. 12. 16:19
작성자
risehyun
  • 배열이란
    형식이 같은 자료형 여러 개가 모여 새로운 하나를 이룬 형식을 뜻한다.
    즉, int 자료형 변수 5개가 모이면 int형 배열이 된다.
    배열이 기존의 변수와 가장 다른 점 중 하나는 변수의 이름과 달리 배열의 이름은 메모리의 주소라는 점이다.
    (추후 포인터를 배우면 더 명확해지겠지만, aList[i]가 있다면 여기서 배열 이름 aList는 변수가 아니라 0번 요소의 주소(&aList[0])를 뜻한다.)

    배열을 사용하면 구조가 간결하고 유지보수가 쉬운 좋은 코드를 만드는데 도움이 된다.
    연산에 참여하는 각 변수들을 이름으로만 접근하는 것이 아닌 '배열 연산자'를 활용해 접근할 수 있기 때문이다.

    이때 배열 연산자는 배열이름[인덱스] 형식을 가지며 동일한 형식으로 접근할 수 있다.
    배열은 0부터 시작하는 zero-based index를 가지기 때문에
    각 배열요소의 인덱스는 0에서부터 전체요소의 개수보다 1 작은 범위까지 이다.


  • 배열의 이름과 연산
    - 배열의 이름은 '주소상수'이기 때문에 변수가 아니다. 따라서 배열의 이름만 가지고는 연산자를 수행할 수 없다. 
      위의 예제에서 iArray[4]를 보면 인덱스를 사용해 특정 주소에 접근하고 있다.
      또한 iArray[10] = 10 역시 그냥 배열의 이름만 대입해서는 = 연산자가 작동하지 않으므로
      인덱스를 사용해 대입 연산자를 사용해야 한다.


  • 문자열 == 문자의 배열
    문자열의 실체는 char형 배열이다. 즉, 문자열을 다룬다는 것은 배열을 다룬다는 것이다.
    또한 문자열의 끝은 '\0'(NULL 문자)이다. 따라서 문자열을 저장하는 메모리 크기를 계산할 때 실수로 이 NULL문자가 들어갈 공간을 깜빡하지 않도록 유의해야 한다.

  • 문자열의 끝이 '\0' 인 이유 (공백문자, NULL문자)
    사용자가 문자열을 입력하면 확보된 메모리 크기만큼의 바이트 중 일부가 사용되어 문자열이 저장된다.
    이 때 NULL 문자를 중심으로 왼쪽은 사용된 영역이고 오른쪽은 사용되지 않은 영역으로 나뉜다.

    이처럼 프로그래머가 기술해야 할 배열의 크기는 늘 고정이지만 사용자의 입력은 늘 가변적이다.
    이런 유동적인 상황에 맞춰 문자열이 정확히 어느 지점에서 끝나는지를 알아야만
    값을 해석할 때 잘못된 메모리 공간을 침범하여 값이 이상하게 출력되는 오류가 발생할 수 있다.
    따라서 NULL문자는 이런 상황에서 문자열의 끝을 명확하게 구분해주는 구분자 역할을 해준다.

  • 다차원 배열
    메모리가 1차원 선형 구조인 배열을 1차원 배열이라고 한다.
    이 1차원 선형 구조를 여러 겹으로 쌓으면 2차원 면 구조가 된다.

    이처럼 다차원 배열은 메모리의 실제 모습과는 상관없이 논리적 구조가 2차원 혹은 3차원인 배열을 말한다.
    즉, 자료의 접근 방법에 한정되는 것이다.

    ※ 2차원 배열의 기본 문법
    기존의 1차원 배열과 달리 2차원 배열은 행(row)와 열(column)로 구성된 2차원 구조이다.
    그래서 2차원 배열을 선언할 땐 자료형 배열이름 [행][열]; 형식으로 기술한다.
    그리고 초기값을 정할 때도 1차원 배열과는 조금 다르다.
#include <stdio.h>

int main(void)
{
	// 3행 4열 int 배열 선언 및 정의
	int aList[3][4] = {
		{ 10, 20, 30, 40 },
		{ 50, 60, 70, 80 },
		{ 90, 100, 110, 120 }
	};

	int i = 0;
	int j = 0;

	// 행 단위 처리를 위한 바깥쪽 반복문
	for (i = 0; i < 3; ++i)
	{
		for (j = 0; j < 4; ++j)
		{
			printf("%d\t", aList[i][j]);

		}
		putchar('\n');
	}
	return 0;
}

 

여기서 i는 행의 인덱스이고 j는 열의 인덱스이다.
2차원 배열에 대해 배열연산을 한 번만 수행하면 이는 주소를 의미한 r-value가 된다.
예를 들어, aList[1]은 1번 행 전체를 의미하는 '주소상수'가 된다. 

※ 3차원 배열
3차원 배열 역시 앞서 살펴본 2차원 배열처럼 1차원 구조의 메모리를 논리적으로 3차원 접근하는 방법을 말한다.
2차원 배열이 개념적으로 행과 열의 구성이였다면, 3차원 배열은 두 가지 개념에 면(Plane)을 더하여 3차원을 이룬다.
따라서 2차원 배열의 배열이라고 생각하면 쉽게 이해할 수 있다.
이를 비유적으로 표현하자면 아파트 이름[단지][동][호]가 된다.

#include <stdio.h>

int main(void)
{
	// 면, 행, 열
	int aList[4][2][3] = { 0 };
	int i = 0, j = 0, k = 0, nCounter = 0;

	for (i = 0; i < 4; i++)
	{
		// 면
		printf("Plane number : %d\n", i);
		for (j = 0; j < 2; j++)
		{
			// 행
			for ( k = 0; k < 3; k++)
			{
				// 열
				aList[i][j][k] = ++nCounter;
				printf("%d\t", aList[i][j][k]);
			}
			
			putchar('\n');
		}
		printf("\n\n");
	}
	return 0;
}


대부분 배열이라는 개념보다 1차원 배열은 1차원 배열, 2차원 배열은 2차원 배열로 각각 구분해 생각하는 경향이 있지만,
2차원 배열은 1차원 배열 여러 개를 다루는 방식이다.

따라서 3차원 배열처리는 2차원 배열 여러 개를 다루는 방법으로 코드를 작성한다.

 

+ )

int main()
{
// 배열
// 배열은 메모리가 연속적인 구조이다.
// int형 변수 10개를 배열로 한번에 선언했을 경우
// 메모리상에 10개의 4바이트짜리 int가 연속적으로 할당되게 된다.
// 이때 초과된 11번째 데이터에 접근하려고 하면 의도된 배열이 아닌 곳에 접근하기 때문에
// 다른 변수에 침범하여 원하지 않았던 값을 가져올 가능성이 있다.

int iArray[10] = { };
// 배열의 이름을 정해주고 자료형 타입과 []안에 몇 묶음의 배열을 만들지 정한다.
// {} 안에는 10개 요소에 대한 초기값을 지정할 수 있다. 
// 괄호 안이 비어있으면 전체를 0으로 초기화하겠다는 뜻이다.

// 변수 안에 있는 값을 지칭해서 가지고 오려면 개별 요소에 접근해야 한다.
// 이때 사용하는 것이 인덱스 접근이다.

iArray[4]; // 배열의 5번째 요소에 접근한다. 
           // 배열 인덱스가 0부터 시작되기 때문에
           // 5번째 요소는 [4]가 된다.
           
iArray[10] = 10; // 배열의 총 크기인 10(0~9)을 넘는 초과인덱스(10)를 할당하는 잘못된 접근이다.
                 // 위에서 살펴보았듯 이러한 상황은 문제를 야기하므로
                 // 관련 예외가 발생하지 않도록 주의해야한다.
                 // 보통은 배열에 접근할 때 지금처럼 숫자를 바로 적는 것이 아니라
                 // 우회적으로 인덱스값 변수를 사용하여 접근하는 방식으로 
                 // 이러한 문제를 방지한다.

int iData = 100;

int iArray2[100] = { };

retun 0;
}

 

'C,C++ > [강의] 어소트락 C++' 카테고리의 다른 글

지역변수/전역변수  (0) 2022.12.28
구조체  (0) 2022.12.13
함수와 재귀함수  (0) 2022.11.28
VS 단축키 및 편의사항  (0) 2022.11.25
함수, 반복문  (0) 2022.11.24