Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

자라나라

[C언어]포인터와 배열의 크기 본문

C언어

[C언어]포인터와 배열의 크기

자랄수있다 2022. 4. 25. 09:40

포인터란?

메모리의 주소값을 저장하는 변수이다. 포인터 변수라고도 부른다. 

char형 변수에 문자를, int형에 정수를 저장하는 것처럼 포인터는 주소값을 저장한다.

ex) int a = 20; // 변수 선언

int *ptr = &n; // 포인터 선언

여기서 &는 주소연산자, *는 참조 연산자가 되는 것이다. 

*붙은 녀석이 주소를 저장한다 생각하면 되겠다.

길을 찾아가주는 반딧불이라고 생각하자. 왠지 그렇게 생겼다

 

포인터의 선언

타입* 포인터이름;

ex) int* ptr;

 

포인터의 선언과 동시에 초기화를 하는 것이 좋다 !

타입* 포인터이름 = &변수이름;  또는,

타입* 포인터이름 = 주소값; 

(*의 위치는 타입에 붙어있어도 되고 포인터 앞에 붙어있어도 되고 그 사이에 있어도 되고 상관없다)

여기서 주소값은 어떻게 알 수 있을까?

포인트 변수의 주소를 16진수로 출력해주는 %p가 있다. 값은 00000000 ~ FFFFFFFF 로 출력된다.

 

이전에 scanf를 배웠을 당시, &를 쓴 적이 있다.

그때는 백프로 이해하지 못하고 그저 '입력값을 임시로 기억해주는 메모리장치' 정도로 생각하고 넘어갔다. 무책임하게 넘긴 것은 아니다. 그 당시엔 이게 요점이 아니었기 때문ㅎㅎ..

이젠 이해했으니 한번 그 주소값을 출력해보자!

변수 A의 메모리 주소가 16진수로 출력이 되었다. 이는 디버깅할 때마다 값이 다르다 (RAM이 휘발성이기때문)

이번엔 배운내용을 바탕으로 변수와 포인터를 선언해서 그 주소값을 출력해보자

 

막 쳤는데 18이 입력됐다. 욕하고싶은 거 아님

잘 출력됐다.

numptr을 %d로도 출력해도 특정값이 나오는데, 이는 10진수로 출력된 것이고

%p와 동시에 출력했을 때 두 값은 진법만 다른 같은 수이다.

우연의 일치일까 몇 번 돌려봤는데 아님

이건 중요하지 않고 !

 

정리하자면

*ptr이 결국 num을 가리키니까 출력값이 같다., num의 주소는 &num, 즉 ptr

또한

*ptr = a 인걸 이용해 a값을 바꿀 수도 있다.

이중 포인터

포인터를 가르키는 포인터이다. 

  • [초대장]안녕 ! 널 위한 선물을 준비했어 아래 주소로 꼭 와주라! ---이동---> 선물 뙇!!!(비행기티켓이면 좋겠다)
    초대장은 포인터고, 선물은 가르키는 값이 되겠다.
  • [쪽지]잘 잤어? 식탁 위를 확인해봐 --이동--> [초대장] --이동--> 선물
    여기서 쪽지가 바로 이중포인터가 되는 것이고 결국 가리키는 값은 똑같다

여기서 주의할 점은 *쪽지 = 테이블의 주소가 아니라 선물의 주소라는 것!

결국 다중포인터에서 그들이 가리키는 주소는 다 똑같다.

 

이중포인터를 쓰는 이유는 뭘까?

라는 질문은 사실, 굳이 왜 포인터를 쓸까?와 같다.

그렇다면 포인터를 쓰는 이유는?

C언어에서는 함수를 호출할 때 Pass-by-value(Call-by-value) 의 방식만 쓰는데 이는 복사된 데이터를 전달하여 구성함으로써, 값을 수정하여도 원본의 데이터에는 영향을 주지 않도록 하는 방식이다.

아래 예시를 보자.

angel 함수에 대입한 수에는 a 값이 1004로 바뀌었어야 하는데 그대로 10이 나왔다.

angel을 호출할 때 전달되는 인자 a는 그 변수 자체가 아니라 복사된 값을 전달하는 것이기 때문에

main함수와 angel 함수 속 변수 a는 서로 다른 메모리에 존재하는 별개의 변수로 존재하는 것이다. 

그렇게 angel 함수가 종료되면서 그 안에서의 변화는 사라지고,  main함수로 돌아왔을 때 a는 그대로 10이 되는 것이다.

 

그럼 여기서 포인터를 써보자.

성공적으로 1004가 출력되었다.

이번엔 a라는 변수를 복사한 게 아니라 그 주소값의 위치를 복사하여 그곳에 20을 저장했기 때문이다.

C언어에서는 제공하지 않지만 pass by reference의 동작 방식이 있는데, 이는 실제값이 아닌 실제값의 주소가 쌓이게 된다. (자세한 내용은 https://mangkyu.tistory.com/107 참고)

swap 함수

위에서 배운 내용으로 바탕으로 함수를 한 번 만들어 보자 

변수 a와 b를 넣으면 그 값이 바뀌어 나오는 swap 함수

 

temp는 임시로 x의 값을 저장해놓을 변수이다. 양 손에 음식이 든 접시가 있을 때, 접시를 바꾸려면 잠시 올려놓을 곳이 필요하다. temp가 테이블의 역할을 한다.

a와 b는 지역변수이기 때문에 main을 벗어나면 값이 소실된다. 그러므로 그 주소값을 swap에 넘겨줘야한다. swap(&a, &b)

주소값을 저장할 수 있는 변수는 포인트 변수이므로 파라미터에는 int *x, int *y가 들어가게 된다.

 

배열과 포인터

 

앞에서 printf를 배우며 잠시 다뤘던 문자열은, 배열과 연관이 깊었다. 아니, 문자열 자체가 문자의 배열이다.

C언어에서 문자열(string)은 메모리에 저장된 연속된 문자(char)의 집합이기 때문이다.

 

일단 함 보자.

아래는 문자열에서 첫번째와 두번째 주소 값을 출력하는 코드이다.

원하는 대로 출력이 됐다. 이번엔 다른 방법으로 출력해보자.

이전에 우린 sizeof로 각 자료형의 크기를 구한적이 있다

보시다시피, 문자는 1바이트이다. 문자열의 배열에서 한 글자당 1바이트를 차지하는 것이다.

위의 hello 예시에서 *ptr과 *ptr2는 메모리 주소이다. *ptr의 주소가 001 이라면 ptr2는 1바이트 다음인 002가 될 것이다. 그렇다면 *ptr2대신에 *ptr+1 을 대입해보면 어떨까?

이런 뜬금없이 i 가 나왔다. 혹시 알파벳순일까 해서 -1을 넣었더니 g가 나왔다. 역시 알파벳순이 맞았다.

이유가 뭔가하고 찾아보니 연산자 우선순위의 문제였다.

위 자료를 보면 포인터는 2순위고 +-는 4순위이다. 즉 *ptr + 1은 *ptr= h에서 ascii 상의 다음 코드값인 i를 내놓은 것이다.

다시 제대로, 우선순위를 조정해서 출력해주면

원하는 값이 나왔다. 

 

 

이번엔 int형 배열의 주소를 확인해보자.

10진수가 더 보기 편하니까 %d로 출력ㅎㅏ겠슴다

역시 4바이트의 갭을 두고 붙어있다. 

그렇다면 변수 arr 자체의 주소는??

배열의 주소는 배열의 [0]의 주소값과 같은 것을 알 수 있다.

이번엔 arr + 1을 출력해보자

4바이트 차이가 난다 즉 arr + 1 은 arr[1]의 주소값과 같게 되는 것이다. 

정리하면,

arr = &arr[0]

arr + 1 = &arr[0] + 1 = &arr[1]

arr + 2 = &arr[2]

arr + i = &arr[i]

... 증명해보자

 

 

arr + i = &arr[i] 는 증명되었다. 

같은 원리로 

*(arr + i) = arr[i] 도 맞나 확인해보자.

 

arr + i = &arr[i]

*(arr + i) = arr[i]

 

마지막으로 아래의 예시도 살펴보자

int *ptr = arr

*(ptr + n) = arr + n = &arr[n]

ptr + 1 은 ptr에서 4바이트를 더하게 되는 것이다.

위의 세가지 증명을 정리하면

  • arr + i = ptr + i = &arr[i]
  • *(arr + i) = *(ptr + i) = arr[i]

추가적으로, 

a[b] = *(a + b)로 바꿔서 처리를 한다.

이를 응용해 덧셈의 교환법칙을 이용하면

ptr[i] = *(ptr + i) = *(i +ptr) = i[ptr] 이 되어

이렇게도 출력이 된다. (물론 실무에선 이렇게 쓰지 않는다)

a[b] = *(a + b)의 개념이 잘 이해는 안 되지만 일단 알아둬야겠다.

 

 

 

 

'C언어' 카테고리의 다른 글

[C언어]배열(array)[2]  (0) 2022.05.08
[C언어] 배열(array)[1] 선언, 초기화  (0) 2022.04.15
[C언어] 함수  (0) 2022.04.12
[C언어] if else , break/continue, random, switch  (0) 2022.04.01
[C언어] 반복문  (0) 2022.03.24