본문 바로가기

코딩/객체지향프로그래밍

[C++] 포인터, 벡터, 배열 (1)

출처: http://tcpschool.com/c/c_array_oneDimensional

 


 

1. 포인터 변수

  • &x : 변수 x의 메모리 상의 시작 주솟값을 반환
  • int* px : (int*)는 정수형 변수의 시작 주솟값을 저장하는 [포인터]라는 data type
  • *px: px라는 포인터 변수 선언 이후, px에 저장된 주솟값으로 jump, 참조 (px가 '가리키는' 변수로 jump, 참조)
  • px도 물론 포인터'변수'이기 때문에 메모리 공간을 차지하고, 따라서 시작 주솟값이 있음 !!
#include <iostream>
using namespace std;

int main() {
	int x = 10;
	int *px = &x; //포인터 변수에는 주솟값이 들어감

	cout << &x << " , " << x << endl; //x의 주솟값, 10 출력
	cout << px << " , " << *px << endl; //x의 주솟값, 10 출력

	return 0;
}

 

2. Pass by Pointer

  1. pass by value (int a = x; int b = y;) : a, b라는 지역 변수를 만들어 x, y 값을 단순히 복사하여 동작, swap함수를 써도 a와 b에만 값이 바뀌어 저장되는 거지, main공간의 xy 변수에는 값이 그대로이다.
  2. pass by reference (int &a = x; int &b = y;) : 변수 a, b의 주솟값이 x, y의 주솟값과 같아져 결국 동일한 메모리 공간을 가리킴, a는 x의 reference variable, 100% 동일한 별명과 이름 관계 (메모리 공간은 x, y 2칸 차지)
  3. pass by pointer (int *a = &x; int *b = &y;) : 포인터 변수 a, b에는 각각 x, y의 주솟값이 들어감, *a == x, *b == y,  * 참조를 통해 x, y를 '가리키는' 것이다. (메모리 공간은 a, b, x, y 4칸 차지)

→ 세 개의 pass를 구분해서 사용하는 경우: 주솟값은 모든 변수, 함수, 객체.. 가 다 가지는 것이다. 만약 객체의 크기가 매우 클 때 pass by value로 값을 보낸다면 그 엄청난 크기의 객체를 다 복사해야 하기 때문에 메모리 측면에서 비효율적이다(메모리를 너무 많이 잡아먹음). 이때 pass by ref.로 보낸다. 

 

→ pass by pointer는 함수를 또다른 함수의 입력으로 넣을 때 사용된다. (교수님 말씀에 따르면) pass by ref.를 잘 쓰고 pointer는 잘 안쓴다고 한다. 단, 간혹 함수에 전달할 인자가 주솟값인 특정한 경우에 사용한다 ! 

 

#include <iostream>
using namespace std;

void swap(int *a, int *b) {
	int temp = *a; 
	*a = *b;
	*b = temp;
}

int main() {
	int x = 10, y = 20;
	cout << x << " , " << y << endl; //10, 20
	swap(&x, &y);
	cout << x << " , " << y << endl; //20, 10

	return 0;
}

 

3. 함수 포인터

  • 포인터 변수는 함수의 시작 주솟값도 저장할 수 있다. (함수도 주솟값을 가지기 때문)
  • [출력 타입] (*함수 포인터 변수)(입력 타입, 입력 타입, ...) 호출 스타일 잘 기억하기 !!
#include <iostream>
using namespace std;

int sum(int a, int b) { return a + b; }
int mult(int a, int b) { return a * b; }
// 함수를 입력parameter로 받는 함수
int evaluate(int(*f)(int, int), int a, int b) {
	return f(a, b);
}

int main() {
	// (int, int)의 입력, int의 출력을 가진 함수포인터
	int(*func)(int, int); //함수의 주솟값 저장하는 함수 포인터(이름: func)

	func = &sum; //sum함수의 주솟값을 포인터변수 func에 저장
	cout << func(10, 20) << endl; //sum대신 func써도 무방
	//변수 가리키는 포인터로 참조할 때는 *쓰는데, 함수포인터는 * 안붙이고 그냥 사용!!

	func = &mult;
	cout << func(10, 20) << endl;

	cout << evaluate(&sum, 10, 20) << endl; //첫번째 입력 파라미타가 함수의 주솟값이므로
	cout << evaluate(&mult, 10, 20) << endl;

	return 0;
}

 

4. 벡터 basic

1. 벡터란?

  • C++에서 벡터란 메모리의 블럭을 관리하는 [객체]이다.
  • '값', '데이터'들의 모음 → 하나하나 보다는 여러 개를 관리함 (심지어 vector까지 vector안에 넣을 수 있음)
  • ex) string(문자열)도 char(문자)들을 일렬로 나열한 것이므로, '문자들의' vector라고 볼 수 있다! (string 각각의 element가 char이어야 함)
  • 블럭(block)안에 값을 순차적으로 저장한다. 이 때 저장된 값은 반드시 동일한 데이터 형(data type)을 가져야 한다! → homogeneous (homogeneity - 동종성)
  • 각 element(원소)마다 index가 존재한다. (C++은 zero-based indexing! 0부터 카운트 시작) → 벡터의 각 원소들은 0~크기-1 까지의 인덱스를 가진다.

2. 벡터의 선언

#include <vector>
using namespace std;

int main() {
	vector<int> v1; //vector<int> 까지가 v1의 data type
	vector<int> v2(10);
	vector<int> v3(10, 8);
	vector<int> v4{1, 2, 3, 4};
	vector<int> v5 = {1, 2, 3, 4, 5}; //v4와 동일한 표현
    
    return 0;
}
  • v1: vector<벡터에 저장할 데이터 타입> 벡터이름; → 벡터 이름과 저장할 데이터 타입만 선언
  • v2: (초기화 크기);  → 벡터 안에 저장할 데이터들의 개수, 사이즈까지 지정 (각 데이터들은 '0'으로 초기화 됨)
  • v3: (초기화 크기, 초기화 값);  → 벡터 안의 데이터 개수만큼 지정해준 값으로 초기화 됨
  • v4: {값1, 값2, 값3, 값4};  → 특정한 값으로 벡터를 지정해줌, 적어준 값 만큼 크기도 정해짐

 

5. 벡터 메소드 (벡터도 '객체'이므로!!)

#include <iostream>
#include <vector>
using namespace std;

int main() {
	vector<int> v{ 1, 2, 3, 4, 5 };
	v.push_back(6); //{1, 2, 3, 4, 5, 6}
	v.pop_back(); //{1, 2, 3, 4, 5}
	cout << v[3] << endl; //4
	cout << v.at(2) << endl; //3
	cout << v.size() << endl; //5
	v.clear();
	cout << v.empty() << endl; //ture
    
	return 0;
}
  • .push_back([데이터 형에 맞는 값]) : 벡터 맨 뒤에 새로운 값 추가
  • .pop_back() : 벡터 맨 뒤의 값 삭제
  • [인덱스] : 해당 인덱스에 위치하는 원소에 접근
  • .at(인덱스) : [ ] 연산자와 동일한 기능 / [ ]는 연산자, .at( )은 함수
  • .size() : 벡터의 크기=원소의 개수 반환
  • .clear() : 벡터를 빈 벡터로 만ㄷ름
  • .empty() : 벡터가 비어있으면 (아무 원소도 없으면) true반환, 그렇지 않으면 false반환

 

6. 벡터의 원소에 접근하기

for (int i = 0; i < vec.size(); i++)
	cin >> vec[i]; //내가 원하는 값으로 vec 원소 바꾸기
    
for (int &elem : vec) //0부터 끝까지 element를 뽑아서 cin으로 새로쓰겠다
	cin >> elem;
  • 위 두 for문은 100% 동일한 동작을 함!

 

/*int &elem = vec[0]; -> body(cin >> elem)
  int &elem = vec[1]; -> body(cin >> elem)
  int &elem = vec[2]; -> body...(마지막 element까지)*/
for (int &elem : vec) //0부터 끝까지 element를 뽑아서 cin으로 새로 쓰겠다
	cin >> elem;

/*int elem = vec[0]; -> body(cout << elem) 
  int elem = vec[1]; -> body(cout << elem)
  int elem = vec[2]; -> body...(마지막 element까지)*/
for (int elem : vec)
	cout << elem;
  • cin으로 값을 키보드로부터 받을 땐 &걸어주기: 입력값을 vector안의 값으로 바꿔야 함 → &걸어줘서 elem과 각 원소 동기화
  • cout으로 출력할 땐 x: vector안의 값을 안바꿔주고 출력만 하면 됨 → & 안 걸어줘도 됨

 

*) 1~3 example

#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;

void print(const vector<int> &vec) { //벡터 원소 출력->원소 바뀌지 않음
	//size는 언제나 양수값, i에 unsigned붙여 더 명확하게
	for (unsigned i = 0; i < vec.size(); i++) 
		cout << setw(4) << vec[i];
	cout << endl;
}

int sum(const vector<int> &vec) { //벡터 원소 합->원소 바뀌지 않음
	int result = 0;
	for (int elem : vec)
		result += elem;

	return result;
}

int main() {
	vector<int> vec = { 10, 20, 30, 40 };

	cout << vec.size() << endl;
//	cout << vec << endl; -> vector는 이렇게해도 화면에 출력되지 않음
	print(vec);

	//vetor의 element에 access할 때 (바꾸거나 가져올 때) index
	vec[0] = 100;
	vec.at(1) = 200; //[] == .at()
	print(vec);

	//vector의 가운데부터 추가,제거하는 메소드도 있음
	vec.push_back(50); //마지막에 element 추가, append - 값을 할당
	print(vec);

	vec.pop_back(); //입력인자x, 마지막 element 제거
	print(vec);

	for (int &elem : vec)
		cin >> elem;

	for (int elem : vec)
		cout << setw(4) << elem;
	cout << endl;

	print(vec);

	return 0;
}
  • &: 객체는 pass by ref.로 보내서 메모리 효율 증가시키기
  • 함수 인자로 벡터를 보내줄 때 역시 &를 걸어서 보내주는게 훨씬 좋음! → &가 없으면 main의 벡터가 함수로 전달될 때 모든 원소의 값을 싹 다 복사하기 때문에 메모리 비효율적
  • 주의: 이 때 &를 걸어주면 main의 벡터 원소가 원하지도 않을 때 바뀔 수가 있음  const 상수라고 말해주기!
  • const: 함수 안에서 입력 객체의 data가 바뀌지 않음을 보증
  • 변경될 일 없는 변수는 const 걸어주는게 무조건 좋음 (추가 정보 → 읽기도 쉽고 안전한 코드)
  • 함수 내에서 벡터안의 원소 값을 잠깐 바꾸고싶을 땐 const 지워주기

 


 

*)sample codes: https://github.com/halterman/CppBook-SourceCode

 

 

 

 

 

 

반응형