포인터
1. 운영체제와 프로그래밍
변수 ---> 메모리주소
- 기계어에서는 변수가 위치한 메모리 주소를 통해 변수 값을 읽거나 변경
- 컴퓨터 시스템의 메모리는 운영체제가 관리
- 운영체제가 메모리를 관리하는 방법에 따라 프로그래밍 방법도 달라진다.
2. 32비트 운영체제와 64비트 운영체제
- 운영체제에서 실행되는 프로그램을 32비트용(x86) 프로그램과 64비트용 프로그램(x64)으로 나누어 개발 가능
- 32비트용 프로그램은 32비트 운영체제와 64비트 운영체제에서 모두 동작
3. 64비트 운영체제의 장단점
[ 장점 ]
- 동시 처리 능력이 좋음
- RAM을 16EB(엑시바이트) 까지 사용 가능 (32bit ---> 4GB)
[ 단점 ]
- 기본적인 메모리 사용량이 많음
- 32비트 프로그램과 호환하기 위한 모듈까지 관리해야 하기 때문에 낮은 사양의 컴퓨터의 설치하면 손해
---> 메모리를 비효율적으로 사용할 가능성이 높아지고 호환성이 떨어져 아직까지 많은 개발자들이 32비트 방식으로 프로그램을 개발
- " 32비트 프로그래밍에서는 int형이 32비트(4바이트) "
- " 32비트 프로그래밍에서는 주소를 저장하거나 사용할 때 4바이트로 표현 "
4. 메모리 주소지정 방식
- 운영체제는 메모리 주소를 1바이트 단위로 관리
- 32비트 윈도우 운영체제는 0~4,294,967,295번까지의 주소 사용
- 메모리를 사용하려면 반드시 사용할 메모리 주소를 지정해야 함
- 메모를 사용할 때 한 번에 읽거나 저장할 크기를 명시해야 함
5. 직접 주소 지정 방식
- 메모리를 사용할 때 프로그래머가 사용할 메모리 주소를 직접 적는 방식
- " 102번지에 1042라는 값을 2바이트 크기로 저장하겠다 "
6. 1042가 왜 4와 18로 나누어질까요?
- 0000 0100 0001 0010
4 18
- 1042 값은 8비트에 저장할 수 없기 때문에 두 개의 8비트에 나누어 저장
- 102번지에 18, 103번지에 4가 저장
- 윈도 운영체제는 리틀 엔디언이라는 바이트 정렬을 사용
7. 16진법으로 메모리 형태 표시하기
- C언어에서는 2진수를 직접 사용하는 방법을 제공하지 않음
- 2진수에 가장 가까운 표현법인 16진수를 주로 사용
- 16진수 한 자릿수는 4비트로 표시 가능
- 16비트 두 자리는 1바이트를 의미
- 16진수로 표현된 숫자는 바이트 단위로 나누기가 편리함
8. 16 진접으로 메모리 형태 표시하기
9. 직접 주소 지정 방식은 C언어의 "변수" 문법과 같다.
- C언어는 "변수"라는 개념으로 직접 주소 지정 방식을 사용
- C언어에서 변수를 사용하면 변수에 값을 대입하는 소스 코드가 어셈블리 형태의 기계어로 번역 됨
- C언어가 주소를 사용하지 않고 변수라는 개념을 사용하는 이유?
( 메모리 주소 대신 변수 이름을 사용하면 코드를 더 쉽게 이해 가능 )
10. C언어에서 직접 주소 지정 방식의 한계
- C언어의 직접 주소 지정 방식은 변수 개념을 사용하기 때문에 문법 구조상 서로 다른 함수에 존재하는 변수 참조 불가능
- 함수의 매개변수와 반환값을 이용하여 서로 다른 함수에 존재하는 지역 변수들 간에 값을 전달 가능
11. 간접 주소 지정 방식
- 102번지에 4바이트 크기의 "주소"가 저장되어 있는데 이 주소에 가서 "값" 1042를 2바이트 크기로 대입하라
- 0x000000066번지에 4바이트 크기의 "주소"가 저장되어 있는데 이 주소에 가서 "값" 0x0412를 2바이트 크기로 대입하라
12. 포인터(Pointer)
- int add = 0x00000006 C;
- 일반 변수도 주소를 저장할 수 있으나, 저장된 주소의 메모리에 가서 값을 읽거나 저장할 수 있는 기능은 없다.
- C언어는 간접 주소 지정 방식으로 동작하는 포인터(Pointer) 문법에 제공
- 자신이 사용하고 싶은 메모리의 "주소"를 저장하고 있는 메모리가 포인터
- 포인터 변수는 자료형을 선언하지 않아도 무조건 크기가 4바이트
13. 변수가 저장된 메모리 공간의 주소 얻기
- 변수의 주소는 프로그램이 실행될 때마다 달라지기 때문에 포인터 변수에 주소를 직접 입력하는 것보다 프로그램 안에 선언한 다른 변수의 주소를 받아와 사용하는 것이 안전
14. 변수가 위치한 메모리 주소 출력하기
15. * 키워드의 또 다른 이름, 번지 지정 연산자
16. " Ptr = " 과 " *Ptr = " 의 차이점
- " Ptr = " : 포인터 변수의 값(가리키는 대상의 주소)이 변경
- " *Ptr = " : 포인터가 가리키는 대상의 값이 변경
17. " Ptr = " 형태는 포인터 변수에 주소를 지정한다.
- 포인터 변수에 저장된 주소는 "포인터가 가리키는 대상 메모리"의 시작 주소를 의미
18. " *Ptr = " 형태는 포인터가 가리키는 대상에 값을 저장한다.
- " 포인터가 가리키는 대상 "의 값을 변경할 때는 Ptr 변수 앞에 *(번지지정) 연산자를 추가하여 " Ptr = " 과 같이 사용
19. 다른 함수에 선언된 지역 변수 사용하기
- 포인터를 사용하여 간접 주소 방식으로 값을 대입하는 이유?
( 모든 변수가 같은 함수에 선언되는 것은 아니기 때문 )
- 일반 변수는 다른 함수에 있는 변수 사용 불가
- 포인터 변수는 다른 함수에 선언된 변수의 값을 읽거나 변경 가능
20. 직접 주소 지정 방식으로 다른 함수에 선언한 변수 사용하기
21. 간접 주소 지정 방식(포인터)으로 다른 함수에 선언한 변수 사용하기
22. 포인터를 사용할 때 자주 발생하는 실수들
- 포인터를 사용할 때 *연산자의 사용 여부에 따라 두 가지 표현 가능
- *(번지지정) 연산자를 사용해야 하는 곳에서 실수로 누락하면 문제 발생
23. const 키워드로 주소 변경 실수 막기
- const 키워드를 이용하여 피호출자에서 호출자로부터 전달받은 주소를 변경하는 실수를 방지
24. int * const p;
- p가 가지고 있는 주소를 변경하면 번역할 때 오류 발생
25. const int *p;
- *p를 사용하여 대상의 값을 변경하여 번역할 때 오류 발생
26. const int * const p;
- p가 가지고 있는 주소를 바꾸거나 * p를 사용하여 대상의 값을 바꾸면 번역할 때 오류 발생
27. 사용할 메모리의 범위를 기억하는 방법
(1) 시작 주소와 끝 주소를 기억하는 것
(2) 시작 주소와 사용할 크기를 기억하는 것
28. 시작 주소와 끝 주소로 메모리 범위 기억하기
- 시작 주소와 끝 주소로 메모리 범위를 기억하려면 총 8바이트 필요
29. 시작 주소와 사용할 크기로 메모리 범위 기억하기
- 시작 주소와 사용할 크기로 메모리 범위를 기억하려면 총 8바이트 필요
- 사용할 메모리 크기는 명령문에 포함되어 있기 때문에 자신이 사용할 메모리의 시작 주소만 기억하면 된다.
- 포인터도 자신이 가리킬 대상에 대해 사용할 범위는 저장하지 않고 사용할 메모리의 시작 주소만 기억하면 된다.
30. 포인터 변수의 주소 연산
- 포인터 변수에 저장된 주소도 일반 변수처럼 연산 가능
- 주소를 1만큼 증가시킨다는 의미가 일반 수학 연산과 다르다.
- 포인터에서 +1의 의미는 그다음 데이터의 주소를 의미
31. 포인터가 가리키는 대상의 크기
- 포인터 변수를 선언할 때 * 연산자 앞에 적는 자료형은 포인터 변수가 가리키는 대상의 크기를 의미
- 포인터 변수가 가리키는 대상의 자료형과 포인터 변수 선언 시 적는 자료형을 동일하게 지정하는 것이 일반적
32. 포인터가 가리킬 수 있는 크기와 실제 대상의 크기가 다른 경우
- 포인터가 가리킬 수 있는 크기와 실제 대상의 크기가 다를 수 있다.
- 프로그래머가 의도적으로 두 크기를 다르게 사용하는 경우도 있다.
33. int 형 변수에 저장된 값을 1바이트 단위로 출력하기
34. void * 형 포인터
- 대상의 크기가 정해져 있지 않은 void * 형 포인터
void 키워드 : 정해져 있지 않다.
포인터 변수가 가리키는 대상의 크기를 모를 때 void * 형을 사용
사용할 메모리의 시작 주소만 알고 끝 주소를 모를 때 void * 형 포인터 사용
- void * 는 주소를 사용할 때 반드시 "사용할 크기"를 표기해야 한다.
35. void * 형 포인터 활용하기
- void * 는 자신이 사용할 대상의 크기 지정을 잠시 미룰 수 있다는 장점을 가짐
- main 함수의 지역 변수의 주소를 받아 1을 대입하는 MyFunc 함수
( MyFunc 함수에 전달되는 주소의 형식이 char *, short *, int * 중 하나 )
36. void * 형 포인터를 사용하여 지역 변수의 값 변경하기
37. void * 를 사용하여 대상 메모리의 크기 조절하기
38. 포인터 변수에서 형 변환 문법은 모든 자료형에서 사용할 수 있다.
- 포인터 변수에 직접 형 변환을 사용하는 형식은 모든 포인터에서 사용할 수 있는 개념