[C++ 정리] 포인터 / 배열 / 구조체를 연계한 사용 2015-06-12

프로그래밍시 포인터 / 배열 / 구조체를 연계지어 사용하는 방법에 대하여 정리해보자.

pointer_array_struct

Ex1,2>에 대한 그림설명

#include "stdafx.h"
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	const int arraySize = 10;

	int numberArray[arraySize];
	int* pointer;

	/*
	 - 테스트를 위해 1~10의 값을 넣는다.
	*/
	for (int i = 0; i < arraySize; i++)
	{
		numberArray[i] = i + 1;
	}

	// 8번째 배열의 주소를 얻어온다.
	pointer = &numberArray[7];
	cout << "numberArray[7] :: " << *pointer << "\n\n";

	// Ex1> 배열의 주소를 가진 포인터는 +1 / -1 연산으로 배열의 어느 원소는 쉽게 접근이 가능하다.
	cout << "numberArray[0] :: " << *(pointer - 7) << "\n";
	cout << "numberArray[1] :: " << *(pointer - 6) << "\n";
	cout << "numberArray[2] :: " << *(pointer - 5) << "\n";
	cout << "numberArray[3] :: " << *(pointer - 4) << "\n";
	cout << "numberArray[4] :: " << *(pointer - 3) << "\n";
	cout << "numberArray[5] :: " << *(pointer - 2) << "\n";
	cout << "numberArray[6] :: " << *(pointer - 1) << "\n";
	cout << "numberArray[7] :: " << *pointer << "\n";
	cout << "numberArray[8] :: " << *(pointer + 1) << "\n";	
	cout << "numberArray[9] :: " << *(pointer + 2) << "\n\n";

	// Ex2> 포인터에 1을 더했지만 주소는 배열의 단위인 int(4byte) 만큼 더해진것을 확인할 수 있다.
	cout << "numberArray[7] ADDR :: " << pointer << "\n";
	cout << "numberArray[8] ADDR :: " << pointer + 1 << "\n\n";
	
	// Ex3> 정의된 배열 변수는 첫번째원소의 주소와 같다
	cout << "numberArray == &numberArray[0] ? :: " << (numberArray == &numberArray[0] ? "true" : "false") << "\n\n";

	// Ex4> 배열 포인터 정의
	// - int*를 arraySize만큼 갖는 배열 4byte X 10 = 40byte
	int* pointerArray1[arraySize];
	cout << "arrayPointer Define1 :: " << sizeof(pointerArray1) << "\n";
	// - arraySize만큼 갖는 배열의 포인터 4byte
	int (*pointerArray2)[arraySize];
	pointerArray2 = &numberArray;
	cout << "arrayPointer Define2 :: " << sizeof(pointerArray2) << "\n";
	for (int i = 0; i < arraySize; i++)
	{
		cout << "arrayPointer access :: " << (*pointerArray2)[i] << "\n";
	}
	cout << "\n";

	// Ex5> 구조체 포인터 정의
	struct dotStruct{
		int x;
		int y;
	};
	dotStruct dot = { 100, 200 };
	dotStruct* pointerDot;
	pointerDot = &dot;

	// - 구조체의 맴버에 접근방법은 다음과 같이 두가지다
	cout << pointerDot->x << "\n";
	cout << (*pointerDot).x << "\n\n";

	// Ex5> 구조체에 포함된 포인터
	struct userStruct{
		char name[10];
		userStruct* user;
	};
	userStruct users[6] = {
		{ "AAAA", &users[1] },
		{ "BBBB", &users[2] },
		{ "CCCC", &users[3] }
	};
	// 또는 다음과 같이 정의
	//userStruct users[3];
	strcpy_s(users[3].name, "DDDD");
	users[3].user = &users[4];
	strcpy_s(users[4].name, "EEEE");
	users[4].user = &users[5];
	strcpy_s(users[5].name, "FFFF");
	users[5].user = &users[0];
	// ※ users[0].name = "AAAA"는 에러이다. &name[0] = "AAAA" 하는 것과 같다.
	//		strcpy(users[0].name, "AAAA");
	
	// - 구조체에 포함된 포인터에 접근방법은 다음과 같다
	cout << "struct pointer :: " << users[0].user->user->user->user->user->user->user->name << "\n";

	cout << "struct pointer :: " << (*users[0].user).name << "\n";
	
	return 0;
}
* Ex1,2> 배열을 포인터로 접근하는 방법
* Ex3> 정의된 배열변수는 첫번째 원소의 주소와 같다.
* Ex4> 유형별 배열 포인터를 정의하는 방법
* Ex5> 구조체를 포인터에 담고 사용하는 방법
* Ex6> 구조체에 포함된 포인터를 사용하는 방법

[C++ 정리] const(상수)의 활용 2015-06-11

const 키워드와 함께 정의한 변수의 값는 수정이 불가능하다. 즉 상수화 되어버리는데, 프로그래밍시에 바뀌어서는 안될값이 있을 경우 활용할 수 있다. 코드가 길어질 경우 실수로 변수의 값이 바뀌어 지는것을 방지할 수 있다.

Ex1> 배열의 크기를 상수화하여 전역에서 사용한다.

#include "stdafx.h"
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	const unsigned short arraySize = 100;

	int number[arraySize] = { 0 };

	for (int i = 0; i < arraySize; i++)
	{
		cout << i + 1 << "::" << number[i] << "\n";
	}

	return 0;
}

 

Ex2> 포인터 또한 다음과 같은 유형으로 상수화 할 수 있다.

#include "stdafx.h"
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	int number1 = 10;
	int number2 = 20;

	// Ex 1>
	// 포인터가 가리키는 값이 const일 경우
	const int* pointer_ex1 = &number1;
	// 포인터값은 변경가능하다
	pointer_ex1 = &number2;
	// [Error] 가리키는 값을 변경할 수 없다.
	//*pointer_ex1 = 30;

	cout << *pointer_ex1 << "\n";

	// Ex 2>
	// 포인터가 const 일경우
	int* const pointer_ex2 = &number1;
	// [Error] : 포인터값을 변경할 수 없다
	// pointer_ex2 = &number2;
	// 가리키는 값은 변경가능하다
	*pointer_ex2 = 30;

	cout << *pointer_ex2 << "\n";

	// Ex 3>
	// 포인터와 가리키는 값이 const 일경우
	const int* const pointer_ex3 = &number1;
	// [Error] : 포인터값을 변경할 수 없다
	// pointer_ex2 = &number2;
	// [Error] 가리키는 값을 변경할 수 없다.
	//*pointer_ex2 = 30;

	cout << *pointer_ex3 << "\n";

	return 0;
}

 

[C++ 정리] 포인터 기본 개념 및 예시 2015-06-11

포인터는 다른 변수의 위치를 가르키는 변수이다. 다음 그림과 같이 값을 담은 변수에 대하여 주소값을 가질 수 있으며 이는 프로그래밍에서 유용하게 활용 될 수 있다.

pointer
#include "stdafx.h"
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	int value = 1206;
	// ※ 포인터 변수는 항상 0 또는 NULL로 초기화 하고 사용할때는 항상 0 또는 NULL인지를 확인한다.
	//    - 0으로 초기화 하지 않는다면 쓰레기 값을 가지게 되고 
	//      만약 쓰레기 값이 다른 중요한 정보를 접근할 경우 
	//      심각한 문제가 발생할 여지가 있다.
	int* pointer = NULL;

	// Ex1> pointer는 포인터형 변수 이므로 value의 주소값만 받을 수 있다.
	// value 앞에 &(Ampersand)를 붙여주면 주소값이 된다.
	pointer = &value;
	// [Error]
	//pointer = value;

	// Ex2> pointer가 가리키고 있는 값을 출력할때는 앞에 *를 붙여야 한다.
	cout << "Ex2.\n";
	cout << "ADDRESS : " << pointer << "\n";
	cout << "VALUE : " << *pointer << "\n";
	cout << "\n";

	// Ex3> 포인터변수에 주소를 지정할때는 동일한 자료형의 주소만 받을 수 있다.
	float* pointer_float;
	float temp = (float)value;
	pointer_float = &temp;
	cout << "Ex3-1.\n";
	cout << "VALUE : " << *pointer_float << "\n";
	cout << "\n";
	// [Error] : 다른 자료형의 포인트 변수라면 형변환을 해주면 에러가 나지는 않지만 쓰레기 값이 출력된다.
	// - 이는 정수타입의 메모리를 실수타입으로 분석해버려서 이다.
	float* pointer_temp;
	pointer_temp = (float*)&value;
	cout << "Ex3-2.\n";
	cout << "VALUE : " << *pointer_temp << "\n";
	cout << "\n";
	// [Error] : 메모리에는 변수의 값만 저장하기 때문에 자료형을 알 수가 없기때문에 규칙위반이다.
	//pointer_temp = &value;	

	// Ex4> 포인터변수에 동일한 자료형이 아닌 주소를 받아 유연하게 사용하려면 void*를 사용한다.
	void* pointer_void;
	pointer_void = &value;
	// 사용할 때는 다시 형변환을 해주어야 한다.
	int* pointer_test = (int*)pointer_void;
	cout << "Ex4.\n";
	cout << "ORG_ADDRESS : " << pointer_void << "\n";
	cout << "NEW_ADDRESS : " << pointer_test << "\n";
	// [Error] : 원래 자료형과 다른 포인터 형이므로 규칙위반이다.
	// cout << "VALUE : " << *pointer_void << "\n";
	cout << "VALUE : " << *pointer_test << "\n";
	cout << "\n";

	// Ex5> 포인터변수 크기는 시스템의 기본연산단위를 사용한다. 자료형별 차이는 없다.
	// (16bit=>2byte, 32=>4byte, 64=>4byte)
	cout << "Ex5.\n";
	cout << "char* \t\t: " << sizeof(char*) << " bytes\n";
	cout << "int* \t\t: " << sizeof(int*) << " bytes\n";
	cout << "float* \t\t: " << sizeof(float*) << " bytes\n";
	cout << "double* \t: " << sizeof(double*) << " bytes\n";
	cout << "\n";

	return 0;
}