C++ Chapter 6.1 : 배열 기초

Date:     Updated:

카테고리:

태그:

인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!


배열은 동일한 크기의 연속된 메모리 공간

int a = 1;
int b = 2;
int c = 3;

int num[3] = {1, 2, 3}; // num[0] -> 1, num[1] ->2, num[2] -> 3
  • 변수 하나 하나에 대입하는 것 보다는 num이라는 배열로 한번에 1, 2, 3 값에 접근하는게 더 효율적
  • int를 담을 수 있는 4byte 크기의 메모리 공간이 연속으로 3개 붙어있는 공간을 빌려오는 것.(총 12byte)


배열의 선언과 초기화

int a[3] = {1, 2, 3};   // 정석 선언+초기화
int a[] = {1, 2, 3};   // 크기를 대괄호 안에 적어주지 않아도 초기화 값으로 보아 크기가 3인것을 알 수 있으므로 오류 X 
int a[5] = {1, 2};   // 오류 X. 크기를 5로 선언했으니 나머지는 0으로 채워져 {1, 2, 0, 0, 0}가 된다.
int a[5];  // 오류 X. 초기화는 안하고 선언만 한 상태. 4byte 크기의 연속된 5개의 메모리 공간을 가져온다. 쓰레기값으로 차있음
int a[];   // 오류! 크기를 알 수 없기 때문에. 총 몇 byte의 메모리 공간을 가져와야 하는지 알 수 없음.

C++ 11부터는 =을 빼고 int a[]{1, 2, 3};으로 쓸 수 있다.


응용

구조체 배열

struct Rectangle
{
	int length;
	int width;
};

int main()
{
	cout << sizeof(Rectangle) << endl; // 8 출력

	Rectangle rect_arr[10]; // 구조체 배열

	cout << sizeof(rect_arr) << endl; // 80 출력 ( = 8 * 10 )
return 0;
}

rect_arr[1].width = 2; 이런식으로 사용가능

배열에 enum 쓰기

enum StudentName
{
	JACKJACK,  // 0에 대치
	DASH,  // 1에 대치
	VIOLET, // 2에 대치
    NUM_STUDENTS,  // 3에 대치. 💛마지막에 넣어주니 전체 학생 수와 같아짐.💛
};

int main()
{
	int my_array[NUM_STUDENTS]; // 크기 3의 배열 선언. 초기화 전이라 쓰레기 값 가득
 
	my_array[JACKJACK] = 1; // my_array[0] = 1;
	my_array[DASH] = 100; // my_array[1] = 100;

	return 0;
}


배열 크기는 컴파일 타임에 결정된다.

int num_students = 0;
cin >> num_students;

int students_scores[num_students]; // 에러 ! !

num_students는 사용자 입력으로 값이 결정되므로 런타임에 결정된다. 그러나 배열 크기는 실행전에 미리 결정되있어야 한다. 컴파일 타임에 배열의 크기가 결정 되어 있어야 함. 따라서 마지막 줄은 에러다. cf) 런타임때 배열의 크기가 결정되는 배열을 동적 배열이라고 한다.

int a = 2;
int b[a]; // 에러 ! !

이 경우도 안된다. 변수 a 메모리 공간에 2가 할당되는건 런 타임 때 결정되는 것이여서.

const int a = 2;
int b[a]; // 정상 작동

이 경우엔 괜찮다. const가 붙은 상수는 컴파일 타임에 결정되기 때문에 int b[2]나 마찬가지라고 보기 보기 때문이다.


배열의 이름은 배열의 첫번째 원소의 주소 값이다.

#define NUM_STUDENTS 100000 
// 이렇게 매크로나 const 상수로 아주 큰수를 잡아두고 배열 크기를 미리 정하기도 한다. (런타임에 결정 못하니까)

int main()
{
    int students_scores[NUM_STUDENTS];

	cout << (int)&students_scores << endl; 
	cout << (int)&students_scores[0] << endl;
	cout << (int)&students_scores[1] << endl;
	cout << (int)&students_scores[2] << endl;
	cout << (int)&students_scores[3] << endl;

	cout << sizeof(students_scores) << endl;

	return 0;
}

  • (int)& : & 은 해당 변수의 주소를 리턴하라는 기호다. 주소값을 int호 형변환한 것.

  • 배열의 이름은 배열의 첫번째 원소 (인덱스 0)의 주소 값을 담고 있기 때문에 (int)&students_scores(int)&students_scores[0]은 동일한 값을 리턴한다.

  • 출력된 값을 보면 각 주소들이 4씩 차이나는 것을 알 수 있다. int 원소 하나의 크기가 4byte이기 때문에 주소값도 서로 연속해있는 원소마다 4씩 차이가 나는 것.

함수 파라미터로 배열을 넣으면 👀

using namespace std;

void doSomething(int students_scores[20]) // 얘는 배열이 아니고 포인터다.
{
    cout << (int)&students_scores << endl; // 💛포인터의 포인터
    cout << (int)&students_scores[0] << endl; // ⭐ 포인터에 배열의 주소를 복사해 온 후 이렇게 포인터로 배열 원소에 접근할 수 있게 됨
	cout << students_scores[0] << endl; 
	cout << students_scores[1] << endl;
	cout << students_scores[2] << endl;
}

int main()
{
	const int num_studnets = 20; 
	
	int students_scores[num_studnets] = { 1, 2, 3, 4, 5, };  // 사이즈 80  

    cout << (int)students_scores << endl;  // ⭐ 배열 이름으로서 배열의 첫번째 원소 주소값 
    cout << (int)&students_scores << endl; // ⭐ 배열 이름으로서 배열의 첫번째 원소 주소값 
	cout << students_scores[0] << endl; 
	cout << students_scores[1] << endl;
	cout << students_scores[2] << endl;
	
	doSomething(students_scores);

	return 0;
}
  • main()
    • int students_scores[num_studnets] = { 1, 2, 3, 4, 5, };
      • num_students는 const int로서 컴파일 타임에 결정된다.
      • 이 배열의 크기는 20이다.
      • 이 배열의 총 메모리 크기는 80이다.
        • sizeof(students_scores) = 80
      • 초기화는 인덱스4 까지만 됐으므로 그 뒤의 15개 원소는 전부 0으로 초기화된다.
    • students_scores&students_scores는 같다.
      • 배열 이름의 주소 = & 배열이름 = 배열 이름 = 배열의 첫번째 원소의 주소값
    • doSomething(students_scores) 호출
      • 배열 students_scores의 첫번째 원소의 주소값이 파라미터로 doSomething에 넘겨진다.
  • doSomething(int students_scores[20])
    • 👩🏻 int students_scores[20] 이건 배열이 아니라 포인터다!
      • 배열 이름을 통해서 주소값을 받을거라는 것을 표시하기 위해 이렇게 쓴 것일 뿐 포인터로서 작동된다.
        • [20] 숫자도 의미 없다. 그냥 20 크기짜리의 배열을 받을 포인터라는 표시일 뿐.
        • 함수의 매개변수로 배열을 선언하는것은 불가능하다.
        • 따라서 크기 또한 20 * 4 = 80이 아닌 그냥 하나의 주소값을 담는 int *로서 4 크기를 가진다.
          • sizeof(students_scores) = sizeof(int *) = 4
            • 64 bit 환경에선 sizeof(int *) = 8 이다.
        • 포인터 변수에 배열 이름을 대입 받으면 포인터 변수 이름과 []대괄호로 배열 원소에 접근할 수있다.
          • doSomething의 students_scores 포인터 변수로 main의 students_scores 배열 원소에 접근할 수 있게 됨
          • doSomething의 students_scores 포인터 변수와 main의 students_scores은 별개의 변수이다.
      • 포인터 변수로서 students_socres의 첫번째 주소값을 복사하여 넘겨 받는다.

      • ⭐끼리는 동일한 값이다. (주소가 같음. 즉 동일한 곳을 가리킴)
        • doSomething의 students_scores는 대괄호를 사용해서 main의 students_scores 배열 원소에 접근 가능해진다. 주소를 복사로 넘겨 대입 받았기 때문
      • 💛는 포인터의 포인터라서 다른 값.


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Cpp 카테고리 내 다른 글 보러가기

댓글 남기기