// 11-1 : 변수의 주소
#include <iostream>
using namespace std;
int main()
{
// 변수 정의
char c = 'B';
int i = 19;
float f = 4.5f;
// 주소 출력
cout << (int*)&c << "\n"; // int*으로 형변환. 다음장에서 설명한다.
cout << &i << "\n";
cout << &f << "\n";
return 0;
}
/*
--- 결과 ---
0000000FF4EFFAC4
0000000FF4EFFAE4
0000000FF4EFFB04
---
변수의 위치, 즉 주소를 구하는 방법은 이렇다.
변수의 이름 앞에 &(ampersand)를 붙여주는 것이다.
*/
// 11-2 : 변수 a를 가리키는 포인터 p
#include <iostream>
using namespace std;
int main()
{
int a = 123; // 일반 변수 정의
int* p; // 포인터 변수 정의
p = &a;
// 출력
cout << &a << "\n";
cout << p << "\n";
cout << &p << "\n"; // 포인터 변수의 주소
return 0;
}
/*
--- 결과 ---
00000077342FFC34
00000077342FFC34
00000077342FFC58
---
포인트 변수의 정의 예제이다.
int*는 포인터 타입을 의미한다
그러나 위처럼 정의시, int 타입의 변수만 가리킬 수 있다.
char*라고 정의하면 char를 가리킬 수 있다.
*/
// 11-3 : 여러가지 타입의 포인터
#include <iostream>
using namespace std;
int main()
{
int i = 300;
int* pi = &i;
char c = 'C';
char* pc = &c;
float f = 700.5f;
float* pf = &f;
bool b = true;
bool* pb = &b;
short int s = 456;
short int* ps = &s;
return 0;
}
/*
왜 하나의 타입밖에 가리킬 수 없을까?
이유는 메모리에 값만 저장하고 타입은 저장하지 않기 때문이다.
어떤 타입인지 지정해주어야 메모리의 어디서부터 어디까지 값을 가져올지 알 수 있다.
모든 포인터 변수의 크기는 동일하다.
담기는 값이 항상 주소값이기 때문이다.
*/
// 11-4 : void 포인터의 사용
int main()
{
int i = 400;
void* pv = &i; // void는 아무 타입이나 가리킬 수 있다. 형변환이 필요없다.
int* pi = (int*)pv; // 직접 형변환해야 안전하다.
return 0;
}
/*
형변환은 int 타입의 값이 있다라는 정보를 추가해주는 셈이다.
void포인터는 주소를 저장하는 용도로만 사용한다.
때가 되면 형변환해서 사용한다.
형변환하지 않고는 사용할 수 없다.
*/
// 11-5 : 정보에 접근하는 방법
#include <iostream>
using namespace std;
int main()
{
int a = 123;
int* p = &a;
cout << *p << "\n"; // *p는 p가 가리키는 변수라는 의미다. 즉, p의 값을 구할 수 있다.
*p = 789; // p가 가리키는 변수의 값을 변경한다.
cout << a << "\n";
cout << *p << "\n";
return 0;
}
/*
--- 결과 ---
123
789
789
---
비유하자면,
p는 과자의 위치이다. (주소)
*p는 과자 그 자체이다.
*p에서 값을 읽으면 a의 값을 반환한다.
*p에 값을 쓰면 a의 값이 바뀐다.
*/
// 11-6 : 포인터의 동작 방식
#include <iostream>
using namespace std;
int main()
{
int i = 0x12345678;
char* pc = (char*)&i;
// pc가 가리키는 값
cout << hex; // 정수를 16진수로 출력
cout << (int)*pc << "\n"; // 형변환. 숫자로 출력하게 만들기.
return 0;
}
/*
--- 결과 ---
78
---
*/
// 11-7, 8 : 일반적인 포인터 사용법, NULL의 사용
// 11-8
#include <iostream>
using namespace std;
int main()
{
// 포인터 변수 정의, 초기화
int* p = NULL;
if (NULL != p) *p = 30; // 실행 안된다.
int a = 100;
p = &a;
if (p) *p = 30; // 실행 된다.
return 0;
}
// 11-7
int main()
{
// 포인터 변수 정의, 초기화
int* p = 0;
if (0 != p) *p = 30; // 실행 안된다.
int a = 100;
p = &a;
if (p) *p = 30; // 실행 된다.
return 0;
}
/*
--- 결과 ---
---
p를 초기화하지 않은 상태로 사용하면 안된다.
오동작된다. 안전을 확신할 수 없는 포인터는 사용하기 전 확인해야한다.
개발자는 다음과 같은 습관을 가져야 한다.
1. 포인터 변수는 항상 0으로 초기화한다.
2. 사용하기 전에는 0이 아닌지 비교한다.
주소 0번지에 위치할 수 있는 변수는 없다.
그래서 아무것도 가리키지 않음의 의미로 사용한다.
매번 비교하는 것이 일반적이다.
0대신 NULL 사용이 많다.
차이가 없으나 사람이 보기에 눈에 잘띄어서 그렇다.
*/
// 11-9 : 기본 타입과 const
#include <iostream>
using namespace std;
int main()
{
const int a = 123;
a = 456;
return 0;
}
/*
--- 결과 ---
오류가 발생한다.
---
const는 변수의 값을 변경할 수 없게 만든다.
상수 같은 변수가 된다.
const는 constant로, 상수 라는 뜻의 약자다.
const는 정의할 때 반드시 초기화한다.
const 사용은 두가지 경우가 있다.
1. 처음 정의할 때 부터 const인 경우.
2. const가 아니지만, 다른 곳에 넘겨줄 때만 잠깐 const인 척 하는 경우.
*/
// 11-10 : 상수 대신에 const 변수 사용
#include <iostream>
using namespace std;
int main()
{
// 배열의 크기를 const 변수에 보관한다.
const unsigned int arraySize = 100;
char characters[arraySize] = { 0 };
for (int i = 0; i < arraySize; ++i) characters[i] = i + 1;
return 0;
}
/*
--- 결과 ---
---
상수 대신 const 변수 사용예시이다.
위처럼 하면 배열의 개수를 변경해야할 때,
중복 코드를 없애고, 실수를 줄일 수 있다.
*/
// 11-11, 12, 13, 14 : 이하 코드 주석 참고
#include <iostream>
using namespace std;
// 11-14 : 두 군데 모두 const인 경우
int main()
{
int i1 = 10;
int i2 = 20;
const int* const p = &i1;
p = &12; // X
*p = 30; // X
return 0;
}
// 11-13 : 포인터 자체가 const인 경우
int main()
{
int i1 = 10;
int i2 = 20;
int* const p = &i1; //int타입을 가리키는 p는 const 속성을 가진다 라는 뜻이다.
p = &12; // X
*p = 30; // O
return 0;
}
// 11-12 : 가리키는 변수가 const인 경우
int main()
{
int i1 = 10;
int i2 = 20;
const int* p = &i1; // p가 가리키는 변수는 const int 타입이다. 라는 뜻이다. 실제 그러한지는 중요치 않다.
p = &i2; // O
*p = 30; // X
return 0;
}
// 11-11 : const 사용하지 않은 경우
int main()
{
int i1 = 10;
int i2 = 20;
int* p = &i1;
p = &i2;
*p = 30;
return 0;
}
/*
--- 결과 ---
---
const의 의미 외우는 법
const 다음에 오는 것을 상수화시킨다.라고 생각하자.
// const int* p
const 다음에 int가 오므로. int 타입의 값.
즉, 포인터가 가리키는 값이 const이다.
// int* const p
const 다음에 p가 오므로, p 자체가 const이다.
*/
'C++ > 뇌를 자극하는 C++' 카테고리의 다른 글
[C++] 챕터 13 - 복합 타입 : 복합적인 정보 (0) | 2023.06.14 |
---|---|
[C++] 챕터 12 - 배열과 구조체와 포인터 : 복합적인 방법으로 정보를 다루는 법 (0) | 2023.06.14 |
[C++] 챕터 10 - 구조체 : 다양한 타입의 정보를 한 곳에 모으는 법 (0) | 2023.04.27 |
[C++] 챕터 9 - 배열 : 변수를 여러개 모아 놓은 변수 (0) | 2023.04.25 |
[C++] 챕터 8 - 성적표 프로젝트 Ver 1 (0) | 2023.04.25 |
댓글