본문 바로가기

Programing/C++

[C++] C++와 표준 라이브러리 초단기 속성코스(반복문, 스트링, 스택 & 힙)

728x90
반응형

출저 : 책, 전문가를 위한 C++ 

 

① 반복문

컴퓨터는 같은 일을 계속 반복하는데 뛰어나다. 이를 위해 C++는 while, do.while,for, 범위기반 for 등 네가지 반복 메커니즘을 제공한다.

 

② while문

while문은 주어진 표현식이 true가 될 때 까지 일정한 코드 블록을 계속해서 반복한다.

다음 코드는 This is silly. 라는 문장을 다섯번 출력한다.

#include <iostream>

int main()
{
	int i = 0;
	while (i < 5) {
		std::cout << "This is silly." << std::endl;
	}
}

break키워드를 사용하면 반복문(루프)을 즉시 빠져나와 뒤에 있는 코드를 계속 진행한다. continue키워드를 사용하면 즉시 반복문의 첫문장으로 돌아가서 while문에 지정한 표현식을 다시 평가한다. 하지만 반복문 안에서는 continue사용을 자제한다. 프로그램의 실행흐름을 갑자기 건너뛰게 작성하는 것은 바람직 하지 않기 때문에 꼭 필요할 때만 사용하는 것이 좋다.

 

③ do/while문

C++는 while문을 약간 변형한 do/while문도 제공한다. 동작은 while문과 비슷하지만 먼저, 코드 블록부터 실행한뒤 조건을 검사하고 그 결과에 따라 루프를 계속 진행할지 결정한다.

이 구문을 활용하면 코드 블록을 최소 한번 실행하고 그 뒤에 더 실행할지 여부는 주어진 조건에 따라 결정할 수 있다.

 

다음 코드는 while조건이 false이더라도 'This is silly.' 란 문장이 한번은 출력되는 예를 보여준다.

#include <iostream>

int main()
{
	int i = 100;
	do {
		std::cout << "This is silly." << std::endl;
		++i;
	} while (i < 5);
}

 

④ for문

반복문을 작성하기 위한 구문으로 for문도 있다. for문으로 작성한 코드는 모두 while문으로 변환할 수 있고, 그 반대도 가능한다. 하지만 for문의 문법이 더 편할 떄가 많다. 초기 표현식, 종료 조건, 매번 반복이 끝날 때마다 실행할 문장으로 반복문을 구성할 수 있기 때문이다.

 

위의 This is silly. 라는 문장을 다섯번 출력한 while문의 코드를 for문으로 작성해보겠다. 어떻게 다른지 지켜보자

#include <iostream>

int main()
{
	for (int i = 0; i < 5; i++)
	{
		std::cout << "This is silly." << std::endl;
	}
}

 

초기값, 종료 조건, 반복할때 마다 실행할 문장을 모두 한줄에 표현해서 좀더 읽기 쉽다.

 

⑤ 범위 기반 for문

이 구문은 컨테이너에 담긴 원소에 대해 반복문을 실행하는데 편하다. C스타일으 루프, 이니셜라이저 리스트, 그리고 array, vector, 표준 라이브러리에서 제공하는 컨테이너 처럼 반복자를 리턴하는 begin()과 end()메서드에 정의된 모든 타입에 정의할 수 있다.

 

다음 예제는 먼저 정수값 네개로 구성된 배열을 정의한다 그런 다음 범위기반 for문을 돌면서 이 배열의 모든 원소에 대한 복제본을 화면에 출력한다. 이렇게 원소를 일일이 복제하지 않고 반복문을 실행하려면 레퍼런스 변수를 활용하면된다.

#include <iostream>
#include <array>

int main()
{
	std::array<int, 4> arr = { 1,2,3,4 };
	for (int i : arr)
	{
		std::cout << i << std::endl;
	}
}

 

이니셜라이저 리스트

이니셜라이저 리스트는 <initializer_list>헤더 파일에 정의돼 있으며, 이를 활용하면 여러 인수를 받는 함수를 쉽게 작성할 수 있다. 엄밀히 말해 initializer_list는 클래스 템플릿이다. 그래서 vector에 저장할 객체의 타입을 지정할 때 처럼 원소 타입에 대한 리스트를 꺾쇠 괄호로 묶어서 지정해야한다. 다음 예제를 통해 구체적인 방법을 살펴보자

#include <initializer_list>
using namespace std;

int makeSum(initializer_list<int> lst)
{
	int total = 0;
	for (int val : lst) {
		total += val;
	}
	return total;
}

 

여기서 makeSum()함수는 정수에 대한 이니셜라이저 리스트를 인수로 받는다. 그리고 함수 안에서 범위 기반 for문을 사용해서 인수로 주어진 정수들을 모두 더한다. 이 함수를 호출하는 방법은 다음과 같다.

int a = makeSum({ 1,2,3 });
int b = makeSum({ 10,20,30,40,50,60 });

이니셜라이저 리스트는 타입에 안전(타입세이프)하다. 그래서 이니셜라이저 리스트를 정의할 때는 지정한 타입만 허용한다. 앞에서 makeSum() 함수를 정의할 때 이니셜라이저 리스트에 정수 타입 원소만 들어가도록 지정했다. 그래서 다음과 같이 인수로 double 타입 값을 지정하면 컴파일 에러 또는 경고 메시지가 출력된다.

 

int a = makeSum({ 1,2,3.0}); //complie error

C++의 스트링

C++에서 텍스트 스트링을 다루는 방법은 세가지가 있다.

 ① C 처럼 스트링을 문자 배열로 표현

 ② 스트링 타입으로 감싸서 표현

 ③ 비표준 제네릭 클래스를 사용

 

여기서 C++의 string타입은 <string>헤더 파일에 정의돼 있고, 기본 타입 처럼 사용할 수 있다는 정도만 알아두자.

string타입은 I/O 스트림과 마찬가지로 std 네임 스페이스에 속한다.

다음 예는 string을 문자 배열 처럼 다루는 방법을 보여주고 있다.

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

int main()
{
	string myString = "Hello, World";
	cout << "The value of myString is " << myString << endl;
	cout << "The second letter is " << myString[1] << endl;
}

 

포인터와 동적 메모리

동적 메모리를 이용하면 컴파일 시간에 크기를 확정 할 수 없는 데이터를 다룰수 있다. 아주 단순한 프로그램이 아니라면 대부분 어떤 형태로든 동적 메모리를 사용한다.

 

스택과 힙

C++ 애플리케이션에서 사용하는 메모리는 크게 스택(stack)과 힙(heap)으로 나뉜다.

스택은 테이블에 쌓아둔 접시에 비유할 수 있다. 제일 위에 놓인 접시는 프로그램의 현재 스코프를 표현하며, 주로 현재 실행 중인 함수를 가리킨다. 현재 실행 중인 함수에 선언된 변수는 모두 최상단의 접시에 해당하는 최상단 스택 프레임의 메모리 공간에 담겨있다. 

 

예를 들어 현재 foo()라는 함수가 실행된 상태에서 bar()라는 다른 함수를 호출 하면 최상단 접시 위에 bar()라는 함수에 대한 접시, 즉 스택 프레임이 올라온다. foo()에서 bar()로 전달되는 매개변수는 모두 foo()의 스택 프레임에서 bar()스택 프레임으로 복제 된다. 두 개의 정수값이 선언된 foo()함수가 실행되는 동안의 스택 프레임 상태를 보여주고 있다.

 

출저 : 책, 전문가를 위한 C++

 

스택 프레임은 각각의 함수마다 독립적인 메모리 공간을 제공한다는 점에서 굉장히 유용하다. 

foo()함수에 대한 스택 프레임에 변수 한 개가 선언돼 있을 때 bar()함수를 호출하더라도 특별히 수정하지 않는 한 그 변수는 그대로 유지된다. 또한 foo()함수의 실행이 끝나면 해당 스택 프레임이 삭제되기 때문에 그 함수 안에 선언된 변수가 더 이상 메모리 공간을 차지 하지 않는다. 스택에 할당된 변수는 프로그래머가 직접 할당 해제 할 필요 없이 자동으로 처리 된다.

 

힙이란 현재 함수 또는 스택프레임과는 완전히 독립적인 메모리 공간이다. 함수가 끝난 후에도 그 안에서 사용하던 변수를 계속 유지하고 싶다면 힙에 저장한다. 힙은 스택보다 구조가 간결하다. 마치 비트 더미와 같다. 프로그램에서 원하는 시점에 언제든지 이 비트 더미에 새로운 비트를 추가하거나 기존에 있던 비트를 수정할 수 있다. 힙에 할당된 메모리 공간은 직접 할당 해제(삭제) 해야 한다. 힙은 스마트 포인터를 사용하지 않는 한 자동으로 할당 해제 되지 않기 때문이다.

반응형