포인터
포인터란?
- 포인터 : 주소를 가지고 있는 변수
포인터는 메모리의 주소를 가진 변수. 포인터를 이용하여 메모리의 내용에 직접 접근가능
메모리의 구조
변수는 메모리에 저장된다. 메모리는 바이트 단위로 액세스 된다.
변수와 메모리
변수의 크기에 따라서 차지하는 메모리 공간이 달라진다.
변수의 주소
변수의 주소를 계산하는 연산자: % 변수 i의 주소: &i
변수의 시작 주소를 가져온다. 왜 이렇게 가져오는지는 몰라 메모리의 상태에 따라, os에 따라 다름.
포인터의 선언
- 포인터 : 변수의 주소를 가지고 있는 변수
int i = 10; // 정수형 변수 i 선언 int *p = &i;//변수 i의 주소가 포인터 p로 대입
p는 int 타입의 포인터. p에다가 메모리의 저장할 수 있는 공간을 확보를 함.
포인터 크기 : 옛날 컴픁 4바이트, 지금은 8바이트?(메모리만을 저장하기 위해서) 포인터 변수를 선언했을 땐, 공간만 할당. 값은 i의 변수의 시작 주소를 (메모리 주소)를 저장.
간접 참조 연산자 *
: 포인터가 가리키는 값을 가져오는 연산자.
*p가 할당 되어있는 메모리의 주소가 가리키고 있는 값을 가져온다.
간접 참조 연산자의 해석
포인터 예제1,2,3
(*pc)++; 가 맞다. *pc++라고 하면 안된다. 전자는 저장된 값에다가 ++연산이 들어가고, 후자는 주소 값이 바뀐다.
포인터 사용시 주의점 #1
포인터의 타입과 변수의 탕비은 일치하여야 한다.
포인터 사용시 주의점 #2
초기화가 안된 포인터를 사용하면 안 된다. 뭔지 모르는 값이 들어있는 포인터를 메모리 주소로 사용하게 되면, 권한이 없는데로 가서 접근하게 된다.
포인터 사용시 주의점 #3
포인터가 아무것도 가리키고 있지 않는 경우에는 NULL로 초기화하자.
포인터 연산
증가 감소 덧셈 뺄셈 포인터 타입 : char < short < int < float < double ++ 연산후 증가되는 값 : 1<2<4<4<8
포인터의 data type이 기준이다.
증가 연산 예제
포인터의 증감 연산
포인터 간의 비교
주소 가지고도 컨트롤 가능. 조심해야 할 건, p1,p2가 뭘 받을지 모르니까. p1,p2위치가 바뀐다면 위험하다.
간접 참조 연산자와 증감 연산자
v = a++ => a를 가져다가 v에 대입한 뒤, a의 값을 증가시켜라.
v = ++a => a를 증가시킨뒤 v에 대입.
이런거 많이 쓰지마 가독성이 떨어져.
포인터와 배열
&a[0] = a
포인터를 배열처럼 사용
포인터 변수 p에 배열 a의 시작주소 a를 넣어주면 똑같이 사용 가능.
포인터를 사용한 방법의 장점
- 인덱스 표기법 보다 빠르다. (원소의 주소를 계산할 필요가 없다.)
포인터와 함수
가장 큰 장점 -> 메모리 컨트롤을 손수 할 수 있다.
call by value -> 값에 의한 호출. 카피를 해주는 것
call by reference-> 카피는 카피인데 메모리 주소값만 카피를 해주는 것.
swap()함수 #1
- -> 변수 2개의 값을 바꾸는 작업을 함수로 작성.(카피해서 썼기에, 바뀌는 건 없음 다른 공간에서 a,b는 원형이 보존되고 있는 상태이다.)
- 포인터를 이용도 가능(a랑 b에 설정되어 있는 값은 똑같다. 주소가 넘어가기 때문에 원형이 바뀐다.)
배열이 함수 인수인 경우
배열의 경우, 크기가 큰 경우에 복사하려면 많은 시간 소모 배열의 경우, 배열의 주소를 전달
배열이 함수의 인수인 경우
주의
- 함수가 종료되더라도 남아 있는 변수의 주소를 반환하여야 한다.
- 지역 변수의 주소를 반환하면 함수가 종료되면 사라지기 때문에 오류
포인터 사용의 장점
- 연결 리스트나 이진 트리 등의 향상된 자료 구조를 만들 수 있다.
- 참조에 의한 호출 - 포인터를 매개 변수로 이용하여 함수 외부의 변수의 값을 변경할 수 있다.
- 동적 메모리 할당 - 17장에서 다룬다.
응용 예제1
-> 포인터를 이용하면 작업을 독립되게 만들 수 있다.
버블 정렬
배열의 최솟값 최댓값 읽어보기
참고자료