CS 프로그램/개발

c++ 프로그래밍 (1) : c언어와의 차이점

parktest0325 2020. 9. 15. 21:58
#include <iostream> 

int main(int argc, char** argv) { 
    std::cout << "HELLO WORLD" << std::endl; 
    return 0; 
}

///////////////
using namespace std;
int main(int argc, char** argv) { 
    int a, b;
    cin >> a >> b;
    cout << a << "+" << b << "=" << a+b << endl; 
    return 0; 
}

1. 헤더파일

c++에서 표준 헤더파일은 .h 를 안붙여줘도 된다. (커스텀은 .h 확장자 붙여줘야함)

 

2. 네임스페이스 

std 는 네임스페이스. C++에서는 같은 이름을 가진 식별자가 있을 수 있는데, 네임스페이스를 명시하여 구분할 수 있다.

using namespace std; 를 통해 사용할 네임스페이스를 지정하면 주석 아래 코드처럼 std를 생략할 수 있다. 

 

3. 입출력

cout은 함수가 아닌 객체이며 << 연산자를 이용하여 출력내용을 객체의 버퍼로 삽입한다. 

c++은 c언어처럼 출력할때나 입력할때 %d, %s, %c, %f 등으로 타입을 지정해주지 않아도 된다. 

 

4. 데이터타입

#include <iostream>
#include <string>


int main(){
    std::string name;
    std::cout << "이름 입력 : ";
    std::cin >> name;
    
    std::string message = "안녕하세요, " + name + " 님.";
    std::cout << message << std::endl;
}

string 이라는 타입을 지원하며 배열 형태가 아니기때문에 길이를 지정하지 않아도된다.

c언어에서는 문자열이 배열로 만들어지며 strcat으로 합쳤지만, 문자열을 + 연산자로 합칠 수 있다. 

 

5. 초기화

c++ 에서는 int a = 10; 과 int a; a = 10; 이 다르다. 또한 int a(10); 과 같은 모양으로도 사용할 수 있다. (왜다른지는 나중에)

 

6. 범위기반 for문

int main(){
    int arr[10] = {3,1,4,1,5,9,2,6,5,3};
    
    for(int i=0; i<10; i++){
        cout << arr[i] << endl;
    }
    
    for(int n : arr){
        cout << n << endl;
    }	
}

위의 for문과 아래의 for문이 동일한 역할을 수행하는데, n이라는 지역변수가 arr의 각 원소가 되어 출력하게된다.

 

7. 레퍼런스 변수, l-value, r-value

void swap (int& a, int& b){
    int tmp = a; 
    a = b;
    b = tmp;
}

int main(){
    int a = 5;
    int& p = a;
    p = 10;
    
    int arr[10] = { 3, 1, 4, 1, 5, 9, 2 , 6, 5, 3 };
    
    for( int& n : arr ){ // n의 주소에 arr의 각 원소의 주소가 전달된다고 보면됨
        n++ ; // == *n++ 
    }
    for( int n : arr ){ // arr의 각 원소의 값을 가져온다. (위에서 +1 씩 됨)
        cout << n << endl;
    }
}

포인터와 비슷한데, 변수에 별명을 붙여주는 변수라고 생각하면 쉽다. 포인터는 주소를 저장하는 변수를 새로 생성하고 그 주소에 다른 변수의 주소를 담는 방식이라면 레퍼런스변수는 변수를 가리킬수 있는 이름을 추가하는 것이다.

int& p = a; 에서 p라는 레퍼런스 변수를 선언하고 a의 주소를 가져왔기 때문에 p와 a는 공용체(union)와 같은 느낌으로 같은 메모리 공간에 존재한다.

C++11 에서 rvalue, lvalue 개념이 도입됐다.

C : lvalue는 대입 시 왼쪽 혹은 오른쪽에 오는 식이고, rvalue는 대입 시 오직 오른쪽에만 오는 식

C++ : lvaue는 어떤 메모리 위치를 가리키는데 &를 통해 그 위치를 참조할 수 있으며 rvalue는 lvalue가 아닌 모든값.

std::string a = "abc";
std::string b = a;
// 오른쪽에 있는 값들은 전부 rvalue이다.
std::int c = 2;
std::int d = c*2;
std::int e = c*d;

a="abc"; 코드에서 "abc"는 메모리공간(.rdata)에 저장된 뒤 a 라는 변수가 이 메모리공간을 가리키도록(move)한다.

b=a; 코드에서 a는 이미 메모리공간의 "abc" 라는 데이터를 가리키고있는데, b에 값을 넘겨주기 위해 a의 값 "abc"를 다른 메모리 공간(스택)에 복사(copy)하고 스택에 복사된 "abc"는 b가 가리키는 상태가 된다. 

이렇게 a, b는 lvalue 라고 부르며, "abc" 같이 move를 통해 전달되는 값은 rvalue라고 한다. 

 

#include <iostream>
#include <string>

using namespace std;

void storeByValue(string s) {
	string b = s;
	cout << "b1=" << &b << endl;
	cout << "s1=" << &s << endl << endl;
}
void storeByLRef(string& s) {
	string b = s;
	cout << "b2=" << &b << endl;
	cout << "s2=" << &s << endl << endl;
}

void storeByRRef(string&& s){
    // string b = s;
	string b = move(s);
	cout << "b3=" << &b << endl;
	cout << "s3=" << s << endl << endl;
}

int main() {
	string a = "abc";
	cout << " a=" << &a << endl;
	cout << " t=" << &"test" << endl<<endl;
	storeByValue(a);
	storeByLRef(a);
	storeByRRef("def");
}

레퍼런스 변수는 자신과 대입한 변수가 동일화 되는것이다. 

1) storeByValue

a 가 string으로 선언되면서 스택에 메모리 공간이 생기고, .rdata영역에 "abc"가 생성되어 이 값을 가리키게 된다.

string s 를 파라미터로 전달받을 때, 스택에 s의 공간이 생기며 a의 값 "abc"가 .rdata에서 복사된 뒤 s가 가리키게된다.

b 값에 s를 저장할때에도 b가 스택에 공간이 할당되며, "abc"가 .rdata에 복사되고 그 복사된 영역을 b가 가리키게된다.

 

2) storeByLRef 

&하나를 붙인 변수는 좌측값 참조 변수(lvalue reference)라고 한다. 

string& s 레퍼런스 변수를 파라미터로 전달받는데, 이 변수는 전달받은 a와 동일하게 된다. &a == &b

b 변수는 스택에 생성되며 s의 값 "abc"가 복사되고 그 값을 가리키게 된다.

 

3) sotreByRRef

&두개를 붙인 변수는 우측값 참조 변수(rvalue reference)라고 한다.

우측값 참조 변수는 우측값(상수, 식 등)을 참조하는 변수이다. string&& s = "abc"; 라는건 "abc" 라는 .rdata에 생성되는 문자열상수에 s라는 별명을 붙였다고 보면 된다. 변수는 "abc"를 가리키는 s를 힙메모리공간에 할당한거라면, &&s는 "abc"의 별명그니까 "abc" 그 자체이다.

이 변수는 copy 최적화를 위해 move와 함께 사용하도록 만들어졌다. 

 

move(s) 설명 나중에 다시공부

youtu.be/6buEm6R980o

 

8. 오버로딩

void swap(int& a, int& b);
void swap(int*& a, int*& b);
void swap(double a, double b);

C언어에서는 컴파일러가 함수명을 보고 정의부를 찾기 때문에 동명함수가 존재하면 에러가 발생하지만, C++에서는 함수명과 매개변수를 한꺼번에 보기 때문에 동일한 이름이라도 매개변수가 다르면 컴파일이 가능하다. 

 

9. 함수 기본값

int inventory[64] = { 0 };
int score = 0;

void setItem(int itemId, int num=5);

void getItem(int itemId, int cnt=1, int sc=0){
    inventory[itemId] += cnt;
    score += sc;
}
void setItem(int itemId, int num){
    ...
}

int main(){
    getItem(3); // cnt, sc 변수는 기본값을 사용
    getItem(6,3); // sc 변수는 기본값을 사용
    getItem(11,34,7000);
}

파라미터에 디폴트 값을 정의해줄 수 있기 때문에 파라미터 일부를 넘기지 않아도된다. 하지만 디폴트 값을 지정한 파라미터는 오른쪽에 몰려있어야 한다.

함수 선언부에만 디폴트 값을 지정하면 된다.