profile image

L o a d i n g . . .

반응형

배열 기초 array

#include <iostream>

using namespace std;

#define D_NUM_STUDENTS 100000

struct Rectangle
{
	int length;
	int width;
};

enum StudentName
{
	JACKJACK,	// = 0
	DASH,		// = 1
	VIOLET,		// = 2
	NUM_STUDENTS,	// = 3
};

int main()
{
	/*
	int student1_score;	// jack jack
	int student2_score;	// dash
	int student3_score;	// violet
	*/
	int one_student_score;	// 1 variable
	int student_scores[5];	// 5 int

	cout << sizeof(one_student_score) << endl;	// 4
	cout << sizeof(student_scores) << endl;		// 20

	one_student_score = 100;

	student_scores[0] = 100;	// 1st element, 0:index
	student_scores[1] = 80;		// 2nd element
	student_scores[2] = 90;		// 3rd element
	student_scores[3] = 50;		// 4th element
	student_scores[4] = 0;		// 5th element
	//student_scores[5] = 30;	// 6th element? runtime error!
	// 집주인에게 허락받지 않고 옆집을 사용해 버린 상황

	cout << student_scores[0] << endl;
	cout << student_scores[1] << endl;
	cout << student_scores[2] << endl;
	cout << student_scores[3] << endl;
	cout << student_scores[4] << endl;
	//cout << student_scores[5] << endl;

	// 평범한 변수처럼 사용 가능함
	cout << (student_scores[0] + student_scores[1]) / 2.0 << endl;


	// 구조체 배열
	Rectangle rect_arr[10];

	cout << sizeof(Rectangle) << endl;
	cout << sizeof(rect_arr) << endl;

	rect_arr[0].length = 1;
	rect_arr[0].width = 2;


	// 배열 초기화
	int my_array[5] = { 1, 2, 3 };	// 넣지 않으면 알아서 초기화
	int my_array2[] = { 1, 2, 3, 4, 5 };
	int my_array3[]{ 1, 2, 3, 4, 5 };	// C++ 11부터 가능


	// enum 사용 가능
	int students_scores[NUM_STUDENTS];
	students_scores[JACKJACK] = 0;
	students_scores[DASH] = 100;


	
	int num_students = 0;
	cin >> num_students;

	//int students_scores2[num_students];	error!!
	// cin으로 입력받는다는 것은 runtime에 값이 정해진다는 뜻임
	// 사이즈가 고정된 배열의 사이즈는 compile-time에 고정되어야 함!!
	// => C style: #define D_NUM_STUDENTS 100000(큰 수)
	// 동적 할당을 이용하면 되기 때문에 권장하지 않음


	// const 변수로 사이즈 설정은 가능
	const int num_students2 = 10;

	int students_scores3[num_students2];

	return 0;
}
#include <iostream>

using namespace std;

void doSomething(int students_scores[20])	// == int students_score[], 포인터로 받아서 괄호 안 상관없음
{
	// array를 함수의 parameter로 넣어 줄 수 있음
	cout << (int)&students_scores << endl;		// 포인터 변수의 주소값
	cout << (int)&students_scores[0] << endl;	// 포인터 변수에 저장되어 있는 값(원래 배열)
	cout << students_scores[0] << endl;
	cout << students_scores[1] << endl;
	cout << students_scores[2] << endl;
	cout << "Size in doSomething : " << sizeof(students_scores) << endl;	// 포인터의 size
}

int main()
{
	const int num_students = 20;
	//cin >> num_students;

	int students_scores[num_students] = {1, 2, 3, 4, 5};

	cout << (int)&students_scores << endl;		//1832, 첫 번째 방 주소
	cout << (int)&students_scores[0] << endl;	//1832
	cout << (int)&students_scores[1] << endl;	//1836
	cout << (int)&students_scores[2] << endl;	//1840
	cout << (int)&students_scores[3] << endl;	//1844

	cout << sizeof(students_scores) << endl;	// 80

	cout << endl;

	// ~함수와 메인 함수에서의 배열 주소가 다르게 찍히는 이유~
	// 배열은 이름 자체가 내부적으로 주소로 사용이 됨, &를 붙이지 않아도 주소를 얻을 수 있음
	// 함수의 매개변수로 받은 것(int students_scores[20])은 배열이 아니라 포인터!
	// 배열을 받을 때 사용을 할 것이라고 코딩을 할 수 있는 것뿐, 컴파일러 내부에서는 포인터로 처리함
	// 배열의 모든 원소를 복사해서 가져오는 것이 아닌, 배열의 첫 번째 주소값만 넘어간다는 것임
	cout << (int)&students_scores << endl;
	cout << students_scores[0] << endl;
	cout << students_scores[1] << endl;
	cout << students_scores[2] << endl;
	cout << "Size in main : " << sizeof(students_scores) << endl;

	doSomething(students_scores);

	return 0;
}

 

 

배열과 반복문

#include <iostream>

using namespace std;

int main()
{
	//const int num_students = 5;
	/*
	int score0 = 84;
	int score1 = 92;
	int score2 = 76;
	int score3 = 81;
	int score4 = 56;

	int total_score = score0 + score1 + score2 + score3 + score4;

	double avg_score = static_cast<double>(total_score) / num_students;
	//Note: double(total_score) / num_students != double(total_score / num_students);
	*/

	int scores[] = { 84, 92, 76, 81, 56 };

	// 배열이 함수 parameter로 넘어갔을 때, 함수에서 이렇게 연산하면 포인터의 사이즈를 계산해 버릴 수 있으니 주의!!
	// 배열을 보낼 때는 elements 개수를 같이 넘기기
	const int num_students = sizeof(scores) / sizeof(int);

	int max_score = 0;
	int min_score = numeric_limits<int>::max();
	int total_score = 0;
	

	for (int i = 0; i < num_students; i++)
	{
		total_score += scores[i];
		if (scores[i] > max_score)
			max_score = scores[i];
		//max_score = (max_score < scores[i]) ? scores[i] : max_score;
		if (scores[i] < min_score)
			min_score = scores[i];
		//min_score = (min_score > scores[i]) ? scores[i] : min_score;
	}

	double avg_score = static_cast<double>(total_score) / num_students;

	cout << max_score << endl;
	cout << min_score << endl;

	return 0;
}

 

 

배열과 선택 정렬 selection sort

정렬(sorting): 순서를 맞춰 주는 것

#include <iostream>

using namespace std;

void printArray(const int array[], int length)
{
	for (int index = 0; index < length; index++)
		cout << array[index] << " ";
	cout << endl;
}

int main()
{
	/*		value	index
	3 5 2 1 4	1	3
	1 5 2 3 4	2	2
	1 2 5 3 4	3	3
	1 2 3 5 4	4	4
	1 2 3 4 5
	*/

	const int length = 5;

	int array[length] = { 3,5,2,1,4 };
	printArray(array, 5);

	// swap
	//int temp = array[0];
	//array[0] = array[1];
	//array[1] = temp;
	//
	//printArray(array, 5);
	// std::swap(...)

	// 내가 구현한 선택 정렬
	for (int i = 0; i < length - 1; i++)
	{
		int value = array[i];
		int index = i;

		for (int j = i + 1; j < length; j++)
		{
			if (array[j] < value)
			{
				value = array[j];
				index = j;
			}
		}
		array[index] = array[i];
		array[i] = value;

		printArray(array, length);
	}
	cout << endl;


	int array2[length] = { 8,1,9,3,5 };
	printArray(array2, length);

	for (int startIndex = 0; startIndex < length - 1; startIndex++)
	{
		int smallestIndex = startIndex;

		for (int currentIndex = startIndex + 1; currentIndex < length; currentIndex++)
		{
			if (array2[smallestIndex] > array2[currentIndex])
			{
				smallestIndex = currentIndex;
			}
		}
		// swap two values in the array
		// std::swap(array2[smallestIndex], array[startIndex]);
		{
			int temp = array2[smallestIndex];
			array2[smallestIndex] = array2[startIndex];
			array2[startIndex] = temp;
		}
		printArray(array2, length);
	}


	return 0;
}

 

 

정적 다차원 배열

메모리는 일차원적 구조

#include <iostream>

using namespace std;

int main()
{
	const int num_rows = 3;
	const int num_columns = 5;

	for (int row = 0; row < num_rows; row++)
	{
		for (int col = 0; col < num_columns; col++)
		{
			cout << '[' << row << ']' << '[' << col << ']' << '\t';
		}
		cout << endl;
	}

	cout << endl;


	int array[num_rows][num_columns] =	// row-major <-> column-major
	{
		{1,2,3,4,5},		// row 0
		{6,7,8,9,10},		// row 1
		{11,12,13,14,15}	// row 2
	};
	//array[0][0] = 1;

	for (int row = 0; row < num_rows; row++)
	{
		for (int col = 0; col < num_columns; col++)
		{
			cout << array[row][col] << '\t';
		}
		cout << endl;
	}

	cout << endl;

	// 주소 찍어 보면 4씩 차이남
	for (int row = 0; row < num_rows; row++)
	{
		for (int col = 0; col < num_columns; col++)
		{
			cout << (int)&array[row][col] << '\t';
		}
		cout << endl;
	}

	// num_rows만 생략 가능! num_columns는 생략 불가능
	int array2[][num_columns] =
	{
		{1,2},	// 나머지 0으로 채움
		{6,7,8,9,10},
		{11,12,13,14,15}
	};

	int array3[num_rows][num_columns] = { 0 };


	int array4[5][4][3];

	return 0;
}

 

 

C언어 스타일의 배열 문자열

#include <iostream>
#include <cstring>

using namespace std;

int main()
{
	char myString[] = "string";	// 마지막 자리에 null character가 있음! '\0'

	for (int i = 0; i < 7; i++)
		cout << (int)myString[i] << endl;

	cout << sizeof(myString) / sizeof(myString[0]) << endl;	// array size: 7
	cout << endl;

	// 입력받기
	char myString2[255];
	//cin >> myString2;
	cin.getline(myString2, 255);	// 공백 포함해서 입력받기

	//myString2[0] = 'A';
	//cout << myString2 << endl;

	// char로 된 문자열을 출력할 경우, NULL(\0)이 나오기 전까지 출력함
	//myString2[4] = '\0';
	//cout << myString2 << endl;

	int ix = 0;

	// while문으로 출력하기
	while (true)
	{
		if (myString2[ix] == '\0') break;

		cout << myString2[ix] << " " << (int)&myString2[ix] << endl;
		ix++;
	}
	cout << endl;


	// cstring 안에 정의되어 있는 함수들
	char source[] = "Copy this!";
	char dest[50];
	strcpy_s(dest, 50, source);

	//cout << source << endl;
	//cout << dest << endl;

	//strcat() 문자열 뒤에 붙여 주기
	strcat_s(dest, source);

	cout << "source: " << source << endl;
	cout << "dest: " << dest << endl;


	//strcmp() 두 문자열이 동일한지 비교하기
	//같으면 0 return!! 조건문 사용시 조심
	cout << strcmp(source, dest) << endl;
	if (strcmp(source, dest) == 0)
	{

	}


	return 0;
}
//strcat와 동일하게 작동하는 함수 구현
//strcmp와 동일하게 작동하는 함수 구현

#include <iostream>

using namespace std;

void myStrcat(char *ori, int length, const char *cop)
{
	int idx = 0;
	while (true)
	{
		ori[length + idx] = cop[idx];
		if (cop[idx++] == '\0')
			break;
	}
}

int myStrcmp(char *c1, char *c2)
{
	int idx = 0;
	while (c1[idx] != '\0' || c2[idx] != '\0')
	{
		if (c1[idx] > c2[idx])
		{
			return 1;
		}
		else if (c1[idx] < c2[idx])
		{
			return -1;
		}
		idx++;
	}
	return 0;
}

int myStrlen(char *ori)
{
	int idx = 0;
	while (true)
	{
		if (ori[idx] == '\0')
			return idx;
		idx++;
	}
}

int main()
{
	const int MAX = 100;
	char a[MAX] = "Hello ";
	char b[MAX] = "World!";
	int length = myStrlen(a);

	cout << length << endl;

	myStrcat(a, length, b);

	length = myStrlen(a);

	for (int i = 0; i < length; i++)
	{
		cout << a[i];
	}
	cout << endl;

	char c[MAX] = "aaaazz";
	char d[MAX] = "aaaazz";

	cout << (myStrcmp(c, d) == 0 ? "두 문자열은 같습니다." : "두 문자열은 다릅니다.") << endl;

	return 0;
}

 

 

포인터의 기본적인 사용법

지역 변수: '스택'

동적 할당 메모리: '힙'

필요한 데이터가 저장되어 있는 주소를 사용하여 직접 접근하여 가져온다.

#include <iostream>

using namespace std;

int* doSomething(int* ptr_a)
{
	return nullptr;
}

struct Something
{
	int a, b, c, d;	// 4 * 4bytes
};

int main()
{
	int x = 5;

	cout << x << endl;
	cout << &x << endl;	// &: address-of operator
	cout << (int)&x << endl;

	// de-reference operator (*)
	// reference: 간접적으로 참고하는 개념
	// de-reference: 포인터가 데이터의 주소를 간접적으로 가리키고 있는 것에 대하여, 그곳에 뭐가 있는지 직접 접근하겠다는 의미

	cout << *(&x) << endl;	// == x
	cout << endl;

	// pointer: 메모리 주소를 담는 변수
	typedef int* pint;
	int *ptr_x = &x, *ptr_y = &x;
	//int *ptr_x = &x, ptr_y = &x;	// error!! ptr_y에도 *을 붙여야 함
	//pint ptr_x = &x, ptr_y = &x;	// 가능하지만 typedef보다는 직접 선언하기

	cout << ptr_x << endl;	// 데이터의 주소
	cout << *ptr_x << endl;	// 데이터의 주소에 있는 내용(데이터)

	cout << endl;

	// array를 parameter로 넣으면 전부 복사됨... => 포인터로 첫 번째 주소와 데이터 개수만 알려 준다면 해결 가능
	
	double d = 123.0;
	//int *ptr_i = &d;	// error!
	double *ptr_d = &d;

	cout << ptr_d << endl;
	cout << *ptr_d << endl;

	cout << typeid(ptr_x).name() << endl;	// 출력: int *, gcc에서는 Pi 출력


	// 포인터 자체의 사이즈는 고정! 주소는 그냥 주소임!
	// 단, 포인터에도 타입이 있는 이유는 de-referencing을 위해
	// 64비트에서는 주소가 더 긺
	cout << sizeof(x) << endl;	// 출력: 4
	cout << sizeof(d) << endl;	// 출력: 8
	cout << sizeof(&x) << " " << sizeof(ptr_x) << endl;	// 출력: 4 4
	cout << sizeof(&d) << " " << sizeof(ptr_d) << endl;	// 출력: 4 4
	
	cout << endl;

	Something ss;
	Something *ptr_s;

	cout << sizeof(Something) << endl;	// 출력: 16
	cout << sizeof(ptr_s) << endl;		// 출력: 4

	cout << endl;

	// 초기화 안 된 상태에서 출력하면 엉뚱한 값임
	int *ptr_a;
	cout << *ptr_a << endl;


	return 0;
}

 

 

널 포인터 Null Pointer

#include <iostream>
#include <cstddef>

using namespace std;

void doSomething(double *ptr)
{
	// parameter는 다시 선언이 되고, 값이 복사가 되는 형식임! 따라서 다른 main()과 주소 출력!
	cout << "address of pointer variable in doSomething() " << &ptr << endl;
	if (ptr != nullptr)
	{
		// do something useful
		cout << *ptr << endl;
	}
	else
	{
		// do nothing with ptr
		cout << "Null ptr, do nothing" << endl;
	}
}

int main()
{
	double *ptr = 0;	// c-style
	double *ptr2 = NULL;
	double *ptr3{ nullptr };	// modern C++
	double d = 123.4;

	doSomething(ptr);
	doSomething(nullptr);
	doSomething(&d);

	ptr = &d;

	doSomething(ptr);

	cout << "address of pointer variable in main() " << &ptr << endl;


	std::nullptr_t nptr;	// null pointer type, parameter로 널 포인터만 받아야 하는 경우 사용

	return 0;
}

 

 

포인터와 정적 배열

이후 메모리 동적 할당, 동적 배열 등을 이해할 때 중요함

#include <iostream>

using namespace std;

//void printArray (int *array)	동일함!
void printArray(int array[])
{
	// parameter로 배열이 들어오는 것처럼 보이지만, 내부적으로는 포인터로 다룸
	cout << sizeof(array) << endl;	// 출력: 4
	cout << *array << endl;	// 출력: 9

	*array = 100;
}


int main()
{
	int array[5] = { 9,7,5,3,1 };

	// array는 배열이 아니라 '포인터', 첫 번째 방의 주소를 담고 있음
	cout << array[0] << " " << array[1] << endl;
	cout << array << endl;	// == &array[0]
	cout << &array[0] << endl;

	cout << *array << endl;	// 출력: 9

	// 문자형 포인터이기 때문에 직접 접근 시 문자형으로 출력함
	char name[] = "jackjack";
	cout << *name << endl;	// 출력: j


	int *ptr = array;
	cout << ptr << endl;	// == &array[0]
	cout << *ptr << endl;	// 출력: 9


	cout << sizeof(array) << endl;	// 출력: 20, 4*5
	cout << sizeof(ptr) << endl;	// 출력: 4, 포인터 변수의 size


	printArray(array);

	// printArray 함수 안에서 변경한 것을 main 함수에서도 확인 가능
	// C에서는 이러한 용도로 많이 사용하였음, C++은 reference를 사용
	cout << array[0] << " " << *array << endl;	// 출력: 100 100

	
	// 포인터 연산, 다음 항목 출력 가능
	cout << *ptr << " " << *(ptr + 1) << endl;	// 출력: 100 7


	return 0;
}

#include <iostream>

using namespace std;

struct MyStruct
{
	int array[5] = { 9,7,5,3,1 };
};

void doSomething(MyStruct ms)
{
	cout << sizeof(ms.array) << endl;	// 출력: 20
}

void doSomething(MyStruct *ms)
{
	cout << sizeof((*ms).array) << endl;	// 출력: 20
}


int main()
{
	// array가 structure, class 안에 들어 있을 경우, 포인터로 강제 변환되지 않음
	MyStruct ms;
	cout << ms.array[0] << endl;
	cout << sizeof(ms.array) << endl;	// 출력: 20

	doSomething(ms);
	doSomething(&ms);

	return 0;
}

 

 

포인터 연산과 배열 인덱싱

#include <iostream>

using namespace std;

int main()
{
	short value = 7;
	short *ptr = &value;

	// 데이터 타입의 사이즈에 맞춰서 옆으로 한 칸
	cout << uintptr_t(ptr - 1) << endl;
	cout << uintptr_t(ptr) << endl;
	cout << uintptr_t(ptr + 1) << endl;
	cout << uintptr_t(ptr + 2) << endl;


	int array[] = { 9,7,5,3,1 };
	int *ptr2 = array;

	for (int i = 0; i < 5; i++)
	{
		//cout << array[i] << " " << uintptr_t(&array[i]) << endl;
		cout << *(ptr2 + i) << " " << uintptr_t(ptr2 + i) << endl;
	}


	char name[] = "Jack jack";

	const int n_name = sizeof(name) / sizeof(name[0]);

	char *ptr3 = name;

	for (int i = 0; i < n_name; i++)
	{
		//cout << *(name + i);
		cout << *(ptr3 + i);
	}


	return 0;
}

#include <iostream>
// while문과 break를 사용해서 문자열을 출력, 마지막에 널 캐릭터는 출력하지 않게끔
// 포인트 연산 사용 ++ptr

using namespace std;

void printArray(char *arr)
{
	char *ptr = arr;
	while (true)
	{
		cout << *ptr << endl;
		if (*(++ptr) == '\0')
			return;
	}
}

int main()
{
	const int MAX = 100;
	char array[MAX];

	cout << "문자열을 입력해 주세요." << endl;
	while (true)
	{
		cin.getline(array, MAX);
		if (!cin.fail())
			break;
		cin.clear();
		cin.ignore(MAX, '\n');
	}

	printArray(array);

	return 0;
}

 

 

C언어 스타일의 문자열 심볼릭 상수

#include <iostream>

using namespace std;

// return type 가능
const char* getName()
{
	return "Jack Jack";
}

int main()
{
	//char name[] = "Jack Jack";
	//char *name = "Jack Jack";	error!! 실제로 "Jack Jack"이 담길 메모리에 대한 정보가 없음
	const char *name = "Jack Jack";	// 가능
	const char *name2 = getName();
	const char *name3 = "Jack Jack2";

	cout << uintptr_t(name) << endl;
	cout << uintptr_t(name2) << endl;	// 동일한 메모리 사용
	cout << uintptr_t(name3) << endl;	// 다른 메모리 사용


	int int_arr[5] = { 1,2,3,4,5 };
	char char_arr[] = "Hello, World!";

	// cout에서 문자열은 특별하게 처리함! 문자의 포인터가 들어오면 문자의 배열일 가능성이 높다고 판단
	cout << int_arr << endl;	// 출력: 주소
	cout << char_arr << endl;	// 출력: Hello, World!
	cout << name << endl;		// 출력: Jack Jack

	char c = 'Q';
	// 메모리 주소가 들어가니까 문자열이라고 생각하기 때문에, null이 나올 때까지 쭉 출력함!
	cout << &c << endl;	

	return 0;
}

 

 

메모리 동적 할당 new와 delete

static memory allocation: 전역 변수, static 변수 등 한번 만들어지면 프로그램이 끝날 때까지 계속 메모리를 갖고 있는 것

dynamic memory allocation

자동 메모리 할당: 변수, 정적 배열 등 블럭 밖으로 나가면 메모리 해제

#include <iostream>

using namespace std;

int main()
{
	// 정적으로 할당하는 것들은 stack에 할당, 동적은 heap
	//int array[1000000];	// error!! Stack overflow 

	//int var;
	//var = 7;
	int *ptr = new int(7);	// new int: int에 맞춰서 메모리를 받아오고, 그 주소를 알려줌
	//	   new int { 7 };
	*ptr = 7;

	cout << ptr << endl;
	cout << *ptr << endl;

	// 중요!! 할당받은 메모리를 다시 돌려 줌
	// OS가 메모리를 기억하고 있기 때문에 프로그램이 종료되면 자동으로 회수함
	// delete는 OS가 가져가기 전에 먼저 수동으로 반납하는 것임!
	delete ptr;
	ptr = NULL;	// 해제 후 NULL, 0, nullptr 넣어 주기

	// 삭제를 하더라도 주소는 그대로 남아 있음, 알고 있던 집으로 갔더니 다른 주소더라
	cout << "After delete" << endl;
	if(ptr != nullptr)
	{ 
		cout << ptr << endl;
		cout << *ptr << endl;
	}

	// 다른 프로그램이 모두 메모리를 사용하고 있어서 할당받지 못할 때가 있음
	// 프로그램이 죽지 않게 짜려면... std::nothrow => 오류를 발생시키지 않고 실행함
	int *ptr2 = new (std::nothrow) int{ 7 };

	if (ptr2)
	{
		cout << ptr2 << endl;
		cout << *ptr2 << endl;
	}
	else
	{
		cout << "Could not allocate memory" << endl;
	}


	int *ptr3 = ptr2;

	delete ptr2;
	ptr2 = nullptr;
	ptr3 = nullptr;	// ptr3 해제하지 않고 *ptr3 접근하면 오류 발생!!


	// memory leak 메모리 누수
	// 1. 할당하는 메모리가 큰 경우, 작업 관리자 확인
	// 2. debugger의 Diagnostic Tools 확인
	// new와 delete는 OS에 다녀와야 하기 때문에 느림 => 적게 사용하는 것이 좋음
	while (true)
	{
		int *ptr = new int;
		cout << ptr << endl;

		delete ptr;
	}
	

	return 0;
}

 

 

동적 할당 배열

Dynamically Allocating Arrays: run-time에 배열의 사이즈를 결정하고, 그때그때 OS에서 메모리를 받아오기 때문에 유동적으로 사용이 가능함

#include <iostream>

using namespace std;

int main()
{
	int length;
	cin >> length;

	//int array[length];
	int *array = new int[length]();	// 전부 0으로 초기화
	//			{11, 22, 33, 44, 55, 66}; // length를 6 미만으로 할 경우 error!

	array[0] = 1;
	array[1] = 2;

	for (int i = 0; i < length; i++)
	{
		cout << (uintptr_t)&array[i] << endl;
		cout << array[i] << endl;
	}

	delete[] array;


	int fixedArray[] = { 1,2,3,4,5 };	// compile-time
	int *array2 = new int[3]{ 1,2,3 };	// new int[]시 빌드 실패!

	// resizing, 직접적으로는 안 됨! 더 큰 메모리를 받은 다음 복사해서 옮기기
	// OS에 요청을 할 수 있음(될 수도 있고, 안 될 수도 있음)

	delete[] array2;

	return 0;
}

 

 

포인터와 const

#include <iostream>

using namespace std;

int main()
{
	const int value = 5;		// 변수가 const면
	const int *ptr = &value;	// 포인터도 const
	//*ptr = 6;	error!
	//value = 6;	error!

	cout << *ptr << endl;	// 출력은 문제없음


	int value2 = 5;
	const int *ptr2 = &value2;
	//*ptr2 = 6;	error!
	value2 = 6;

	cout << *ptr2 << endl;	// 출력은 문제없음


	int v1 = 5;
	const int *p = &v1;	// const int *: 가리키고 있는 주소에 있는 '데이터'를 바꾸지 않겠다!
	//*p = 10;	error!

	int v2 = 6;
	p = &v2;	// 가능! 


	int v3 = 5;
	int *const p2 = &v3;	// int *const: 가리키고 있는 '메모리 주소'를 바꾸지 않겠다!
	*p2 = 10;	// 가능!

	int v4 = 8;
	//p2 = &v4;	error!


	const int *const p3 = &value;	// 초기화 필요


	// 함수 parameter에서 종종 사용!
	int a = 5;
	const int *pt1 = &a;
	int *const pt2 = &a;		
	const int *const pt3 = &a;	

	return 0;
}

 

 

참조 변수 reference variable

변수의 별명처럼 사용할 수 있음

#include <iostream>

using namespace std;

//void doSomething(int &n)
void doSomething(const int &n)	// 값 변경 불가
{
	//n = 10;
	cout << "In doSomething " << n << endl;
	cout << "In doSomething " << &n << endl;
}

int main()
{
	int value = 5;
	const int y = 8;

	int *ptr = nullptr;
	ptr = &value;

	int &ref = value;	// 참조, ref = value처럼 작동함
	//int &r;		error! reference는 반드시 초기화되어야 함
	//int &r = 104;	error! 리터럴은 메모리 주소가 없음
	//int &r = y;	error! 
	const int &r = y;	// const는 const로 선언

	cout << ref << endl;

	ref = 10;

	cout << value << " " << ref << endl;	// 출력: 10 10

	cout << &value << endl;
	cout << &ref << endl;	// value와 동일한 주소
	cout << ptr << endl;
	cout << &ptr << endl;


	int value1 = 5;
	int value2 = 10;

	int &ref1 = value1;

	cout << ref1 << endl;

	ref1 = value2;

	cout << ref1 << endl;


	int n = 5;
	cout << n << endl;
	cout << &n << endl;

	// 포인터는 복사해서 넣어 주는 것, 레퍼런스를 쓰게 되면 아예 변수 자체가 넘어감
	// 주소조차도 복사할 필요가 없기 때문에 효율이 더 높음
	doSomething(n);
	cout << n << endl;



	return 0;
}
#include <iostream>

using namespace std;

void printElements(const int(&arr)[5])	// 이 경우, [5] 필수
{
	for (int i = 0; i < 5; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

struct Something
{
	int v1;
	float v2;
};

struct Other
{
	Something st;
};

int main()
{
	const int length = 5;
	int arr[length] = { 1,2,3,4,5 };

	printElements(arr);

	Other ot;
	//ot.st.v1 = 1;

	int &v1 = ot.st.v1;
	v1 = 1;


	int value = 5;
	// 기능상 동일함
	int *const ptr = &value;
	int &ref = value;

	*ptr = 10;
	ref = 10;


	return 0;
}

 

 

참조와 const

#include <iostream>

using namespace std;

void doSomething(const int& x)	// 장점: 복사X
{
	cout << x << endl;
}

int main()
{
	int a = 1;

	doSomething(a);
	doSomething(1);	// parameter가 const reference라면 가능!
	doSomething(a + 3);
	doSomething(3 * 4);


	return 0;
}

 

 

포인터와 참조의 멤버 선택

#include <iostream>

using namespace std;

struct Person
{
	int age;
	double weight;
};

int main()
{
	Person person;

	person.age = 5;		// member selection operator
	person.weight = 30;

	Person &ref = person;
	ref.age = 15;

	Person *ptr = &person;
	ptr->age = 25;
	(*ptr).age = 20;

	Person &ref2 = *ptr;
	ref2.age = 45;

	cout << &person << endl;
	cout << &ref2 << endl;	// 원본과 동일한 주소

	return 0;
}

 

 

C++11 For-each 반복문

#include <iostream>
#include <limits>
#include <algorithm>
#include <vector>

using namespace std;

int main()
{
	int fibonacci[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };

	// change array values? => 실패
	for (int number : fibonacci)
		number = 10;

	for (auto &number : fibonacci)	// reference
		number *= 10;

	// output
	for (const auto &number : fibonacci)
		cout << number << " ";
	cout << endl;


	// 가장 큰 숫자 찾기
	int max_number = numeric_limits<int>::lowest();

	for (const auto &n : fibonacci)
		max_number = max(max_number, n);

	cout << max_number << endl;
	

	// 동적 할당 array는 for-each 사용 불가능 => vector 사용!
	// 동적 할당 배열을 아주 편하게 사용할 수 있게 std에 들어 있음
	vector<int> fibonacci = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };

	return 0;
}

 

 

보이드 포인터

#include <iostream>

using namespace std;

enum Type
{
	INT,
	FLOAT,
	CHAR
};

int main()
{
	// void pointer, generic(포괄적) pointer

	int i = 5;
	float f = 3.0;
	char c = 'a';

	void *ptr = nullptr;

	// 주소 넣는 것은 문제 없음! 단, 그렇기 때문에 어떤 타입인지 알 수가 없어짐
	ptr = &i;
	ptr = &f;
	//ptr = &c;

	int *ptr_i = &i;

	cout << ptr_i << endl;
	cout << ptr_i + 1 << endl;

	cout << &f << " " << ptr << endl;	// '주소' 출력 가능
	//cout << *ptr << endl;		// error! 주소에 값이 있는 건 알겠지만, 어떤 형인지 알 수 없음!
	cout << *static_cast<float*>(ptr) << endl;

	//cout << ptr + 1 << endl;	// error! 대체 몇 바이트를 더해야 하는지 알 수 없음!


	// void pointer를 많이 사용하진 않겠지만... 포인터를 이해하는 데 도움이 됨
	Type type = FLOAT;
	if (type == FLOAT)
		cout << *static_cast<float*>(ptr) << endl;
	else if(type == INT)
		cout << *static_cast<int*>(ptr) << endl;

	return 0;
}

 

 

다중 포인터와 동적 다차원 배열

#include <iostream>

using namespace std;

int main()
{
	int *ptr = nullptr;
	int **ptrptr = nullptr;	// 이중 포인터, 포인터에 대한 포인터, 원래 데이터 타입은 integer

	int value = 5;

	ptr = &value;
	ptrptr = &ptr;

	cout << ptr << " " << *ptr << " " << &ptr << endl;
	cout << ptrptr << " " << *ptrptr << " " << &ptrptr << endl;
	cout << **ptrptr << endl;
	cout << endl;


	const int row = 3;
	const int col = 5;

	const int s2da[][5] = 
	{
		{1, 2, 3, 4, 5},
		{6, 7, 8, 9, 10},
		{11, 12, 13, 14, 15}
	};

	/*
	int *r1 = new int[col] { 1, 2, 3, 4, 5 };
	int *r2 = new int[col] { 6, 7, 8, 9, 10 };
	int *r3 = new int[col] { 11, 12, 13, 14, 15 };

	int **rows = new int*[row] {r1, r2, r3};

	for (int r = 0; r < row; r++) {
		for (int c = 0; c < col; c++)
			cout << rows[r][c] << "\t";
		cout << endl;
	}

	delete[] r1;
	delete[] r2;
	delete[] r3;
	delete[] rows;
	*/

	int **matrix = new int*[row];

	for (int r = 0; r < row; r++)
		matrix[r] = new int[col];


	for (int r = 0; r < row; r++)
		for (int c = 0; c < col; c++)
			matrix[r][c] = s2da[r][c];

	// print all elements
	for (int r = 0; r < row; r++) {
		for (int c = 0; c < col; c++)
			cout << matrix[r][c] << "\t";
		cout << endl;
	}

	// delete
	for (int r = 0; r < row; r++)
		delete[] matrix[r];

	delete matrix;
	cout << endl;


	int *matrix2 = new int[row*col];

	for (int r = 0; r < row; r++)
		for (int c = 0; c < col; c++)
			matrix2[c + col * r] = s2da[r][c];

	for (int r = 0; r < row; r++) {
		for (int c = 0; c < col; c++)
			cout << matrix2[c + col * r] << "\t";
		cout << endl;
	}

	delete[] matrix2;


	return 0;
}

 

 

std::array 소개

#include <iostream>
#include <array>
#include <algorithm>

using namespace std;

void printLength(const array<int, 5>& my_arr)
{
	// 똑같이 작동 가능하나, array 또한 복사되어 작동함! (& 이용)
	cout << my_arr.size() << endl;	
}

int main()
{
	//int array[5] = { 1, 2, 3, 4, 5 };
	array<int, 5> my_arr = { 1, 2, 3, 4, 5 };	// 선언 시, 숫자가 꼭 들어가야 함
	my_arr = { 0, 1, 2 };	// 가능

	cout << my_arr[0] << endl;
	cout << my_arr.at(0) << endl;	// 똑같이 출력하나, 검색 후 문제 발생시 예외 처리!
	cout << my_arr.size() << endl;
	printLength(my_arr);
	cout << endl;

	array<int, 5> arr2 = { 1,21,3,40,5 };

	for (auto &element : arr2)
		cout << element << " ";
	cout << endl;

	sort(arr2.begin(), arr2.end());

	for (auto &element : arr2)
		cout << element << " ";
	cout << endl;

	sort(arr2.rbegin(), arr2.rend());

	for (auto &element : arr2)
		cout << element << " ";
	cout << endl;


	return 0;
}

 

 

std::vector 소개

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	//std::array<int, 5> array;
	std::vector<int> array;

	std::vector<int> array2 = { 1,2,3,4,5 };
	std::vector<int> array3 = { 1,2,3 };
	std::vector<int> array4 { 1,2,3 };

	cout << array2.size() << endl;
	cout << array3.size() << endl;
	cout << array4.size() << endl;

	array2.resize(10);	// resize 가능

	for (auto &itr : array2)
		cout << itr;
	cout << endl;

	cout << array2[1] << endl;
	cout << array2.at(1) << endl;
	cout << array2.size() << endl;	// size

	int *my_arr = new int[5];
	delete[] my_arr;	// 꼭 지워야 한다는 부담이 있음
	// vector는 블럭을 나가면 사라짐!! 아주 큰 장점


	return 0;
}

 

 

해당 포스트는 '홍정모의 따라하며 배우는 C++' 강의를 수강하며 개인 백업용으로 메모하였습니다.

인프런: https://www.inflearn.com/course/following-c-plus

 

홍정모의 따라하며 배우는 C++ - 인프런

만약 C++를 쉽게 배울 수 있다면 배우지 않을 이유가 있을까요? 성공한 프로그래머로써의 경력을 꿈꾸지만 지금은 당장 하루하루 마음이 초조할 뿐인 입문자 분들을 돕기 위해 친절하고 자세하게 설명해드리는 강의입니다. 초보로 시작하더라도 중급을 넘어 고급 프로그래머로 가는 길목에 들어서고 싶으시다면 최고의 디딤돌이 되어드리겠습니다. 여러분의 꿈을 응원합니다! 초급 프로그래밍 언어 C++ 온라인 강의 C++

www.inflearn.com

반응형
복사했습니다!