배움 저장소
[홍정모의 따라하며 배우는 C++] 6. 행렬, 문자열, 포인터, 참조 본문
6.1 배열 기초 [1 of 2] array
배열 이름 뒤에 붙는 [ ]는 deferencing이다. 배열의 자료형 크기 * 해당 index 자리에 있는 값을 읽는다
c++11은 배열의 uniform initialization을 지원한다.
int arr[]{ 1, 2, 3, 4, 5 };
배열의 Index에 Enum 열거형을 사용할 수 있다
- 열거형의 마지막 변수를 COUNT로 쓰면 편리하다.
enum StudentName
{
JACK,
ALI,
VIOLET,
NUM_STUDENT,
};
int main()
{
// c++ 11 allow array's uniform initialization
int arr[NUM_STUDENT]{ 0, 1, 2 };
arr[JACK];
arr[ALI];
arr[VIOLET];
}
배열의 크기는 Compile time에 결정되어야 한다
- 배열의 크기는 runtime constant로 정할 수 없다. 따라서 배열의 정의도 Compile time에 결정되어야 한다.
const int count = 5;
int student_count[count];
배열을 함수의 Parameter로 지정하여도 내부적으로는 포인터로 변환하여 사용한다
참고) - 10.7 배열을 함수에게 전달해주는 방법 https://hoplite.tistory.com/75
홍정모의 따라하며 배우는 C언어 10.배열과 포인터
10.1 배열과 메모리 - 배열의 인덱스는 (해당 값의 주소 - 첫 값의 주소) / sizeof(자료형)과 같다 - 배열의 이름은 첫 값의 주소를 가리킨다. 따라서 Ampersand(주소 연산자) 없이도 포인터에 할당할 수
hoplite.tistory.com
6.3 배열과 반복문
6.4 배열과 선택 정렬 selection sort
Selection Sort
void printArray(const int arr[], const int length)
{
for (int i = 0; i < length; ++i)
cout << arr[i] << " ";
cout << endl;
}
int main()
{
const int length = 5;
int arr[length] = { 3, 5, 2, 1, 4 };
printArray(arr, 5);
for (int i = 0; i < length-1; ++i)
{
int min_i = i;
for (int j = i+1; j < length; ++j)
{
if (arr[j] < arr[min_i])
min_i = j;
}
int temp = arr[min_i];
arr[min_i] = arr[i];
arr[i] = temp;
}
printArray(arr, 5);
}
Bubble Sort
void printArray(const int arr[], const int length)
{
for (int i = 0; i < length; ++i)
cout << arr[i] << " ";
cout << endl;
}
int main()
{
const int length = 7;
int arr[length] = { 64, 34, 25, 12, 22, 11, 90 };
printArray(arr, length);
for (int end = length; 0 <= end; --end)
{
bool isSorted = true;
for (int i = 0; i < end-1; ++i)
{
if (arr[i] > arr[i + 1])
{
int temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
isSorted = false;
}
}
if(isSorted) break;
}
printArray(arr, length);
}
6.5 정적 다차원 배열
6.6 C언어 스타일의 배열 문자열
참고 https://hoplite.tistory.com/76
홍정모의 따라하며 배우는 C언어 11 문자열 함수
11.1 문자열을 정의하는 방법 'H' 'e' 'l' 'l' 'o' '\0' ? ? ? 특정 컴파일러는 비어있는 공간을 '\0'으로 채워준다. Put( ) 함수의 활용법 #define MESSAGE "A Symbolic string constant" #define MAXLENGTH 81 p..
hoplite.tistory.com
cin >> 을 사용하면 space, enter 직전까지 값을 받아들이고 나머지는 buffer에 저장한다
cin.getline( )를 이용하여 enter(next line)까지 값을 입력받아보자.
#include <iostream>
using namespace std;
int main()
{
char str[255];
cin.getline(str, 255);
cout << str << endl;
}
C스타일 문자배열 함수를 사용하려면 <cstring>라이브러리를 포함하자.
- strcpy함수는 depreciated(오래되어 사용하지 않는다). 복사하려는 저장공간이 부족할 때 에러를 만든다.
- 참고) "11.5 ~11.6", "11.11" https://hoplite.tistory.com/76
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char source[] = "Copy this!";
char desti[50];
//strcpy(desti, source);
strcpy_s(desti, static_cast<size_t>(50), source);
cout << desti << endl;
}
6.7 포인터의 기본적인 사용법
같은 자료형이라면 여러 변수를 선언/초기화할 수 있지만 포인터는 예외이다
- 자료형은 생략가능하지만 매 변수 앞에 Asterisk(*)를 붙여주어야 한다.
- typedef를 사용하면 이러한 수고를 덜 수 있다. 2중/3중 포인터를 만들 때 자주 사용한다.
#include <iostream>
using namespace std;
int main()
{
int x;
//int* ptr_1 = &x, ptr_2 = &x; // Error!, ptr_2 needs asterisk
typedef int* int_ptr_t;
int_ptr_t ptr1 = &x, ptr_2 = &x;
}
포인터에 자료형이 필요한 이유
- 주소 값 자체는 자료형을 구분하지 않으나 dereferencing을 했을 때 어떤 자료형으로 가져올지를 알아야한다.
- 배열을 가리키는 포인터를 사용하려면 각 element를 읽기 위해 자료형 크기를 알아야한다. 배열의 시작 주소값에서 자료형크기 * index 주소로 이동하여 해당 index 값을 가져온다.
6.7-2 널 포인터 Null Pointer
nullptr은 주소 0을 가리킨다.
int* ptr = nullptr;
cout << ptr << endl;
>> 00000000
nullptr은 여러 방식으로 초기화 할 수 있다. NULL과 0을 대신해서 쓰기도 한다
void checkPointer(double* ptr)
{
if (ptr == nullptr)
{
cout << "function \"" << __FUNCTION__ << "\" take nullptr!!" << endl;
return;
}
}
int main()
{
double *ptr = nullptr; // Modern C++ sytle
double* ptr2{nullptr};
double* ptr3(nullptr);
double *ptr_NULL = NULL;
double *ptr_ZERO = 0;
checkPointer(nullptr);
}
>> function "checkPointer" take nullptr!!
nullptr 자료형 사용하기 <cstddef>
- nullptr_t 자료형은 nullptr 값만 가지는 자료형이다. 자료형이 nullptr 값만 가지는 Parameter에 사용한다.
#include <cstddef>
using namespace std;
std::nullptr_t nptr;
6.8 포인터와 정적 배열
배열과 포인터는 주소값을 저장하고 있다
포인터 vs 배열
(1) sizeof( ) 출력값이 다르다
(2) pointer는 4byte로 크기가 고정되어 있다.
(3) array는 (해당 자료형 크기 * 배열의 크기) 값을 출력한다.
int main()
{
int arr[5] = {0, };
int* ptr = arr;
cout << sizeof(arr) << endl; // >> 20
cout << sizeof(ptr) << endl; // >> 4
}
함수의 Parameter로 전달된 배열은 Pointer로 변환된다
포인터의 활용: (*) Indirect를 사용하여 원본 값 변경하기
- C-style은 주소값에서 indirect하면 값을 변경할 수 있다. "Asterisk( * ) + 주소값" 형식으로 사용하면 된다.
- C++에서도 사용가능하나 Ampersand( & )를 더 많이 사용한다. 이후 강의에서 다룬다.
6.9 포인터 연산과 배열 인덱싱
16진수 주소값을 10진수로 변환하기
- int( ) 혹은 (int)을 사용하여 주소값을 10진수로 변형할 수 있다.
- uintptr_t( )을 사용해보자. uintptr_t는 포인터 크기만큼만(4byte) 주소값을 unsigned int로 변환하여 저장한다.
cout << uintptr_t(ptr) << endl;
참고) 10.3 포인터의 산술 연산( Pointer Arithmetic ) https://hoplite.tistory.com/75
홍정모의 따라하며 배우는 C언어 10.배열과 포인터
10.1 배열과 메모리 - 배열의 인덱스는 (해당 값의 주소 - 첫 값의 주소) / sizeof(자료형)과 같다 - 배열의 이름은 첫 값의 주소를 가리킨다. 따라서 Ampersand(주소 연산자) 없이도 포인터에 할당할 수
hoplite.tistory.com
Virtual Memory와 Physical Memory
(1) 프로그램의 실행을 process라 부른다. process는 서로 독립적인 virtual memory를 사용한다.
(2) memory는 virtual memory와 physical memory로 구분한다.
- physical memory(실제 DRAM 상의 메모리)이다.
- virtual memory는 프로그램상 표시되는 가상의 메모리로 physical memory를 이어붙여 연속적인 주소값을 만든다.
(3) physical memory와 virtual memory 사이에서 두 memory address를 translation을 해주는 page table이 존재한다.
(4) table이 virtual memory 와 physical memory 사이의 관계를 형성해주고 각 process 내에서는 서로 독립적인
virtual memory 공간을 만든다. 이 때문에 크기가 거대한 데이터를 연결해도 연속된 것처럼 나타난다.
6.10 C언어 스타일의 문자열 심볼릭 상수
참고) text segment: 11.2 메모리 레이아웃과 문자열 - https://hoplite.tistory.com/76
C는 string literal 주소값을 Pointer에 저장할 수 있다. C++은 이를 금지한다
- C에서 아래 예제를 실행시켜보자. C는 text segment에 접근할 수 있다.
// C
char *test = "is this work in C?";
printf("%s", test);
is this work in C?
아래 예제는 C++에서 실행하였다. C++는 text segment에 접근을 막아놓았다.
// C++
char* test = "is this work in C++?";
cout << test << endl;
const 상수로 지정해주면 text segment에 접근할 수 있다. 상수이므로 에러 발생을 예방해준다.
// C++
const char* test = "is this work in C++?";
cout << test << endl;
COUT이 문자열을 출력하는 방법
- cout은 다양한 자료형을 출력할 수 있다. 그 중에 문자열은 다른 자료형과 다른 방식으로 처리된다.
- 배열을 출력하면 주소값이 나와야 하지만 문자열은 null character('\n')를 만나기 전까지 값을 출력한다.
- 이는 string 자료형이 아닌 c-style 문자열에만 해당한다. c++ string은 null chracter를 가지고있지 않다.
int arr_i[5] = {0,};
char arr_char[] = "Hello there?";
const char* ptr = "is this work in C++?";
cout << arr_i << endl; // >> 00AFFC00
cout << arr_char << endl; // >> Hello there ?
cout << ptr << endl; // >> is this work in C++ ?
COUT이 자료형이 문자 주소일 때만 특별히 작동함을 확인해보자.
- 자료형이 문자 주소일 때 cout이 문자열을 출력함을 알 수 있다. null character('\0')까지 문자를 출력한다.
char test = 'A';
cout << &test << endl; // >> A儆儆윕쭄?
주소를 출력하고싶다면 형변환을 해보자
cout << static_cast<void*>(&test) << endl;
cout << (void*)(&test) << endl;
6.11 메모리 동적 할당 new와 delete
static memory allocation : 프로그램이 끝날 때까지 저장공간을 할당받는다.
automatic memory allocation : Scope 내부에서 저장공간을 할당받고 반환한다.
컴파일 타임에 얼마만큼 저장공간을 할당받을지 정해져 있다.
메모리 레이아웃에서 Stack을 활용한다. stack의 저장공간은 heap보다 작다.
Dynamic Memory allocation : 필요한 만큼의 저장공간을 힙에서 할당받는다.
컴파일 타임에 할당받을 저장공간이 정해져있지 않다.
Stack보다 많은 공간을 할당받을 수 있다.
참고 12.1 메모리레이아웃 - https://hoplite.tistory.com/78
메모리의 동적 할당 예제
int *ptr = new int{7};
cout << ptr << endl;
cout << *ptr << endl;
delete ptr;
ptr = nullptr;
- 프로그램이 종료되면 메모리를 해제해주지 않아도 자동으로 해제가 된다. OS가 할당된 메모리의 주소를 간직하고 있기 때문에 가능하다.
- Debug 모드에서 delete ptr이후에 ptr 값은 00008123이 입력된다. 디버그모드에서 메모리가 해제되었음을 가리키는 주소값이다.
메모리 해제가된 주소에서 값을 불러오면 쓰레기 값을 가져오거나 에러가 발생할 수 있다
- 동적할당 메모리를 사용할 때 항상 조건문으로 nullptr인지 확인해보자.
- smart pointer를 사용하면 간단하게 해결할 수 있다.
if (ptr != nullptr)
{
cout << ptr << endl;
cout << *ptr << endl;
}
동적 메모리 할당시 에러 무시하기
- 동적 메모리할당에 실패하면 에러가 발생하며 프로그램이 종료된다. 이를 원하지 않으면 std::nothrow를 활용하자
- std::nothrow를 활용하면 메모리 할당 실패시 에러를 발생시키지 않는다. ptr에 nullptr이 입력된다.
int *ptr = new (std::nothrow) int{7};
Memory Leak(메모리 누수)
- 아래 예제는 메모리 누수를 발생시킨다.
while (true)
{
int *ptr = new int;
}
- 아래 예제는 메모리 해제로 누수가 발생하지않는다.
while (true)
{
int *ptr = new int;
delete ptr;
}
6.12 동적 할당 배열
동적할당을 사용하면 런타임에 배열의 크기를 결정할 수 있다.
- 배열의 크기는 compile time에 결정되어야 하므로 배열은 항상 compile time에 정의되어야 했다. 동적할당은 가능하다
- 배열 메모리를 해제하려면 delete [ ] 를 사용하자.
int length;
cin >> length;
int *arr = new int[length];
for (int i = 0; i < length; ++i)
{
arr[i] = i;
cout << arr[i] << " " << &arr[i] << endl;
}
delete [] arr;
arr = nullptr;
arr포인터를 더이상 사용하지 않으면 nullptr값을 할당해주지 않아도 된다.
아래와 같이 동적배열을 할당하면 모든 값을 0으로 초기화한다
int *arr = new int[length]();
int *arr = new int[length]{};
uniform initialization을 사용하여 정한 값만큼 초기화할 수 있다
- 할당받은 저장공간보다 많은 값을 입력받으면 에러가 발생한다. 할당받지 않은 공간에 값을 저장했기 때문이다.
int *arr = new int[length]{ 10, 11, 12, 13 };
동적할당 메모리 크기 확인해보기
- "_msize( )" 함수를 사용하면 힙에서 할당받은 메모리 크기를 확인할 수 있다.
size_t _msize(void* _Block);
6.13 포인터와 const
포인터에 const keyword를 사용하여 주소값을 상수로 만들거나 해당주소에 저장된 값을 상수로 만들 수 있다.
- 참고) 10.15 포인터의 호환성-상수 keyword const활용 https://hoplite.tistory.com/75
int value =5;
const int *ptr1 = &value; // fix value
int *const ptr2 = &value; // fix address
const int *const ptr3 = &value;// fix both value and ad
6.14 참조 변수 reference variable
참조변수는 주소값을 다룰 수 있게 하는 연산자로 pointer보다 사용하기 쉽다
- 변수명 + Ampersand( & )를 사용하여 referenced 변수를 만들 수 있다
- 참조하는 변수의 별명으로 사용할 수 있다. 이름은 다르지만 같은 주소값을 가진다.
int value =5;
int *ptr = &value;
int &ref = value;
cout << "&value " << &value << endl; // >> &value 0073F8B0
cout << " &ptr " << &ptr << endl; // >> &ptr 0073F8A4
cout << " ptr " << ptr << endl; // >> ptr 0073F8B0
cout << " &ref " << &ref << endl; // >> &ref 0073F8B0
cout << " ref " << ref << endl; // >> ref 5
위 예제에서 &ref 값과 &value 값이 동일함을 확인할 수 있다.
reference 참조의 특징
(1) 참조 vs 포인터
- 포인터: 주소값을 저장하고 자기 자신은 별도의 주소를 가지고 있다
여러 레벨의 간접참조를 할 수 있다.
포인터연산, 널포인터가 필요할 때 사용한다
- 참조 : 참조하고 있는 변수의 주소값 자신의 주소값이 동일하다. (참조는 내부적으로 포인터로 구현되었다)
한 레밸의 간접참조만 할 수 있다.
매개변수와 리턴값으로 자주 쓰인다
(2) reference(참조)는 선언하여 사용할 수 없다. 반드시 초기화해야 한다. 초기화 이후 다른 값을 참조할 수 없다.
- 참조하고 있는 주소에서 값을 바꿀 수는 있지만 참조 되는 주소를 바꿀 수 없다.
int x = 10;
int y = 20;
int &ref1 = x;
cout << "x = " << x << " " << &x << endl; // >> x = 10 006FFE34
cout << "y = " << y << " " << &y << endl; // >> y = 20 006FFE28
cout << ref1 << " " << &ref1 << endl; // >> 10 006FFE34
ref1 = y;
cout << ref1 << " " << &ref1 << endl; // >> 20 006FFE34
&ref1 = y; // Error!
(3) R-value는 참조 변수의 값으로 사용할 수 없다.
int &ref = 123; // Error!
단 const(상수) reference는 R-value를 참조할 수 있다
- 이를 활용하면 함수의 argument에서 literal 값을 받을 수 있다. 6.15 참조와 const에서 다룬다
const int &ref = 123;
(4) reference variable은 참조하는 값이 상수이면 자기 자신도 상수여야 한다.
- 아래 예제를 보자 reference variable은 해당 값을 바꿀 수 있기 때문에 C++은 이 문법을 금지하고 있다
const int const_i = 10;
int &ref = const_i; // Error!
따라서 상수를 참조하려면 reference variable도 const로 지정해야 한다
const int const_i = 10;
const int &ref = const_i;
일반 변수를 상수로 참조할 수 있다
int const_i = 10;
const int& ref = const_i;
(5) reference variable은 null값을 가질 수 없다
함수의 Parameter에서 reference variable(참조변수) 활용하기
- 포인터는 저장공간을 할당받아 argument의 주소값을 복사한다. reference variable은 argument 주소값을 자신의 주소로 가져온다. 저장공간을 아끼고 속도도 더 빠르다.
void takeRefPara(int& x)
{
cout << __FUNCTION__ << " add = " << &x << endl; // >> main add = 005AF958
cout << __FUNCTION__ << " val = " << x << endl; // >> main val = 0
x = 10;
}
int main()
{
int x = 0;
cout << __FUNCTION__ << " add = " << &x << endl; // >> takeRefPara add = 005AF958
cout << __FUNCTION__ << " val = " << x << endl; // >> takeRefPara val = 0
takeRefPara(x);
}
함수의 배열 Parameter를 Reference variable(참조 변수)로 활용하기
- 아래 코드를 보자 int [5]배열을 대신사용할 수 있는 참조 변수이다. 매개변수로 활용한다.
int (&arr)[5]
void takeRefParaArr(int (&arr)[5])
{
for (int i = 0; i < 5; ++i)
cout << arr[i] << endl;
cout << endl;
}
int main()
{
const int length = 5;
int arr[length] = { 1, 2, 3, 4, 5 };
takeRefParaArr(arr);
}
복잡한 구성의 변수를 간단하게 부르는 예
- 아래 예제는 구조체 내부에 있는 구조체 멤버변수에 접근하기 위하여 dot( . ) operator를 여러번 활용하고 있음을 알 수 있다. 이 때 reference variable을 이용하면 원하는 멤버변수를 쉽게 사용할 수 있다.
struct Something
{
int v1;
float v2;
};
struct Other
{
Something sth;
};
int main()
{
Other one;
one.sth.v1 = 1;
}
reference variable을 이용해 쉽게 해당 값에 접근하였다
int &v1 = one.sth.v1;
v1 = 1;
6.15 참조와 const
const 참조 사용해보기
const int x = 5;
const int &ref_x = x;
const int &ref_ref = ref_x;
int y = 5;
const int& ref_y = y;
const int& ref_refy = ref_y;
함수가 const상수 reference variable을 parameter(매개변수)로 활용하면 literal(고정된) 값을 사용할 수 있다
- 일반 reference variable: L-value만 참조할 수 있다.
- const reference variable: L-value와 R-value 모두 참조할 수 있다.
const int &ref = 3+4; // Work!
int &ref = 3+4; // Error!
const reference variable이 없었다면 Argument에 임시값을 넣기 불가능하다
void takeRefPara(const int& x)
{
cout << x << endl;
}
int main()
{
int x = 3;
takeRefPara(x);
takeRefPara(3);
takeRefPara(x+3);
takeRefPara(x * 3);
}
6.16 포인터와 참조의 멤버 선택
포인터나 참조를 이용하여 특정 struct나 class의 멤버변수를 불러올 수 있다. 다음 예제를 보자.
struct Person
{
int age;
double weight;
};
int main()
{
Person person;
person.age = 10;
person.weight = 30;
Person &ref = person;
ref.age = 15;
ref.weight = 50;
Person *ptr = &person;
ptr->age = 20;
(*ptr).weight = 70;
Person &ref2 = *ptr;
ref2.age = 25;
ref2.weight = 80;
}
6.17 C++11 For-each 반복문
for 반복문을 간단하게 사용할 수 있는 for-each 반복문이다
- 동적할당으로 만든 배열에서 for-each 반복문을 사용할 수 없다. 정적 배열에서 사용가능하다.
int fibonacci[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
for(auto& num :fibonacci)
num *= 10;
for(const auto& num : fibonacci)
cout << num << " ";
cout << endl;
std:vector는 동적할당으로 저장공간을 받는다. 내부에 for-each를 사용할 수 있도록 구현되었다
std::vector<int> v_fibonacci = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
for(auto& num : v_fibonacci)
num *= 10;
for(const auto& num : v_fibonacci)
cout << num << " ";
cout << endl;
6.18 보이드 포인터
보이드 포인터는 generic 포인터라고도 부른다. 모든 주소값은 보이드 포인터로 저장할 수 있다
int i = 5;
float f = 3.0;
char c = 'a';
void *ptr = nullptr;
ptr = &i; // OK
ptr = &f; // OK
ptr = &c; // OK
보이드 포인터는 포인터 연산자를 사용할 수 없다. indirect되었을 때 자료형 크기를 확인할 수 없기 때문이다.
cout << ptr + 1 << endl; // Error!
dereference 연산도 불가능하다.
cout << *ptr << endl; // Error!
자료형이 정해지도록 casting을 하면 dereference 연산이 가능하다.
cout << *static_cast<char*>(ptr) << endl;
6.19 다중 포인터와 동적 다차원 배열
참고) 10.12 2중 포인터 작동원리 - https://hoplite.tistory.com/75
아래는 정적배열이다. 아래 배열을 동적으로 할당해보자
const int arr2d[row][col] ={
{1, 2, 3, 4, 5 },
{6, 7, 8, 9, 10},
{11, 12, 13, 14, 15}
};
(1) 더블포인터 -> 포인터배열 { 배열1 포인터, 배열2 포인터, ... }
- 모든 배열 포인터와 더블포인터를 해제해야하므로 번거롭다.
const int row = 3;
const int col = 5;
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] << " ";
cout << endl;
}
delete[] r1;
delete[] r2;
delete[] r3;
delete[] rows;
(2) for 반복문으로 더블포인터 -> 포인터배열 { 배열1 포인터, ... } 구현하기
const int row = 3;
const int col = 5;
// double pointer pointing to dynamic allocated
// memory that is for array of pointer
int** matrix = new int* [row];
// each pointer pointing to array of int
for (int r = 0; r < row; ++r)
matrix[r] = new int[col];
// assign value
for (int r = 0; r < row; ++r)
for (int c = 0; c < col; ++c)
matrix[r][c] = 10*r + c;
// print value
for (int r = 0; r < row; ++r)
{
for (int c = 0; c < col; ++c)
cout << matrix[r][c] << " ";
cout << endl;
}
// free dynamic allocated memory
// free each array of pointer's elem
for(int r=0; r<row; ++r)
delete[] matrix[r];
// after freeing every array
// freeing double pointer
delete[] matrix;
(3) 1차원 배열로 2차원 배열표현하기 포인터 -> 배열(배열의 크기는 행*열)
const int row = 3;
const int col = 5;
int* matrix = new int [row*col];
// assign value
for (int r = 0; r < row; ++r)
for (int c = 0; c < col; ++c)
matrix[r*col + c] = 10*r + c;
// print value
for (int r = 0; r < row; ++r)
{
for (int c = 0; c < col; ++c)
cout << matrix[r*col + c] << " ";
cout << endl;
}
// freeing pointer
delete[] matrix;
6.20 std::array 소개
std::array는 정적 배열을 클래스에 구현하였다. 여러가지 기능이 구현되어있다.
다음은 standard library Array를 사용하는 방법이다. <array>를 포함시키자
- array<자료형, 크기> 변수명으로 초기화한다. 초기화 이후에도 여러 값을 동시에 할당할 수 있어 편하다.
std::array<int, 5> arr = { 1, 2, 3, 4, 5 };
arr = { 10, 11, 12, };
멤버함수 size( ): array의 크기를 반환한다.
cout << arr.size() << endl;
멤버함수 at( index ): 해당 index의 저장공간에 접근가능한지 검사한다. 접근가능하면 값을 반환한다
접근 불가능하면 Exception을 발생시킨다. Error를 만드는 arr[ index ]와 다르다.
cout << arr[10] << endl; // Just Error!
cout << arr.at(10) << endl; // Make Exception
for-each 반복문을 활용할 수 있다
for(auto& i:arr)
cout << i << " ";
sort( ) 함수를 사용하여 원소를 크기에 따라 분류할 수 있다
- sort함수를 사용하려면 <algorithm>을 포함시켜 주자.
std::array<int, 5> arr = { 5, 2, 3, 1, 4 };
sort(arr.begin(), arr.end());
for(auto& i : arr)
cout << i << " ";
>> 1 2 3 4 5
위에서 begin - end의 순서를 역순으로 바꿀 수 있다.
sort(arr.rbegin(), arr.rend());
>> 5 4 3 2 1
함수의 Argument로 사용해도 개수 정보를 잃어버리지 않는다
void testArrayPara(const std::array<int, 5> &arr)
{
cout << "size = " << arr.size() << endl;
}
int main()
{
std::array<int, 5> arr = { 1, 2, 3, 4, 5 };
arr = { 10, 11, 12, };
testArrayPara(arr);
}
>> size = 5
6.21 std::vector 소개
std::vector는 동적배열을 대체하여 사용할 수 있다
vector는 메모리 해제를 자동으로 해준다. Scope 밖으로 나가면 메모리가 해제된다.
멤버함수 resize( )로 메모리 공간을 조절할 수 있다.
vector<int> v = {1,2,3,4,5};
v.resize(10);
for (const int& i : v)
cout << i << " ";
cout << endl;
>> 1 2 3 4 5 0 0 0 0 0
vector의 멤버함수 활용하기
vector<int> v = { 1, 2, 3, 4, 5 };
v = { 5 };
cout << v.size() << endl;
cout << v.at(0) << endl;
'Programming Language > C++' 카테고리의 다른 글
[홍정모의 따라하며 배우는 C++] 8. 객체지향의 기초 (0) | 2021.12.24 |
---|---|
[홍정모의 따라하며 배우는 C++] 7. 함수 (0) | 2021.12.23 |
[홍정모의 따라하며 배우는 C++] 5.흐름제어 (0) | 2021.12.17 |
[홍정모의 따라하며 배우는 C++] 4.변수 범위와 더 다양한 변수형 (0) | 2021.12.15 |
[홍정모의 따라하며 배우는 C++] 3. 연산자들 (0) | 2021.12.14 |