본문 바로가기
Script/C++

[C++] Chapter 03. 포인터#2 (포인터 vs 배열)

by song.ift 2023. 5. 11.

배열 기초

배열의 크기는 상수여야함. (VC 컴파일러 기준. 다른 컴파일러는 상수값이 아니여도 통과될 수 있음)

배열의 이름은 배열의 데이터가 아니라 배열의 시작주소이다. (첫번째 시작주소)

정확히는 시작 위치를 가리키는 TYPE* 포인터이다.

 

포인터 vs 배열

const char* test1 = “Hello World”;

char test2[] = “Hello World”;

둘이 비슷하게 설정된다는 점에서 포인터와 배열이 똑같아보인다고 하지만 이는 전혀 다르다. (둘이 어셈블리 코드도 다름)

 

test1 = “Hellow World”;

  • .data 주소[H][e][l][l][o][][W][o][r][l][d][\0]
  • readonly 데이터임
  • test1[ 주소 ] << 8바이트
  • 데이터 영역 어딘가에 문자배열을 만들어준 다음에 바구니에 시작 주소를 넣어준거임

 

char test2[] = “Hello World”;

  • 어셈블리 코드로 보면 4바이트씩 복사하고 있음
  • test2는 test1처럼 별도의 바구니가 만들어진게 아님. (포인터와 배열의 가장 큰 차이)

 

  • 포인터는 [주소를 담는 바구니]
  • 배열은 [닭장] 즉, 그 자체로 같은 데이터끼리 붙어있는 ‘바구니 모음’
  • “Hello World” 이거 자체가 배열이라는 것이지. test1처럼 따로 뽑혀가지고 관리되는 개념이 아니다.
  • 다만 [배열 이름]은 ‘바구니 모음’의 [시작 주소] (test2의 주소는 [H])

혼돈되었던 것이 [배열 이름]이 [시작 주소]로 사용하고 있고, [시작 주소]를 또 우리는 [포인터]로 변경해서 사용하다보니까 [배열]과 [포인터]가 같은 거 아닐까 란 생각을 했던 것이다.

 

포인터는 “Hello World”에서 “dfsdfdsf” 막 추가되더라도 8바이트(환경에 따라 다름)고정 크기임. 바구니 자체 크기는 그대로고, 데이터 자체가 늘어나는것이다.

그 데이터는 아마 .rdata에 있다.

 

void Test(char a[45])        // 파라미터에 커서를 갖다대면 *로 바뀌어져있음

  • 배열은 함수 인자로 넘기면, 컴파일러가 알아서 치환한다. (char[] -> char*)
  • 즉 배열의 내용 전체를 넘긴게 아니라, 시작 주소(포인터)만 넘긴 것
  • 그래서 값 복사가 일어나지 않고, 주소를 넘겨주니 주소를 통해 참조해서 값 변경이 가능했던 것이다.

 

결론

💡 배열과 포인터는 엄연히 다른 개념이다. 비록 배열의 이름 자체가 포인터로 쉽게 변환이 되고, 시작 주소를 의미한다고 하되, 실질적으로 메모리상에서 포인터는 그 자체로 하나의 별도의 바구니가 생성이 되는데, 그 바구니의 주소에 다른 영역을 가리키고 있는 상태로 만들어진 것이다.
💡 배열은 별도의 바구니가 생성이 되는 것이 아니고, 이름 자체가 주소의 이름을 지녔을 뿐, 실질적으로 본체 자체는 “Hello World” 같이 배열 그 자체 즉 데이터가 만들어진걸로 봐야된다.
  • 공통점 : 둘 다 첫번째 주소를 이용해 데이터를 다룰 수 있다.
  • 차이점 : 포인터는 고정용량, 배열은 가변용량

배열을 매개변수로 선언할 경우, 인자로 넘길 때 포인터로 변하게 된다.

void Set(int number[]) -> Set(int* number) 포인터라는 말.

> 문자열은 [char 타입의 배열]이라 특수한 케이스

 

다중 포인터

void Set(char *a)
{
    a = “bye” // 밖에 매개변수로 준 변수는 안변해있다.
}

포인터라함은 그냥 주소값을 들고있는 바구니인것이지. *주소를 갖고 원본 데이터를 수정하기위해서는 해당 주소로 (데이터 접근)를 써서 수정을 해야만 된다. 주소를 담는 바구니에 있는 주소값을 멋대로 수정한 셈이다. 결국 포인터 주소값도 결국 값은 값이다.

댓글