포인터란?
C언어에서의 포인터는 메모리의 주소값을 저장하는 변수이며, 포인터 변수라고 부르기도 합니다.
변수가 데이터 값을 저장하는 것처럼 포인터 변수는 주소값을 저장합니다.
주소값
데이터의 주소값이란, 해당 데이터가 저장된 메모리의 시작 주소를 의미합니다. C언어에서는 이러한 주소값을 1바이트 크기의 메모리 공간으로 나누어 표현합니다. 예를 들어 int형 데이터는 4바이트의 크기를 갖지만, int형 데이터의 주소값은 시작 주소 1바이트만을 가리킵니다.
포인터 연산자
- 주소 연산자 & : 주소 연산자는 변수의 이름 앞에 사용하며, 해당 변수의 주소값을 반환합니다. '&' 기호는 앰퍼샌드(ampersand)라고 읽으며, 번지 연산자라고도 불립니다.
- 참조 연산자 * : 참조 연산자는 포인터의 이름이나 주소 앞에 사용하며, 포인터에 가리키는 주소에 저장된 값을 반환합니다. C언어에서 '*'기호는 사용하는 위치에 따라 다양한 용도로 사용됩니다.
이항 연산자로 사용하면 곱셈 연산으로 사용되며, 포인터의 선언이나 메모리에 접근할 때도 사용됩니다.
포인터 선언
다음은 포인터를 선언하는 문법입니다.
//타입* 포인터이름;
int* int_ptr;
char* ch_ptr;
타입으로 포인터가 가리키고자 하는 변수의 타입을 명시합니다.
포인터 이름은 포인터가 선언된 후에 포인터에 접근하기 위해 사용합니다.
포인터를 선언한 후 참조 연산자(*)를 사용하기 전에 포인터는 반드시 먼저 초기화되어야 합니다.
그렇지 않으면 의도하지 않은 메모리의 값을 변경할 수 있기 때문입니다.
따라서 C 컴파일러는 초기화하지 않은 포인터에 참조 연산자를 사용하면 오류를 발생시킵니다.
다음과 같이 포인터의 선언과 동시에 초기화를 하는 것이 좋은 방법입니다.
//타입* 포인터이름 = &변수이름;
//또는
//타입* 포인터이름 = 주소값;
int num = 10;
int* ptr = #
포인터의 참조
선언된 포인터는 참조 연산자를 사용해 참조할 수 있습니다.
int x = 10; // 변수의 선언
int* ptr = &x; // 포인터의 선언
int* pptr = &ptr; // 포인터의 참조
위 그림으로 볼 수 있듯이 변수 x에 10을 저장하면 메모리에 저장됩니다. 이 변수 x의 주소를 포인터 ptr 변수에 저장하고, 포인터 pptr 변수는 ptr 변수의 주소값을 저장하고 있습니다.
포인터 연산
포인터는 값을 증가시키거나 감소시키는 연산을 할 수 있습니다.
다음은 증감 연산자를 이용해 포인터 변수의 값을 증가시키는 예제입니다.
char* ptr_c = 0;
int* ptr_i = NULL;
double* ptr_d = 0x00;
printf("ptr_c의 주소값: %#x\n", ptr_c); // 0
printf("ptr_i의 주소값: %#x\n", ptr_i); // 0
printf("ptr_d의 주소값: %#x\n", ptr_d); // 0
printf("1 증가 후 ptr_c의 주소값: %#x\n", ++ptr_c); // 0x1
printf("1 증가 후 ptr_i의 주소값: %#x\n", ++ptr_i); // 0x4
printf("1 증가 후 ptr_d의 주소값: %#x\n", ++ptr_d); // 0x8
위의 예제에서 모든 포인터에 0을 저장하고 출력하면 모두 초기 주소값인 0을 출력합니다.
이 후 1을 증가시키는 연산을 진행한 후의 주소를 출력한 결과값을 보시면,
char형은 1만큼, int형은 4만큼, double형은 8만큼 주소가 증가한 것을 보실 수 있습니다.
이 주소의 증가폭은 변수의 타입의 크기와 같습니다.
char형은 1바이트, int형은 4바이트, double형은 8바이트의 크기를 갖기 때문에 해당 자료형의 크기만큼 주소값이 증가한 것입니다. 이 규칙은 뺄셈 연산에서도 똑같이 적용됩니다.
또한 포인터 변수끼리 대입 연산(=)과 비교 연산(==)도 가능합니다. 이 경우는 주소에 대한 대입과 비교가 이루어지겠죠.
인수 전달 방법
함수를 호출할 때에 함수에 필요한 데이터를 인수로 전달해 줄 수 있습니다.
인수를 전달하는 방법에는 다음과 같은 두 가지 방법이 있습니다.
- 값에 의한 전달 (call by value)
- 참조에 의한 전달 (call by reference)
값에 의한 전달(call by value)
값에 의한 전달은 인수로 전달되는 변수가 갖고 있는 값을 함수 내의 매개변수에 복사하는 방법입니다.
복사된 값으로 초기화된 매개변수는 인수로 전달한 변수와는 별개의 변수가 됩니다.
따라서 함수 내에서의 매개변수 조작은 인수로 전달되는 변수에 영향을 미치지 않습니다.
#include <stdio.h>
void add(int x)
{
x += 10;
}
int main(void)
{
int num = 10;
printf("변수의 초기값: %d\n", num); // 10
add(num);
printf("add() 호출 후 변수 num의 값은 %d입니다.\n", num); // 10
return 0;
}
add 함수에 num 변수를 인수로 전달했지만 num 변수의 값을 복사했기 때문에 add()에서 매개변수 x의 값을 증가시켜도 num 변수에는 아무런 영향을 주지 못 합니다.
참조에 의한 전달(call by reference)
참조에 의한 전달은 인수로 변수의 값을 전달하는 것이 아니라 해당 변수의 주소값을 전달합니다.
즉, 매개변수에 인수로 전달된 변수의 주소값을 저장하는 겁니다.
이 방법을 사용하면 인수로 전달된 변수의 값을 함수 내에서 변경할 수 있게 됩니다.
#include <stdio.h>
void add(int* x){
*x += 10;
}
int main(void)
{
int num = 10;
printf("변수의 초기값: %d\n", num); // 10
add(&num);
printf("add() 호출 후 변수 num의 값: %d\n", num); // 20
return 0;
}
이번에는 add 함수에 num의 주소값을 전달했고, add()에서는 매개변수를 포인터 변수로 설정해 값을 10만큼 더해주었습니다. 참조에 의한 전달은 주소를 직접 전달하기 때문에 매개변수 x의 값을 변경하면 원래 인수로 전달했던 num의 값이 변경됩니다.
출처
코딩교육 티씨피스쿨
4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등
tcpschool.com
'컴퓨터시스템' 카테고리의 다른 글
웹서버와 CGI와 WAS (+ MIME Type) (2) | 2024.02.22 |
---|---|
파일 디스크립터란? (File Descriptor) (0) | 2024.02.22 |
메모리 단편화와 메모리 할당 정책 (0) | 2024.02.07 |
GCC(GNU Compiler Collection)란? (0) | 2024.02.01 |
컴퓨터시스템 1주차 (0) | 2024.01.14 |