컴퓨터/C
본문을 읽기 전 보고 오는 것은 권장합니다.
C 언어에서는 메모리주소로 접근하여 그 메모리 공간의 데이터를 이용할 수 있는 방법을 제공해 줍니다.
이것이 바로 C언어의 꽃이라고 하는 포인터라는 개념입니다. 사실 사용되고 있는 프로그래밍 언어에 포인터의 개념은 다 들어있습니다. 다만, 우리가 직접 사용을 하느냐 또는 언어에서 제공을 하느냐의 차이일 뿐입니다.
그러면 C언어에서 이 메모리 주소에 접근하는 포인터에 대하여 알아보도록 하겠습니다.
메모리의 주소를 저장하는 변수를 포인터 변수라고 합니다. 조금 생소한 개념일 수 있지만 정리하자면 아래와 같습니다.
변수와 메모리 주소 그리고 포인터 변수에 대하여 이해를 했다면 이제 왜 포인터 변수를 사용하는지 알아봐야 됩니다.
가장 대표적인 장점은 바로 지역변수와 함수의 한계를 극복할 수 있습니다.
지역변수는 중괄호 { } 안에서만 사용할 수 있고 함수의 매개변수로 넘어가게 되면 값이 복사된 형태로 함수안에서 새로운 지역변수가 생기는 형태가 됩니다. 그리고 함수는 하나의 반환만을 할수 있습니다.
#include <stdio.h>
void func(int a, int b)
{
a += 10;
b += 10;
}
int main()
{
int a = 1;
int b = 2;
printf("함수를 실행 하기 전 변수 a 의 값 : %d\n", a);
printf("함수를 실행 하기 전 변수 b 의 값 : %d\n", b);
func(a, b);
printf("함수를 실행 후 변수 a 의 값 : %d\n", a);
printf("함수를 실행 후 변수 b 의 값 : %d\n", b);
return 0;
}
main문의 지역변수 a, b의 값을 함수 func의 매개변수 a, b로 넣어주어 함수 안에서 변경해도 함수 안의 지역변수(매개변수) a, b의 값이 변경되는 것이기 때문에 main함수의 지역변수 a, b는 값의 변화가 없습니다.
하지만 포인터 변수를 사용하면 이런 한계점을 극복이 가능해집니다.
포인터 변수는 메모리의 주소를 저장하고 있고 그 메모리 주소로 접근하여 그 메모리 안의 데이터를 변경할 수 있습니다.
따라서 다른 함수 안의 매개변수로 메모리의 주소 값을 복사하여 가지고 가서 그 메모리 주소 안의 데이터를 변경한다면 다른 지역에 있는 지역변수의 값도 제어가 가능하게 됩니다.
선언 과 초기화 자료형* 변수명 (=&변수명); 초기화와 사용 변수명 = &변수명; *변수명 = 메모리 주소에 넣을 데이터 |
포인터 변수는 2가지 일을 할 수 있습니다.
사용방법에 대하여 자세히 정리하자면 다음과 같습니다.
#include<stdio.h>
int main()
{
int a = 1; // 변수 a 선언
int* p =&a; // 포인터 변수 p 선언 및 변수 a의 주소 저장
p = &a; // 포인터 변수 p에 변수 a의 주소 저장 (윗줄과 동일)
printf("변수 a의 값 : %d\n", a);
printf("포인터 p에 저장된 메모리주소안의 값 : %d\n", *p);
*p = 10; // 포인터 변수 p에 저장된 메모리주소 안의 값을 10으로 변경
printf("포인터 변수로 제어 후 변수 a의 값 : %d\n", a);
printf("포인터 변수로 제어 후 포인터 p에 저장된 메모리주소안의 값 : %d\n", *p);
a = 100;
printf("변수 a를 변경 후 변수 a의 값 : %d\n", a);
printf("변수 a를 변경 후 포인터 p에 저장된 메모리주소안의 값 : %d\n", *p);
return 0;
}
#include<stdio.h>
int main()
{
int a = 1; // 변수 a 선언
int* p =&a; // 포인터 변수 p 선언 및 변수 a의 주소 저장
p = &a; // 포인터 변수 p에 변수 a의 주소 저장 (윗줄과 동일)
printf("변수 a의 메모리 주소 : %p\n", &a);
printf("포인터 변수에 저장된 메모리 주소 : %p\n", p);
printf("포인터 변수의 메모리 주소 : %p\n", &p);
}
#include <stdio.h>
#include <stdio.h>
void func(int a, int b)
{
printf("func 함수 지역변수 a의 메모리 주소 : %p\n", &a);
printf("func 함수 지역변수 b의 메모리 주소 : %p\n", &b);
a += 10;
b += 10;
}
int main()
{
int a = 1;
int b = 2;
printf("main 함수 지역변수 a의 메모리 주소 : %p\n", &a);
printf("main 함수 지역변수 b의 메모리 주소 : %p\n", &b);
func(a, b);
return 0;
}
#include <stdio.h>
void func(int *a, int *b)
{
printf("func 함수 포인터a에 저장된 메모리 주소 : %p\n", a); // int* a = &a가 매개변수에서 된 상태
printf("func 함수 포인터b에 저장된 메모리 주소 : %p\n", b); // int* b = &b가 매개변수에서 된 상태
}
int main()
{
int a = 1;
int b = 2;
printf("main 함수 지역변수 a의 메모리 주소 : %p\n", &a);
printf("main 함수 지역변수 b의 메모리 주소 : %p\n", &b);
func(&a, &b);
return 0;
}
그리고 위에서 포인터 변수는 어떤 변수의 메모리 주소를 저장하고, 저장된 메모리 주소 안의 데이터를 접근하여 사용 변경할 수 있습니다. 그럼 최종 예제로 지역변수의 한계를 극복해보도록 하겠습니다.
#include <stdio.h>
void func(int *a, int *b)
{
*a = 100;
*b = 200;
}
int main()
{
int a = 1;
int b = 2;
printf("함수 실행 전 a의 값 : %d\n", a);
printf("함수 실행 전 b의 값 : %d\n", b);
func(&a, &b);
printf("함수 실행 후(포인터 매개변수 이용) a의 값 : %d\n", a);
printf("함수 실행 후(포인터 매개변수 이용) b의 값 : %d\n", b);
return 0;
}
C 언어 - 오버플로우와 언더플로우 (0) | 2021.06.16 |
---|---|
C 언어 - 다차원 배열 (0) | 2021.06.14 |
C 언어 - 메모리주소 (0) | 2021.06.12 |
C 언어 - 배열과 문자열 (0) | 2021.06.09 |
C 언어 - 지역변수와 전역변수 (0) | 2021.06.08 |
91년생 공학엔지니어의 개발일지
TODAY :
YESTER DAY :
TOTAL :
Commnet