『Lena's by ☆볶기!!』: Restart !!

Rorolena
1-9 정보에 대한 정보

-/1. 포인터의 기본/-

변수의 주소
-----------------------------------------------------------------------
#include <iostream>
using namespace std;

int main()
{
 // 변수를 정의한다.
 char c = 'B';
 int i = 19;
 float f = 4.5f;

 // 주소를 출력한다.
 cout << "c의 주소 = " << (int*)&c << "\n";
 cout << "i의 주소 = " << &i << "\n";
 cout << "f의 주소 = " << &f << "\n";

 return 0;
}
-----------------------------------------------------------------------
point

1. 변수의 이름 앞에 &를 붙여주면
변수의 위치 주소를 구할수있다.

변수 a를 가리키는 포인터 p
-----------------------------------------------------------------------
#include <iostream>
using namespace std;

int main()
{
 // 일반적인 변수를 정의한다.
 int a = 123;

 // 포인터 변수를 정의한다.
 int* p;

 // p가 a를 가리키게 만든다.
 p = &a;

 // 관련 정보를 출력한다.
 cout << "&a = " << &a << "\n";
 cout << "p = " << p << "\n";
 cout << "&p = " << &p << "\n";

 return 0;
}
-----------------------------------------------------------------------
point

1. int*은 포인터 타입을 의미한다.

2. 포인터또한 변수값을 가지며
오직 변수위치의 주소값만을 저장할수 있다.

tip

1. 아래의 포인터를 한줄로
줄여써보면 이렇게 쓸수있다.
int* p;
p = &a;



int* p = &a;

여러 가지 타입의 포인터
-----------------------------------------------------------------------
int main()
{
 // int 타입
 int i = 300;
 int* pi = &i;

 // char 타입
 char c = 'C';
 char* pc = *c;

 // float 타입
 float f = 700.5f;
 float* pf = &f;

 // bool 타입
 bool b = ture;
 bool* pb = &b;

 // short int 타입
 short int s = 456;
 short int* ps = &s;

 return 0;
}
-----------------------------------------------------------------------
point

1. 포인터를 사용 할때에는 가리키고자 하는
변수와 타입을 동일하게 해주어야 한다.
포인터 변수는 변수위치의 주소만을 저장할뿐
그 위치의 변수가 어떠한 타입인지에
관한 정보는 저장하지 않기 때문이다.

2. 아래의 포인터 방식으 모두 똑같다.
int* p;
int *p;
int * p;

tip

1. 포인터 변수의 크기
모든 포인터 변수의 크기는 동일하다.
그 포인터가 가리킬 수 있는 타입이 무엇이던
간에 어짜피 값은 주소 값이기 때문이다.

예로 32비트 윈도우즈 시스템은 4바이트
16비트 DOS 시스템은 2바이트여야
모든 주소값을 담을수있다.

2. void 포인터
void 포인터는 포인터 타입중 하나 인데
이는 모든 타입을 가리킬 수 있는 포인터다.
(정의 하면 void* p;와같이 쓸수있다.
또한 이것은 변수로는 사용할수 없다.)

하지만 void 포인터는 가르키는 변수가
어떠한 타입인지 알수 없기에 사용 할수는 없고
주 활용예로는 주소를 저장하는 용도로만 사용된다.
만약 이를 사용하려면 타입이 있는 포인터로
형변환을 시킬 필요가 있다.

void 포인터의 사용
-----------------------------------------------------------------------
int main()
{
 // int 타입의 주소를 void 포인터에 보관
 int i = 400;
 void* pv = &i;

 // pv에 보관된 주소를 int*타입의 변수에 옮겨 담는다.
 int* pi = (int*)pv;

 return 0;
}
-----------------------------------------------------------------------
point

1. void는 어떠한 형의 값이든 저장할수 있다.
허나 이런점 때문에 어떠한 타입인 지는 알수없어
위와같은 방식으로 주소 저장에 흔히 쓰인다.

이런 void 포인터의 값을 사용하려면
void 포인터를 출력하고자 하는 타입으로
형변환을 해준후 출력해 사용해야 한다.

정보에 접근하는 방법
-----------------------------------------------------------------------
#include <iostream>
using namespace std;

int main()
{
 // p가 a를 가르키게 만든다.
 int a = 123;
 int* p = &a;

 // p가 가리키는 변수의 값을 얻는다.
 cout << "*p = " << *p << "\n";

 // p가 가리키는 변수의 값을 변경한다.
 *p = 789;

 // 과련 정보를 출력한다.
 cout << "a = " << a << "\n";
 cout << "*p = " << *p << "\n";

 return 0;
}
-----------------------------------------------------------------------
point

1. 정보에 접근을 하기 위해서는 먼저
정보의 위치와 값을 얻어야한다.

이경우 포인터가 대상의 변수를 가르키도록
만들어 준후 그 대상을 가르키는 값을
 *p = 789; 와같이 수정하면 된다.

포인터의 동작 방식 확인
-----------------------------------------------------------------------
#include <iostream>
using namespace std;

int main()
{
 // int 타입의 변수 정의
 int i = 0x12345678;

 // char* 타입의 포인터로 i를 가리킨다.
 char* pc = (char*)&i;

 // pc가 가리키는 값을 구한다.
 cout << hex;
 cout << "*pc = " << (int) *pc << "\n";

 return 0;
}
-----------------------------------------------------------------------
point

1. 인트의 값을 준비하고 캐릭터
포인터를 만든후 인트를 가르키면
포인터는 인트의 값중 캐릭터 값인
1바이트 만큼의 정보만 읽어 들인다.

포인터와 NULL의 사용
-----------------------------------------------------------------------
#include <iostream>

int main()
{
 // 포인터 변수를 정의하고 초기화한다.
 int* p = NULL;

 // 이 상태에서 포인터를 사용해보자.
 if (NULL != p)
  *p = 30;

 // p가 변수를 가리키게 만들자
 int a = 100;
 p = &a;

 // 이 상태에서 포인터를 사용해보자.
 if (!p)
  *p = 30;

 return 0;
}
-----------------------------------------------------------------------
point

1. 포인터를 이용함에있어 가능한
0으로 초가화와 0임을 확인할 필요가 있다.
이는 쓰레기값에 의한 오작동을 방지하기 위함이다.

2. 이 소스에서는 0과 NULL은 같은 일을 수행한다.
(NULL은 아무것도 가리키지 않음을 나타낸다.)

상수 대신에 const 속성의 변수 사용.cpp
-----------------------------------------------------------------------
int main()
{
 // 배열의 크기를 const 변수에 보관한다.
 const unsigned int arraySize = 100;

 // 배열을 정의한다.
 char characters[ arraySize ] = {0};

 // 배열에 1 ~ arraySize의 값을 넣는다.
 for (int i = 0; i < arraySize; ++i)
  characters[i] = i + 1;

 return 0;
}
-----------------------------------------------------------------------
point

1. const는 변수의 값을 변경할 수 없도록 만드는 명령문이다.
고로 const를 사용해서 변수를 정의할 때는 반드시 초기화를 해줘야 한다.

이런 const의 사용은 개발자의 불변경 의지와
타 개발자의 소스 의도 판별을 도와준다.

2. const unsigned int arraySize = 100;
char characters[ arraySize ] = {0};

이러한 방식으로 배열을 정의할경우
개발도중 배열의 수를 조정해야할때
관리와 편의성과 수정시 프로그래밍
실수를 줄일수있는 효과가있다.

포인터와 포인터가 가르키는 변수가 const 인 경우
-----------------------------------------------------------------------
int i1 = 10;
int i2 = 20;
const int* const p = &i1;

p = &i2; // FAIL
*p = 30; // FAIL
-----------------------------------------------------------------------
point

1. 포인터 변수를 정의할 때는 const를 최대 2개까지 포함할 수 있다.
하나는 포인터 변수 자체에 보관된 정보이고 다른 하나는
포인터가 가리키는 변수에 보관된 정보 때문이다.

2. const int* const p = &i1; 에서 앞에 걸어준 const는
p가 가리키는 변수는 const int 타입이다 라는 의미로써
p가 가리키는 변수의 값을 바꾸는 것을 허용하지 않게 된다.

3. const int* const p = &i1; 에서 뒤에 걸어준 const는
int 타입을 가리키는 p는 const 속성을 갖는다 라는 의미로써
p의 값을 바꾸는 행위는 용납되지 않는다.

tip

1. const의 의미를 외우는 법
const의 다음에 오는 것을 상수화시켜버린다고 생각하면 된다.
const int* p는 const 다음에 int가 오므로 int 타입의 값,
즉 포인터가 가리키는 값이 const가 된다.
int* const p의 경우에는 const 다음에 p가 오므로
p자체가 const가 된다.