프로그래머/CPP_메모

c++ 배열 정리

미역국마싯 2022. 3. 21. 10:07

목록

1. 선언과 초기화

  1. 선언
  2. 초기화

2. 배열에 접근 및 값 변경

  1. 배열 이름의 뜻
  2. 포인터 이용
  3. 참조 이용
  4. 인덱스 이용
  5. 주의할 점

3. 배열과 포인터

4. 배열을 인자로 넘길 때

5. 다차원 배열


 

선언과 초기화

1. 선언

TYPE 이름[const 개수];

visual stdio 컴파일러는 배열의 크기를 상수로 받도록 한다.

 

2. 초기화

int number[5] = {};		// 1

int number[10] = { 1,2,3 };	// 2

int number[] = { 1,2,3,4,5 };	// 3
  1. 모든 원소를 0으로 초기화
  2. 3번 째 원소까지 1, 2, 3으로 초기화하고 나머지는 0으로 초기화
  3. 데이터 개수만큼 크기를 설정

 

배열에 접근 및 값 변경

배열 이름의 뜻

struct Knight
{
	hp = 100;
	damage = 10;
};

int main()
{
	const int number = 10;
	Knight knights[number];
    
	auto WhatType = knights;    // auto == Knight*
}

auto를 통해 WhatType은 포인터를 가지고 있음을 알 수 있다.

즉, 배열의 이름을 넘겨준다는 것은 해당 배열의 시작 주소를 넘겨준다는 뜻이다.

 

1. 포인터 이용

Knight* knight1 = knights;
knight1->hp = 10;
knight1->damage = 1;

knight2 = knights + 1;
knight2->hp = 8;
knight2->damage = 2;

 

위 코드는 knights의 첫 번째와 두 번째 주소에 위치한 배열의 값을 변경해준다.

knights : Knight[ hp=10, damage=1 ], Knight[ hp=8, damage=2 ]...

knight1[ knights의 시작 주소 ]
knight2[ knights 시작 주소의 다음 주소 ]

 

2. 참조 이용

Knight& refKnight = *knights;
refKnight.hp = 20;
refKnight.damage = 5;

knights : <refKnight, Knight>[ hp=20, damage=5 ]...

knights의 시작 주소에 새로운 이름을 붙인다.

for (int i = 0; i < number; i++)
{
	Knight& refKnight = *(knights + i);
	refKnight.hp = 10;
	refKnight.damage = 1;
}

 

3. 인덱스 이용

knights[0].hp = 10;
knights[0].damage = 1;

for (int i = 0; i < number; i++)
{
	knights[i].hp = 10;
	knights[i].damage = 1;
}

 

주의할 점

위에서 소개한 접근 및 값 변경 방식은 배열에 존재하는 값을 변경하는 것이다. 이와 정반대로 사용할 수 있는 방식도 있다.

Knight temp = *(knights + 1);

knights의 2번 째 주소에 있던 값을 가져와서 temp에 저장한다. 헷갈리지 말자!


 

배열과 포인터

// [H] [e] [l] [l] [o] [ ] [W] [o] [r] [l] [d] [\0]
const char* strPtr = "Hello World";

char strArray[] = "Hello World";

앞에서 배열의 이름은 해당 배열의 시작 주소를 알려준다고 했다. 그런데 포인터도 Hello World가 저장된 바구니의 시작 주소를 가지고 있다. 둘은 차이가 없는걸까?

 

가장 큰 차이점은 따로 바구니( 메모리 공간 )를 만드는 유무이다.

strPtr [ 8 byte 주소 ]

strArray [H] [e] [l] [l] [o] [ ] [W] [o] [r] [l] [d] [\0]	// 12 byte

strPtr은 주소를 담는 8byte 크기의 바구니를 가지고 있지만, strArray는 시작 주소를 가리키는 바구니를 가지고 있지 않다. 배열은 그 자체로 커다란 데이터를 가지고 있다. 배열의 이름이 시작 주소를 의미하는 것과 시작 주소를 가지고 있는 것은 다르다!!

배열은 본체가 있고, 배열의 이름은 그 바구니 중에서 첫 번째 바구니를 의미할 뿐이다. 따라서 strArray는 데이터의 크기에 따라 바구니의 크기가 변한다.

배열의 이름은 배열의 시작 주소를 나타내지만, 배열의 본체( 바구니, 메모리 공간 )는 따로 있는 것이다.

따라서 포인터는 고정 크기를 가지고 배열은 데이터에 따라 크기가 정해진다.

 

헷갈리면 그냥 배열은 거대한 유사 포인터라는 느낌을 가지고 있자.


 

배열을 인자로 넘길 때

앞에서 배열의 이름은 첫 번째 주소를 의미한다고 했고, 배열의 본체는 따로 있다고 했다.

그렇다면 배열을 인자로 넘기면 포인터처럼 시작 주소를 넘겨줄까? 아니면 값 전달 방식처럼 배열의 데이터를 복사해서 넘겨줄까?

void Test(char str[])
{
	// char[] -> char*
	str[0] = 'A';
}

int main()
{
	char strArray[] = "Hello World";
	Test(strArray);
}

배열을 인자로 넘기면 배열의 첫 주소를 넘겨준다. 컴파일러가 배열을 포인터로 치환하기 때문이다. 즉, 배열의 전체 내용을 넘긴게 아니라 시작 주소만 넘긴 것이다. 따라서 strArray는 Aello World로 변경된다.


 

 

다차원 배열

int arrays[2][4] = {
	{ 1, 2, 3, 4 },
	{ 5, 6, 7, 8 }
};

for (int first; first < 2; first++)
{
	for (int second; second < 4; second++)
	{    
		int n = arrays[first][second];
	{
}

위 코드를 보면 다차원 배열을 사용하는 방법을 알 수 있다.

다차원 배열에서 알아야 할 점은 arrays의 첫 번째 배열과 두 번째 배열은 메모리 상에서 연속적으로 위치한다는 것이다.

arrays[2][4]
int array[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
서로 메모리 상에서 같다.

메모리 구조가 같다는 것은 1차원 배열과 다차원 배열은 성능 차이가 없다는 것!

'프로그래머 > CPP_메모' 카테고리의 다른 글

모듈러 연산( modular, 나머지 )  (0) 2022.04.21
c++ 연산자 오버로딩 정리  (0) 2022.04.03
c++ 참조 정리  (0) 2022.03.20
c++ 포인터 정리  (0) 2022.03.20
c++의 다양한 input 방법과 속도 비교  (0) 2022.03.17