정적배열에선 std::array를 사용가능하다. 

기존 정적배열은 함수 파라미터로 배열을 보내면 사이즈를 측정할 수 없었다.

array를 사용하면 정적배열을 간단히 사용할 수 있다.
.size()를 사용하면 사이즈가 출력된다.
파라미터로 복사되어도 그대로 출력된다.
파라미터는 복사되기때문에 array가 크기가 크면 reference &를 사용하는게 좋다.

.at()을 사용하면 사이즈오버를 미리 체크해준다.

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

using namespace std;

void arrCheck(const array<int, 5> arr) {
	cout << &arr << endl;
	for (int i = 0; i < arr.size(); i++) {
		cout << arr[i] << endl;
		cout << arr.at(i) << endl;
	}
}

void arrRefCheck(const array<int,5> &arr) {
	cout << &arr << endl;
	for (int i = 0; i < arr.size(); i++) {
		cout << arr[i] << endl;
		cout << arr.at(i) << endl;
	}
}

int main()
{
	//int array2[5] = {};

	array<int, 5> arr = {1,10,3,7,5};
	cout << "arrSize() : " << arr.size() << endl;
	cout <<"main() : "<< &arr << endl;
	arrCheck(arr);
	arrRefCheck(arr);

	//sort
	std::sort(arr.begin(), arr.end());
	arrCheck(arr);
	arrRefCheck(arr);

	//sort 역순
	std::sort(arr.rbegin(), arr.rend());
	arrCheck(arr);
	arrRefCheck(arr);

	return 0;
}



std::vector는 동적 array를 대체해서 손쉽게 사용가능하다.
std::vector는 동적할당이 되기때문에 처음부터 사이즈를 정해주지 않아도 된다.

std::array와 같이 .size(),.at()이 사용가능 하다.
동적할당이므로 .resize()로 크기를 변경할 수 있다.

동적할당은 delete를 해야하는데 vector은 자동으로 사라진다.

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	std::vector<int> array;
	
	std::vector<int> array2 = { 1,2,3,4,5 };
	cout << array2.size() << endl;

	vector<int> arr = { 1,2,3,4 };
	for (auto &a : arr) {
		cout << a << endl;
	}

	return 0;
}



포인터도 변수다 그러므로 메모리주소를 가지고 있다.

즉, 변수이기에 포인터에대한 포인터를 생성할 수 있다.

2중포인터 기본개념

 

int **ptr은 int *(*ptr)로 이해할 수 있다.
즉, *ptr이 가지고 있는 주소값을 또 포인터로 보게하는 것이다.

 

2중포인터 예

ptr은 int val의 주소값을 가진다.

int val = 5;
int *ptr = &val;

ptrptr은 ptr(val주소값을 가지고있는 포인터)의 주소값을 가진다.

int **ptrptr = &ptr;

de-reference도 가능하다.

cout << **ptrptr << endl;

 

동적 메모리 할당을 이용해 다차원배열 생성

 

동적 메모리 할당을 이용해 다차원배열생성을 알아보기전에

배열과 포인터는 같다는걸 잊지말자!


2차원 배열을 동적할당으로 생성한다고 보면 우선 포인터 3개를 생성한다.

int *(*rows) = new int *[3]; 
//포인터 찍어본결과 임의의 주소값이 들어있다. 


그다음 for문으로 포인터에 접근해 포인터에 배열을 선언해준다.

for (int i = 0; i < 3; i++) {
	rows[i] = new int[5]{};
}

아래 배열과 비슷하게 생성된다.

int rows[3][5] = {};


비슷하다고한 이유는?

메모리주소 형식이 다르다.
위에 선언된 정적2차원배열은 메모리주소가 이어진다.

 

하지만 동적 메모리 할당을 이용하면 메모리 주소가 이어지지 않는다.
위에 말했듯이 포인터도 메모리 주소가 있다.
동적할당 3개를 받은 포인터에 

rows[i] = new int[5]{}; 


의 새로운 포인터주소를 정의해주면 주소가 이어지진않지만 2차원배열이 생성되는걸 알 수 있다.

 

즉, 동적할당된 3개의 포인터에 새로운 배열의 주소를 정의해준다.

 

동적할당은 사용한후 메모리를 반납하는걸 잊지말자!

for (int r = 0; r < row; r++) {
	delete[] rows[r];
}
delete[] rows;

 

#include <iostream>

using namespace std;

int main()
{
	int *ptr = nullptr;
	int **ptrptr = nullptr;

	int value = 5;
	//value의 주소 ptr포인터에 저장
	ptr = &value;
	//ptr포인터의 주소 ptrptr포인터에 저장
	ptrptr = &ptr;

	cout << "==============================================" << endl;
	cout << "다중 포인터 기본예" << endl;
	cout << "value의 주소값 : " << &value << endl;
	cout << endl;

	cout << "ptr포인터의 자신의 주소값 : " << &ptr << endl;
	cout << "ptr포인터에 저장된 주소값 : " << ptr << endl;
	cout << "ptr포인터 de-reference : " << *ptr << endl;

	cout << endl;
	cout << "ptrptr포인터의 자신의 주소값 : " << &ptrptr << endl;
	cout << "ptrptr포인터에 저장된 주소값 : " << ptrptr << endl;
	cout << "ptrptr포인터 de-reference(ptr이 가지고있는 주소) : " << *ptrptr << endl;
	cout << "ptrptr포인터의 double de-reference : " << **ptrptr << endl;
	cout << endl;

	//배열과 포인터는 같다.
	int a[3] = { 1,2,3 };
	int *aa = a;
	cout << "==============================================" << endl;
	cout << "배열과 포인터 비교" << endl;
	cout << "==============================================" << endl;
	cout << "a[3]" << endl;
	for (int i = 0; i < 3; i++) {
		cout << "\t배열안의 값 a : " << a[i] << endl;
		cout << "\t배열의 주소 &a : " << &a[i] << endl;
		//cout << *ptrTest[i] << endl;
	}
	cout << "==============================================" << endl;
	cout << "*aa" << endl;
	for (int i = 0; i < 3; i++) {
		cout << "\t배열안의 값 aa : " << aa[i] << endl;
		cout << "\t배열의 주소 &aa : " << &aa[i] << endl;
		//cout << *ptrTest[i] << endl;
	}
	cout << "==============================================" << endl;

	cout << "1차배열 동적할당" << endl;
	cout << "*ptrTest = new int [3]" << endl;
	int *ptrTest = new int [3];
	for (int i = 0; i < 3; i++) {
		cout << "\t배열안의 주소 &ptrTest[i] : " << &ptrTest[i] << endl;
		cout << "\t배열안의 값 ptrTest[i] : " << ptrTest[i] << endl;
		ptrTest[i] = 3;
		cout << "\t배열안의 값 ptrTest[i] : " << ptrTest[i] << endl;
		//cout << *ptrTest[i] << endl;
	}
	cout << "==============================================" << endl;
	cout << "2차배열 동적할당" << endl;
	cout << "int *(*ptrTest2) = new int *[3]" << endl;
	
	int *(*ptrTest2) = new int *[3];
	cout << "ptrTest2 : " << ptrTest2 << endl;
	for (int i = 0; i < 3; i++) {
		cout << "\t배열안의 주소 &ptrTest2[i] : " << &ptrTest2[i] << endl;
		cout << "\t배열 동작할당 전 ptrTest2[i]: " << ptrTest2[i] << endl;
		//에러가난다
		//cout << "\t배열 동작할당 후 *ptrTest2[i]: " << *ptrTest2[i] << endl;
		//cout << *ptrTest2[i] << endl;
		ptrTest2[i] = new int[5]{};
		cout << "\t배열 동작할당 후 ptrTest2[i]: " << ptrTest2[i] << endl;
		cout << "\t배열 동작할당 후 *ptrTest2[i]: " << *ptrTest2[i] << endl;
	}
	cout << "==============================================" << endl;
	
	const int row = 3;
	const int col = 5;

	int (*arr2)[col] = new int [row][col];
	for (int i = 0; i < row; i++) {
		cout << "상수로 동적할당" << endl;
		cout << &arr2[i] << endl;
		for (int s = 0; s < col; s++) {
			cout << &arr2[i][s] << endl;
		}
	}
	cout << "==============================================" << endl;
	int **arr3 = new int *[row];
	for (int i = 0; i < row; i++) {
		cout << "다중포인터 주소" << endl;
		cout << &arr3[i] << endl;
	}
	cout << "==============================================" << endl;
	for (int i = 0; i < row; i++) {
		cout << "다중포인터 생성" << endl;
		arr3[i] = new int[5]{};
		for (int s = 0; s < col; s++) {
			cout << &arr3[i][s] << endl;
		}

	}
	cout << "==============================================" << endl;
	int arr[row][col] = 
	{ 
	{1,2,3,4,5},
	{},
	{} 
	};
	
	int *(*rows) = new int *[row];
	cout << "rows에 저장된 주소값 : " << rows << endl;
	cout << " *de-reference : " << *rows << endl;
	cout << "&포인터의 주소값 : " << &rows << endl;
	cout << endl;

	
	//초기화
	for (int r = 0; r < row; r++) {
		rows[r] = new int[col];
		cout << "초기화" << endl;
		cout << "&rows[" << r << "] : " << &rows[r] << endl;
		cout << "rows[" << r << "] : " << rows[r] << endl;
		int *a = &rows[r][0];
		cout << "a : " << a << endl;
		cout << "rows[" << r << "][0] : " << rows[r][0] << endl;

	}
	cout << endl;

	cout << "*de-reference : " << *rows << endl;
	cout << "**de-reference : " << **rows << endl;
	cout << "pointer : " << rows << endl;
	cout << endl;

	for (int r = 0; r < row; r++) {
		cout << "&rows["<< r <<"] : " << &rows[r] << endl;
		
		cout << endl;
		for (int i = 0; i < col; i++) {
			rows[r][i] = arr[r][i];
			cout << "&rows[" << r << "]["<< i <<"]" << &rows[r][i] << endl;
			cout << "rows[" << r << "][" << i << "]" << rows[r][i] << endl;
		}

		cout << "===================================" << endl;
	}
	//메모리 제거
	for (int r = 0; r < row; r++) {
		delete[] rows[r];
	}
	delete[] rows;

	//다중배열 사용하지 않기
	int *arrx2 = new int[row*col];
	for (int r = 0; r < row; r++) {
		for (int i = 0; i < col; i++) {
			cout << " i + col * r : " << i + col * r << endl;
			arrx2[i + col * r] = arr[r][i];
		}
	}

	
	for (int r = 0; r < row; r++) {
		for (int i = 0; i < col; i++) {
			cout << arrx2[i + col * r] << " ";
		}
		cout << endl;
	}

	delete[] arrx2;

	return 0;
}

포인터는 주소를 저장한다.

size에 상관없이 주소는 같다.
데이터 타입이 다르더라도 주소형식은 같다. 

자료형과 상관없이 포인터(주소값)저장할때 사용한다.

void pointer는 generic pointer 라고한다.

	void *ptr = nullptr;
	ptr = &i;



void pointer의 한계
*를 사용한 de-reference가 안된다.
자료형을 알 수 없어 +1연산이 안된다.

void포인터형에서 값을 알려면 casting을 해야한다.

	cout << *(static_cast<int*>(ptr)) << endl;


void포인터 사용이유
과거 다형성 구현할때 사용됬었다.

#include <iostream>

using namespace std;


enum Type {
	INT,
	FLOAT,
	CHAR,
};
int main()
{

	int i = 5;
	float f = 3.4f;
	char c = 'c';

	void *ptr = nullptr;

	ptr = &i;
	ptr = &f;
	ptr = &c;

	//자료형을 알 수 없어 연산할 수 없다.
	//cout << ptr + 1 << endl;
	ptr = &i;
	cout << *(static_cast<int*>(ptr)) << endl;
	
	return 0;
}

기존for문은 조건을  입력해주어햐한다.
for-each 반복문을 사용하면 반복문을 실행시킬때 훨씬 간단히 사용할 수 있다.

for-each조건문 사용하면 자료형만 알면 간단히 반복문을 작성할 수 있다.(auto사용가능)

	for (int num : arr) {
		cout << num << endl;
	}


for-each로 array의 내용을 바꾸고 싶다면 &참조변수를 사용해야한다.

	for (int &num : arr) {
		num = 10;
	}


array를 동적할당하면 for-each를 사용 불가능하다.
vector벡터를 사용하면 가능하다.
vector는 동적할당 배열을 사용하기 쉽도록 std안에 들어가 있는것이다.

	vector<int> arr2 = { 1,2,3,4,5,6,7 };
	for (int num : arr2) {
		cout << num << endl;
	}

for-each문은 가시적으로 보기도 좋다.

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	for (int num : arr) {
		cout << num << endl;
	}

	//값 변경하기
	for (int &num : arr) {
		num = 10;
	}
	//10으로 변경됬는지 확인
	for (int num : arr) {
		cout << num << endl;
	}
	
	vector<int> arr2 = { 1,2,3,4,5,6,7 };
	for (int num : arr2) {
		cout << num << endl;
	}


	return 0;
}

 

포인터와 참조를 통해 구조체나 클래스의 멤버에 접근할 수 있다.

포인터는 ->를 사용하여 멤버에 접근한다.
(*포인터명)으로 접근할 수 있으나 잘 사용하지 않는다.

	Person *ptr = &person;
	ptr->age = 30;
	(*ptr).age = 40;


참조는 기존 구조체,클래스와 같이 사용할 수 있다.
참조변수명.멤버 형식으로 사용가능하다.

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


참조에 포인터를 de-reference해서 값을 넣어줄 수 있다.

	Person ref2 = *ptr;
	ref2.age = 50;

포인터,참조사용 멤버접근 cout찍어보기

#include <iostream>

using namespace std;

struct Person {
	int age;
	double weight;
};

int main()
{
	Person person;
	cout << "addr : " << &person << endl;
	//멤버 선택 연산자
	person.age = 10;
	

	//참조 주소값 가져오기
	Person &ref = person;
	ref.age = 20;
	cout << "addr ref : " << &ref << endl;

	Person *ptr = &person;
	cout << "addr &ptr : " << &ptr << endl;
	cout << "addr ptr : " << ptr << endl;
	ptr->age = 30;
	//()를 꼭 해줘야한다.
	(*ptr).age = 40;

	Person ref2 = *ptr;
	cout << "addr ref2 : " << &ref2 << endl;
	ref2.age = 50;

	return 0;
}

참조변수 Reference variable

꼭 포인터를 사용하여 * 사용하지 않고 참조변수 &를 사용할 수 있다.

참조변수는 참조하고 있는 변수의 주소를 공유한다.
즉, 참조는 변수의 또다른 별명처럼 사용할 수 있다.
참조변수는 반드시 초기화를 해야한다(리터럴은 불가능).

함수에서도 참조변수(reference)를 활용할 수 있다.
파라미터를 복사를 할 필요가 없어 빠르다.
또 주소를 전송하기에 함수에서 값을 변경할 수 있다.

#include <iostream>

using namespace std;

void doSomething(int &n)
{
	n = 10;
	cout << "In doSomething : " << n << endl;
	cout << "In doSomething : " << &n << endl;
}
void doSomethingPointer(int *n)
{
	*n = 10;
	cout << "In doSomethingPointer : " << n << endl;
	cout << "In doSomethingPointer : " << &n << endl;
}

struct SubA {
	int v1;

};

struct A {
	int v1;
	SubA subA;
};

int main()
{

	A a;
	a.subA.v1 = 3;
	cout << a.subA.v1 << endl;
	//구조체에서 참조를 활용할 수 있다.
	int &v1 = a.subA.v1;
	v1 = 4;
	cout << a.subA.v1 << endl;


	int val = 5;
	//파라미터로 int자료형을 보내면 복사가 된다.
	doSomething(val);
	cout << val << endl;
	cout << &val << endl;

	//파라미터로 참조변수를 보내면 복사가 되지 않는다.
	//즉, 값이 변경 가능하다.
	doSomethingPointer(&val);
	cout << val << endl;
	cout << &val << endl;

	//포인터에서 참조변수를 사용가능하다.
	int *ptr = nullptr;
	ptr = &val;

	//참조 
	int &ref = val;

	ref = 10;
	cout << ref << endl;
	cout << val << endl;

	//const활용
	const int val2 = 3;
	//불가능하다.
	//int &ref2 = &val2;
	const int &ref2 = val2; 

	return 0;
}

함수에 파라미터로 const 참조변수를 사용하면 편해진다.

그냥 참조변수에 대입하는 값은 L_Value만 가능하다.

const를 사용하면 L_Value만 아닌 연산도 가능해진다.

 

#include <iostream>

using namespace std;

//참조변수
void doSomething(const int &const a) {
	cout << &a << endl;
	cout << a << endl;
}


//포인터
void doSomething2(const int *const a) {
	cout << a << endl;
	cout << *a << endl;
}


int main()
{
	int val = 5;
	
	const int &ref = val;
	int &ref2 = val;

	//포인터,참조변수 두개의 차이

	//그냥 참조변수는 L_Value만 가능하다.
	//int &ref3_1 = 3 + 4;
	const int &ref3 = 3 + 4;
	cout << ref3 << endl;
	cout << &ref3 << endl;

	doSomething(val);
	//ref3의 주소값이 인자가 된다.
	doSomething(ref3);
	doSomething(1 + 3);

	//메모리주소,연산전송이 안된다.
	doSomething2(&val);
	//doSomething2(ref3);
	//doSomething2(1 + 3);
	return 0;
}

 

동적 할당 배열 Dynamically Allocation Arrays

동적 할당 배열은 메모리를 나중에 할당 받을 수 있다.
배열에 들어갈 값을 미리 정해놓을 수 있지만 할당받을 크기보다 크다면 에러가 난다.

동적 할당 배열 반납방법 :  delete[]

#include <iostream>

using namespace std;

int main()
{
	//정적 할당 배열은 컴파일될때 배열의 크기가 고정되어야한다.
	const int length = 5;
	//정적 할당 배열
	int arr[length] = { 1,2,3,4,5 };
	
	int dlen;
	cin >> dlen;

	//동적 할당 배열 받기
	int *ptrArr = new int[dlen];

	for (int i = 0; i < dlen; i++) {
		cout << "i : " << i << endl;
		ptrArr[i] = i;
		cout << (uintptr_t)&ptrArr[i] << endl;
		cout << ptrArr[i] << endl;
	}

	delete[] ptrArr;
	ptrArr = nullptr;

	return 0;
}

포인터에도 const를 사용할 수 있다.

 

const의 위치마다 결과가 다르다.


주소에 접근해 데이터를 변경할 수 없다.

const int *ptr = &value; 


메모리 주소를 변경할 수 없다.

int *const ptr = &value; 


메모리주소,주소안의 데이터를 모두 변경할 수 없다.

const int *const ptr = &value;

const활용 자세한 설명

#include <iostream>

using namespace std;

int main()
{

	int value = 5;
	

	const int *ptr2 = &value;
	cout << *ptr2 << endl;
	//역참조는 불가능하다.
	//포인터를 이용해 값을 변경하지 않겠다는 표현으로 생각할 수 있다.
	//*ptr = 6;


	int value2 = 3;
	//주소에 있는 값을 바꾸지 않겠다는 말이다.
	ptr2 = &value2;
	cout << *ptr2 << endl;
	//에러가난다.
	//*ptr2 = 6;

	//포인터 자체를 상수로 만들기
	int *const ptr = &value;
	//주소값을 변경할 수 없다.
	//ptr = &value2;

	//모든것이 변경 불가능하다.
	const int *const ptr3 = &value;
	return 0;
}

-정적배열을 선언할때 배열의 크기가 커지면 용량이 커진다 
-정적할당은 stack에 들어가고 동적할당은Heap에 들어간다. 

 

메모리 할당의 종류
정적메모리 할당 Static Memory Allocation
-전역변수,static변수 한번만들면 프로그램 종료시까지 유지된다.

자동메모리할당
-블록안에서 변수를 선언,정적배열 선언 블럭밖으로 나가면 메모리가 OS로 다시 할당된다.

동적메모리 할당 Dynamic Memory Allocation
동적 메모리 할당은 new로 할당받는다.
메모리를 할당받는것이기에 포인터로 받아야한다.
delete로 반납해주어야한다.
delete를 하더라도 메모리의 주소는 있기때문에 garbage값이 있다.

int *ptr = new int (8);


다른 프로그램이 메모리를 모두사용하고 메모리를 할당받지 못할때도있다.
- 프로그램이 죽어버릴게 짜는 방법
- 다른 프로그램의 메모리 반납을 기다리는 방법
(std::nothrow)을 사용한다.메모리 할당이 실패하면 nullptr이 할당된다.

int *ptr = new (std::nothrow)int (8);



메모리누수 memory leak
동적메모리 할당을 사용할때 반납을 잊으면 메모리 누수가 발생한다.

#include <iostream>

using namespace std;

//정적메모리 할당
int a = 0;

int main()
{

	//자동메모리 할당
	{
		int array[10];
	}

	int *ptr = new (std::nothrow)int (8);
	cout << *ptr << endl;
	//ptr이 delete가 되면 ptr2도 메모리가 반납된다.
	int *ptr2 = ptr;

	//de-reference
	*ptr = 7;

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

	//delete로 메모리를 반납했기에 garvage값이 출력된다.
	//cout << *ptr << endl;
	//방지하는방법 0,NULL,nullptr을 사용한다.
	ptr = nullptr;
	if (ptr != nullptr) 
		cout << *ptr << endl;

	while (true) {
		//delete를 하면 메모리 누수memory leak이 발생한다.
		int *ptr = new int;
		cout << ptr << endl;
		delete ptr;
	}
	
	return 0;
}

포인터는 메모리의 주소를 저장하는 변수다.
포인터 연산을 하면 데이터 타입에 따라 주소를 옮겨준다.
즉, 실생활을 생각하면 지하철의 앞칸, 뒷칸의 열차번호는 현재열차번호를 알면 알 수 있다.

포인터 변수를 선언하고 변수에 연산 +1,-1해주면 앞뒤 주소를 알 수 있다.

	int val = 7;
	int *ptr = &val;

	//int형 앞뒤 주소를 알 수 있다.
	cout << uintptr_t(ptr) << endl;
	cout << uintptr_t(ptr + 1) << endl;
	cout << uintptr_t(ptr - 1) << endl;


포인터 연산으로 배열의 값과 주소를 똑같이 알아올 수 있다.
(uintptr_t)를 사용하면 16진수가 아닌 8진수로 출력된다.

cout << uintptr_t(ptr) << endl;

int형 char형 배열 포인터 연산

#include <iostream>

using namespace std;

int main()
{
	int val = 7;
	int *ptr = &val;

	cout << uintptr_t(ptr) << endl;
	cout << uintptr_t(ptr + 1) << endl;
	cout << uintptr_t(ptr - 1) << endl;

	int arr[] = { 9,7,5,3,1 };

	int *ptrArr = arr;

	for (int i = 0; i < 5; i++) {
		cout << arr[i] << " addr : " << (uintptr_t)&arr[i] << endl;
		cout << *(ptrArr + i) << " addr : " << (uintptr_t)(ptrArr + i) << endl;
	}

	char name[] = "Choi";

	const int n_name = sizeof(name) / sizeof(name[0]);
	cout << "n_name : " << n_name << endl;

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

	return 0;
}

배열문자열
char배열로 문자열을 저장할 수 있다.

char myStr[] = "string";

주의할점 : 마지막에 \0이 들어있다.
확인하는방법 : 아스키코드로 출력해보면 마지막에 0이 출력된다.

cout으로 출력하면 \0이 나타나면 출력이 멈춘다.

strcmp   : 문자열 비교할때 사용

strcpy_s : 문자열 복사할때 사용
strcat_s : 문자열 붙일때 사용

#include <iostream>
#include <cstring>

using namespace std;

int main()
{
	char myStr[] = "string";

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

	myStr[255];
	cin.getline(myStr, 255);
	cout << myStr << endl;

	myStr[0] = 'A';
	cout << myStr << endl;

	int i = 0;
	while (true)
	{
		if (myStr[i] == '\0') break;

		cout << myStr[i] << " code : " << (int)myStr[i] << endl;
		i++;
	}
	
	char cpy[255];
	//strcpy(cpy, myStr);
	char myStr2[] = "Test !";
	strcpy_s(cpy, 255, myStr2);

	//문자열이 같으면 0출력 틀리면 -1출력
	cout << strcmp(cpy, myStr2) << endl;
	
	//문자열 붙이기
	strcat_s(cpy, myStr2);
	cout << cpy << endl;

	return 0;
}

문자열 심볼릭 상수

 

문자열은 기본적으로 문자의 배열이다.
배열은 포인터와 호환이 된다.

컴파일러가 헷갈리게 하는 부분을 조심하자.

심볼릭 상수는 그냥 특별하게 생각하자.

기호적인 상수로 선언할때 같은 문자열이라면 여러개 생성하지않고 같은 주소를 바라본다.

#include <iostream>

using namespace std;

int main()
{
	char a[] = "Jack Jack";
	//"Jack Jack"은 리터럴이다.
	//포인터는 메모리의 주소만 가르킨다.
	//메모리를 만들것인가 하는 정보가 없다.
	//char *name = "Jack Jack";

	//기호적인 상수처럼 사용할 수 있다.
	const char *name = "Jack Jack";
	const char *name2 = "Jack Jack";

	//컴파일러가 리터럴이 같을 경우 같이 메모리를 사용하게한다.
	cout << (uintptr_t)name << endl;
	cout << (uintptr_t)name2 << endl;
	cout << &name << endl;
	cout << &name2 << endl;

	int int_arr[5] = { 0 };
	char ch[] = "char";
	const char *ch2 = "char2";

	//cout에서 문자열은 특별히 처리한다.
	cout << int_arr << endl;
	cout << ch << endl;
	cout << ch2 << endl;

	char s = 's';
	cout << &s << endl;

	return 0;
}

+ Recent posts