C++ 기초: 변수, 함수, 포인터
C++을 처음 배울 때 가장 먼저 부딪히는 세 가지가 있습니다. 변수, 함수, 포인터. 이 세 개념만 잡으면 나머지는 확장일 뿐입니다.
변수 — 데이터를 담는 상자
C++에서 변수를 선언하려면 타입을 먼저 지정해야 합니다. Python처럼 알아서 추론해주지 않습니다.
int age = 23;
double gpa = 3.8;
char grade = 'A';
bool isStudent = true;
C++11 이후로는 auto 키워드가 생겼습니다. 컴파일러가 타입을 추론해 줍니다.
auto count = 10; // int
auto pi = 3.14159; // double
auto name = "White"; // const char*
하지만 auto를 남발하면 코드 가독성이 떨어집니다. 타입이 명확하지 않은 상황에서는 직접 명시하는 편이 낫습니다.
함수 — 반복을 줄이는 도구
함수를 만들 때는 반환 타입, 이름, 매개변수를 선언합니다.
int add(int a, int b) {
return a + b;
}
void greet(const std::string& name) {
std::cout << "Hello, " << name << std::endl;
}
여기서 주목할 점은 const std::string& 부분입니다. 문자열을 복사하지 않고 참조로 전달하면 성능상 이점이 있습니다. 원본을 수정하지 않겠다는 의미로 const를 붙입니다.
함수 오버로딩
C++은 같은 이름의 함수를 매개변수 타입만 다르게 여러 개 만들 수 있습니다.
int multiply(int a, int b) {
return a * b;
}
double multiply(double a, double b) {
return a * b;
}
컴파일러가 호출 시 인자 타입을 보고 어떤 함수를 쓸지 결정합니다. Java나 C#에서도 동일한 개념이 있으니 낯설지 않을 겁니다.
포인터 — C++의 진짜 얼굴
포인터는 C++을 C++답게 만드는 핵심 개념입니다. 메모리 주소를 직접 다룰 수 있다는 건 강력하지만, 실수하면 프로그램이 바로 터집니다.
int value = 42;
int* ptr = &value; // value의 주소를 저장
std::cout << ptr; // 주소 출력: 0x7fff...
std::cout << *ptr; // 역참조: 42
&는 주소를 가져오고, *는 주소에 저장된 값을 꺼냅니다. 이 두 연산자만 기억하면 됩니다.
동적 메모리 할당
new로 힙 메모리를 할당하고, delete로 반드시 해제해야 합니다. 안 하면 메모리 누수가 발생합니다.
int* arr = new int[5]; // 힙에 배열 할당
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
}
delete[] arr; // 반드시 해제
arr = nullptr; // dangling pointer 방지
실무에서는 new/delete를 직접 쓰는 대신 스마트 포인터를 씁니다.
#include <memory>
auto ptr = std::make_unique<int>(42);
// delete 필요 없음 — 스코프 벗어나면 자동 해제
std::unique_ptr과 std::shared_ptr을 쓰면 메모리 관리 실수를 대폭 줄일 수 있습니다.
세 개념의 연결
변수는 데이터를 담고, 함수는 그 데이터를 처리하고, 포인터는 데이터가 어디에 있는지를 추적합니다. 이 세 가지가 C++ 프로그램의 기본 골격입니다.
다음 단계로는 클래스와 객체지향 프로그래밍을 학습하는 것을 권합니다. 변수를 구조화하고, 함수를 묶고, 포인터를 캡슐화하는 것이 곧 객체입니다. 결국 지금 배운 것의 연장선에 있습니다.