[C언어 개념] 포인터 1
- 포인터는 파생자료형이다
: 파생이란 기본 자료형이 존재하고, 이에 관련되어 정의되는 것을 의미한다.
-컴퓨터의 메모리는 메모리 셀의 모임 (1차원 구성)
: 각 셀은 바이트라고 불리며, 정수로 표시되는 주소를 할당받는다
: 통상 0으로 시작해서 연속적으로 증가하는 수
: 메모리 주소는 사실상 정수값이기 때문에, 이 정수를 표현할 수 있는 변수로 표현이 가능하다
: 주소값을 저장하는 변수를 포인터 변수라고도 한다.
-포인터의 개념 (3가지 개념 기반)
: 포인터 상수, 포인터 값, 포인터 변수
: 포인터 상수) 포인터의 메모리 주소, 상수의 값 변경이 불가능하고, 데이터 값을 저장하기 위해 사용하는 것만이 가능하다
: 포인터 값) C언어에서는 메모리 주소를 직접적으로 저장하는 것이 불가능한데, 주소연산자 &을 통해 얻은 해당 변수의 주소값, 이 값은 프로그램 실행시마다 변경될 수도 있다.
: 포인터 변수) 포인터 값이 있으면 이 값은 다른 변수에 저장된다.
ex) quantity=178, 주소 5000에 저장
p=5000, 주소 5048에 저장
p는 포인터 변수, 5000은 포인터 값, 5048은 포인터 상수
-변수의 주소 접근하기
: 변수의 메모리 상의 위치는 동일한 소스코드일지라도 시스템에 따라 달라지므로 변수의 주소값은 프로그램 작성시에는 알 수 없다
: C언어에서는 변수 주소 파악을 위해 주소 연산자 &을 제공한다.
ex) p=&quantity 의 식은 p=5000 과 동일한 효과를 가진다
:주소 연산자는 단순 자료형이나 배열의 원소에만 사용할 수 있다. 상수의 포인팅, 배열명의 포인팅, 수식 포인팅은 문법오류이다.
:주소를 출력할 땐 %u를 사용한다. 하지만 printf에서 변수의 주소값을 인쇄하는 가장 바람직한 방법은 %p를 이용하는 것
:%u 를 사용하는 이유는 메모리 주소가 unsigned integer 이기 때문이다.
<예제>
변수의 값과 주소를 함께 출력하는 프로그램을 작성하라
-
-
-포인터 변수의 선언
: C언어에서 포인터 변수 또한 다른 변수들과 마찬가지로 포인터 변수로 선언이 되어야 한다.
: data_type *pt_name;
: 별표(*)는 변수 pt_name이 포인터 변수라는 것을 알려준다.
: pt_name은 메모리 공간을 확보해야한다
: pt_name은 data_type의 형태의 데이터를 가진다.
ex) int *p
위와 같은 선언은 변수 p를 정수를 가리키는 포인터 변수로 선언한다.
즉, 변수 p 자체가 int의 자료형이 아니라, p가 가리키는 대상이 int임을 명심해야한다.
: 이러한 선언들도 컴파일러가 메모리를 할당하는 것에 사용된다.
: 위의 예시의 경우 포인터 변수의 초기화가 이루어지지 않았기 때문에 임의의 위치를 가리키게 된다.
-포인터 변수의 초기화
: 포인터 변수에 일반 변수의 주소값을 할당하는 과정을 포인터의 초기화라고 한다.
: 포인터 변수가 선언이 되면 이 변수의 초기화는 언제든 가능하다.
ex) int quantity;
int *p;
p= &quantity;
: 여기서 주의할 점은 초기화는 포인터 변수 p를 초기화하는 것이고, *p, 즉 포인터 변수가 가리키는 메모리 공간 속의 담긴 정보를 초기화하는 것이 아니라는 것이다. quantity는 포인터 변수의 초기화에 아무런 영향을 받지 않는다.
: 선언에 있어서 유일한 제약 사항은 quantity 변수가 포인터 변수 이전에 선언되어야 한다는 점과, 초기화하는 변수가 동일한 자료형을 가지고 있어야 한다는 점이다.
-포인터를 사용하여 변수 접근하기
: 연산자 *는 포인터 연산자, 역참조 연산자, 간접연산자라고 불린다.
: 포인터 변수에 포인터 연산자 *가 사용되면, 그 결과는 해당 포인터가 가리키는 주소에 해당하는 변수가 얻어진다.
: 포인터 변수 *의 의미로 "주소의 값 (the value at address)"로 기억하면 유용하다.
ex) int quantity, *p, n;
quantity=179;
p=&quantity;
n=*&quantity;
n=*p;
n=quantity;
-포인터의 연쇄
: C언어에서는 초인터가 또 다른 포인터를 가리키는 것, 즉 다중 간접지정이 가능하다.
: int **p 와 같은 형태로 가능하다
-포인터 표현식
: 전제조건) p1과 p2가 적절히 선언이 되고 초기화가 된 상태라면 밑과 같은 표현식이 가능하다
: y = *p1 + *p2
sum = sum +*p1
z= 5 * -*p2/ *p1 same as (5* (-(*p2)))/(*p1)
*p2 = *p2 + 10
: C언어는 포인터 변수에 정수를 더하거나 빼는 기능을 제공한다.
: 포인터들 간에 뺼샘을 제공하고, 이에 대한 결과값은 두 포인터 간의 존재하는 원소의 수를 의미한다.
: 두 포인터간의 덧셈은 허용되지 않는다.
: 비교 연산이 지원된다. 곱셈이나 나눗셈은 사용이 불가능하다.
-포인터 증가연산과 스케일 펙터
: 포인터에 정수를 더하거나 뺄 수 있음을 설명하였다 ex) p1 = p2 + 2;
: p1++ 와 같은 표현은 해당 자료형의 다음 값의 위치를 가리키게 된다.
ex) 초기값 2800을 가진 p1에 대해 p1++의 값은 2801이 아니라 2804가 된다.
: 즉, 포인터 변수의 증분은 그 포인터 변수의 값을 그 포인터 변수의 자료형만큼 증가시키고, 이 크기를 스케일 펙터라고 한다.
<<PC에서 각 자료형의 크기>>
character 1byte
integer 4bytes
floats 4bytes
long integers 4bytes
doubles 8bytes
: 자료형의 크기는 시스템마다 다르기 때문에 확인을 위해서는 컴파일러 매뉴얼을 확인하거나, 실행시간에 sizeof 연산자를 사용하는 것이 좋다.
: sizeof 연산자는 크기를 확인하고자 하는 변수 x에 대해 sizeof(x)와 같이 작성하며, 이는 변수 x를 저장하는데 필요한 바이트 수를 반환한다.