Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
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
Tags
more
Archives
Today
Total
관리 메뉴

나의 IT일지

배열과 포인터 본문

프로그래밍 언어/C언어

배열과 포인터

세레프 2023. 2. 21. 04:43

 포인터 변수의 주소를 저장하는 공간 변수로, 변수를 사용할 때 변수의 주소로 접근하기 위해서 사용한다. 즉 , 포인터는 변수이기에, 연산이 가능하며 연산의 공식은 "저장중인 주소값+증감*저장한 변수의 자료형 크기"이다. 이는 배열의 요소의주소를 찾을 때 유용하다. 

#include<stdio.h>

void main() {

	int arr[3] = { 1,2,3 };
	printf("배열주소:%p\n", &arr);
	printf("배열명:%p\n", arr);
	printf("첫번째 주소:%p\n", &arr[0]);
	printf("두번째 주소:%p\n", & arr[1]);
	printf("세번째 주소:%p\n", & arr[2]);

}

 위의 코드를 보면, 배열주소와 배열명과 첫번째 요소의 주소가 같은 것을 확인 할 수 있다. 즉, 배열명은 포인터와 유사하게 배열주소를 보유하고 있다. 게다가 요소마다 주소가 연속적으로 부여되어 있는 것을 확인할 수 있다. 이는 배열도 포인터를 사용할 수 있다는 뜻이다. 그렇다면 배열은 포인터를 어떻게 활용할까?

 

배열과 포인터의 관계

 

포인터 연산

포인터란 변수의 주소를 저장하는 공간이다. 즉, 포인터는 변수의 주소를 저장하는 것 뿐이지, 저장하는 값이 변할 수 있는 변수라는 것이다. 그래서 포인터도 연산이 가능하다. 포인터 연산 주

my-it-diary.tistory.com

 포인터의 연산은 변수의 연산과 다르게 포인터에 저장한 주소값에 변수의 자료형의 크기만큼 증감한다. 이는 배열에서 유용하게 사용할 수 있는데, 요소마다 주소가 부여되어 있어서 포인터 연산을 사용하면, 요소들의 주소를 통해 요소의 값을 구할 수 있게 된다.

#include<stdio.h>

void main() {
	int a[5] = { 1,2,3,4,5 };

	int* ptr;
	ptr = a; // ptr = &a[0]
	printf("*ptr:%d, a[0]:%d\n", *ptr, a[0]);
	
	ptr++;
	printf("*ptr:%d, a[1]:%d\n", *ptr, a[1]);

}

 위의 코드를 보면, 배열주소를 포인터에 저장을 하고 연산하는 것을 확인할 수 있다. 정수형 배열의 주소를 가지고 있는 포인터"ptr"에 증가연산자를 통해 연산하는 경우, "ptr"의 값에 +1이 아닌 정수형의 크기인 +4가 되며, 이러한 규칙을 통해 요소의 주소를 구하는 것이다.

 

#include<stdio.h>

int main() {
	int num[3];

	printf("&num[0]: %d , num=%d\n", &num[0], num);
	printf("&num[1] : %d, num+1:%d\n",&num[1], num + 1);
	printf("&num[2] : %d, num+2:%d\n", &num[2], num + 2);

}

 배열명을 출력하면 주소값이기에, 포인터를 연산하여 간접참조연산자를 통해 변수의 값을 구하듯이, 배열명의 연산을 통해 요소의 주소를 구하고 간접참조 연산자를 사용하여 요소의 값을 구하는 것이 가능하다.

(배열명 + 증가량), (배열명 - 감소량)

 위의 구조는 배열명의 연산구조로, 배열명에 값을 증감하여 요소의 주소를 구하는 구조이다. 이때, 배열명의 증감은 포인터와 똑같이 저장한 주소값에 요소의 자료형의 크기만큼 증감하게 된다. 

 

#include<stdio.h>

void main() {
	int a[5] = { 1,2,3,4,5 };

	printf("a[0]:%d\n", a[0]);
	printf("a:%d\n", *a);
	printf("a[1]:%d\n", a[1]);
	printf("*(a+1):%d\n", *(a+1));
	printf("a[2]:%d\n", a[2]);
	printf("*(a+1):%d\n", *(a + 2));
}

 위의 소스코드와 결과를 보면, "a[1] == *(a+1)", "a[2]==*(a+2)"인 것을 알 수 있다. 즉, 배열명의 연산은 요소의 주소를 구하는 방법이며, "배열명[요소번호] = *(배열명 + 요소번호)"인 것을 알 수 있다.

 이는 포인터를 통해 값을 부를때도 똑같이 "포인터명[증감량] = *(포인터 + 증감량)"로 적용이 된다. 예를 들면 "*ptr"은 "*(ptr+0)"으로 바꿀수 있으며, "ptr[0]"으로 바꿀 수 있다.

 

 배열명 연산을 사용할 때 주의 사항이 존재한다. 포인터의 연산 덧셈, 뺄셈, 증감연산자으로 연산이 가능하지만, 배열명의 연산 덧셈과 뺄셈만 가능하고, 증감연산자는 사용이 불가능하다. 배열명은 변수가 아닌 상수이기에, 값을 새롭게 저장하는 대입연산을 내포하는 증감연산자를 사용할 수 없는 것이다. 

 

 


번외 ) 포인터 간의 연산

 포인터는 정수 뿐만 아니라 포인터간의 연산도 가능하며, 이를 통해 두 변수사이의 간격을 구할 수 있고, 두 변수의 위치비교를 할 수 있다. 

#include<stdio.h>

void main() {
	int a[] = { 1,2,3,4,5 };

	int* p1 = &a[0];
	int* p2 = &a[3];

	printf("p1:%d,p2:%d\n", p1, p2);
	if (p1 > p2) {
		printf("p1-p2=%d\n", p1 - p2);
		printf("p2는 p1보다 앞에 있다");
	}
	else
	{
		printf("p2-p1=%d\n", p2 - p1);
		printf("p1은 p2보다 앞에 있다.");
	}
}

 위의 코드를 보면 두 포인터의 뺄셈과 비교를 통해 두 요소의 간격과 위치비교를 하는 것을 알 수 있다. 특히 뺄셈의 결과가 신기한데, 값이 12가 아닌 3인것을 확인 할 수 있다. 이는 두 주소 사이에 정수형 요소 3개가 있다는 것을 알 수 있다. 즉, 뺄셈의 값은 "값의 차/ 요소의 자료형의 크기"라는 것을 알 수 있다.

'프로그래밍 언어 > C언어' 카테고리의 다른 글

이중 포인터  (0) 2023.02.23
함수와 포인터  (0) 2023.02.22
포인터 연산  (0) 2023.02.19
포인터의 기본  (0) 2023.02.18
다차원 배열  (0) 2023.02.17
Comments