2012년 8월 16일 목요일

Handler 메모리 릭 없이 쓰기.(Lint Warnings 제거)

Android 개발 하면서 메세지 처리를 위해서 Handler 를 이용한다. 보통 쓰는 방법은 아래와 같다.

  1. public class Parent
  2. {     
  3.     private Handler m_handlerProc = new Handler()
  4.     {
  5.         @Override
  6.         public void handleMessage(Message message)
  7.         {
  8.            ...
  9.         }
  10.     };
  11. }

쓰는데는 무리가 없지만 패키지 말을때 "Lint Warnings) 가 나타난다.

해서 Warnings 을 제거 하기 위해서는 코드를 아래와 같이 수정하면 된다.

  1. public class Parent
  2. {
  3.     static class InnerHandler extends Handler
  4.     {
  5.         WeakReference<Parent> m_HandlerObj;
  6.         InnerHandler(Parent handlerobj)
  7.         {
  8.             m_HandlerObj = new WeakReference<Parent>(handlerobj);
  9.         }
  10.  
  11.         @Override
  12.         public void handleMessage(Message message)
  13.         {
  14.             Parent handlerobj = m_HandlerObj.get();
  15.             ....
  16.         }
  17.     }
  18.  
  19.     private InnerHandler m_handlerproc = new InnerHandler(this);
  20. }

^^ 그럼 즐프들 하세요..


2012년 8월 13일 월요일

Java String split

Visual C++ 개발 할때 문자열 자르는 함수를 라이브러리로 항상 대동 하고 다녔던거와는 달리

Java 에서는 String Class 에서 split 함수를 제공한다 쓰는 방법은 아래와 같다.

String strMessage = "Test`One`Two`Three";

String[] sArrMsg = strMessage.split("`");

for(int i=0; i<sArrMsg.length; i++)
{
System.out.println(String.format("Parse 문자열 = %s", sArrMsg[i])); 
}

위와 같이 함수를 제공해줘서 아주 잘 쓰고 있는데 문제가 하나 있다.

특정 특수 문자는 파싱이 되지 않는다는 점이다. 문자열 예시를 아래와 같이 바꾸면

String strMessage = "Test.One.Two.Three";

파싱이 되지 않는다. 파싱을 하려면 split 함수 안에 아래와 같이 넣어 줘야 정상 동작한다.

String[] sArrMsg = strMessage.split("\\.");

위와같은 문자열은 더 있는거 같고요 일단 제가 발견한 문자는 ".", "(", ")" 입니다. 발견되는 데로 업데이트 합니다 ..

쓰시는 분들은 유의 하시면 될거 같습니다 ^^;

유의할점은 만약에 파싱할 문자열이 아래와 같다면

String strMessage = "Test```";

파싱되는 문자열이 4개가 아니라 1이 됩니다. 이것을 방지 하기 위해서는 뒤에 공백 문자열을 넣어줘야 정상 동작 합니다.

String strMessage = "Test``` ";

Android 날짜 일수 계산

Android 개발할때 두개의 날짜를 가지고 날짜 일수를 계산 하는 방법입니다.


Date today = new Date();


Calendar calToday = Calendar.getInstance();
calToday.setTime(today);


Calendar calEnd = Calendar.getInstance();
calEnd.set(2012, 8-1, 5);// month 의 경우 해당 월수에 -1을 해줍니다.


int nRemainCnt = 0;


while(!calToday.after(calEnd))
{
nRemainCnt++;
calToday.add(Calendar.DATE, 1);
}



위 while 루프를 빠져 나오면 nRemainCnt 변수에 일수가 저장된다. ^^

iPhone 날짜 일수 계산

iPhone 개발할때 두개의 날짜를 가지고 날짜 일수를 계산 하는 방법입니다.


NSString* strEndDate = "2012.08.05";
NSDateFormatter *dateFormat = [[[NSDateFormatter alloc] init] autorelease];
[dateFormat setDateFormat:@"YYYY.MM.dd"];


NSDate* pEndDate = [dateFormat dateFromString:strEndDate];


double timeInterval = [pEndDate timeIntervalSinceNow];


int nRemainDay = (int)((double)timeInterval/(3600.0*24.00));


위 코드에 nRemainDay 에 날짜 차이값을 얻을수 있습니다 ^^.

2012년 8월 9일 목요일

const 맴버 함수에 대한 이해

가끔 MFC나 혹은 그 밖이 다른 소스를 보면 다음과 같은 맴버 함수들을 볼 수 있다.


class CPeople
{
public:
 CPeople() : m_nAge(5) {;}
 ~CPeople() {;}
 void SetAge(const int& Age) { m_nAge = Age; }
 int  GetAge () const
 {
  return m_nAge;
 }

private:
 int m_nAge;
};

자주는 봤지만 그 의미 파악을 하지는 않고 넘어간 경우가 있어 이번 기회에 확실하게 개념을 파악을 해야 겠다.

기본적으로 const는 상수성을 지닌다는 키워드인데 저렇게 맴버 함수에 const가 붙은 경우는
'이 맴버 함수는 상수 객체에 대해 호출되는 함수이다'라는 의미를 지니게 된다.
또 한 const 키워드가 맴버 함수에 붙음으로서 이 함수 안에서 사용하는 모든 맴버 변수들은 const 키워드가 붙지 않아도
상수성을 지닌다.

다음의 예를 보자
class CPeople
{
public:
 CPeople() : m_nAge(5) {;}
 ~CPeople() {;}
 void SetAge(const int& Age) { m_nAge = Age; }
 int  GetAge () const
 {
    m_nAge = 5;  // 컴파일 오류 맴버 변수는 상수성을 가지게 된다.
    int vale = 5;  // 이건 가능 지역 변수는 상수성을 지니지 않는다. 
    return 1;
 }
 private:
 int m_nAge;
}

GetAge()라는 함수 뒤에 const 키워드가 붙음으로 인해 이 맴버 함수안에 들어 있는 맴버 변수들은 상수성을 가지므로 이 맴버 함수 안에서 맘음대로 맴버변수의 값을 바꾸는건 불가능하게 된다. 

또한 클래스의 객체가 만약 상수 객체라고 한다면 const 맴버 함수만을 호출 할 수 있다.
무슨 말인지는 다음 예를 보면 간단하게 파악이 가능하다.


위와 같이 같은 GetAge()함수지만 하나는 상수 맴버 함수 다른 하나는 비상수 맴버 함수라고 오버로딩 하여 선언하였다.

위와 같이 보통 객체의 경우 GetAge()를 호출하는 경우 비상수 맴버인 GetAge()가 호출이 된다.

하지만 다음과 같은 상수 객체일 경우 GetAge() const 인 상부맴버함수가 불리게 된다.


그럼 저렇게 각 함수에 대해 오버로딩 되어 있지 않고 상수맴버함수만 정의 해놓았을 때는 어떻게 될까?

일반적으로 비상수 객체가 상수맴버 함수의 호출은 가능하다.
하지만 상수객체가 비상수맴버 함수 호출은 불가능하다.

즉 상수객체는 상수맴버 함수만 호출 할 수 있다는 것이고,
비상수 객체는 상수맴버함수, 비상수맴버함수 모두 호출이 가능하다는 뜻이다.



위의 예 처럼 상수 객체가 비 상수 객체를 호출하는 경우 이런경우는 Error이 발생하게 된다.


출처:http://sanaigon.tistory.com/99

UTF-8 Web Text 문자열 변환.

[UTF-8 변환된 문자열 웹에 URL 로 넣어주기 위한 변환 방법]

<Source>
// strOrgUTF8Data 변수는 실제로 받은 또는 변환된 UTF-8 데이터입니다.

CString strEnCodeText;
int nCount = strOrgUTF8Data.GetLength();

for(int i=0; i<nCount; i++)
{
if(strOrgUTF8Data.GetAt(i) & 0x80)
{
CString strChar;
strChar.Format("%%%02X", (BYTE)strOrgUTF8Data.GetAt(i));
strEnCodeText += strChar;
} 
else
{
strEnCodeText += strOrgUTF8Data.GetAt(i);
}
strOrgUTF8Data = strEnCodeText;
}

UTF8 핸들링

1. UTF8이란? 

유니코드 는 전세계 대부분의 주요 언어의 문자 집합을 하나로 모아 서로 충돌하지 않게 같은 코드 공간 속에 배열해 놓은 것이지만, 문자를 표현하기 위해 최소 16 비트를 요구하기 때문에 현재 전세계적으로 널리 쓰이고 있는 8 비트 기반의 ASCII/ISO-8859 인코딩과는 잘 맞지 않는다. 따라서 이 두가지 방식이 공존할 수 있게 고안한 인코딩 방식이 UTF-8 이다.

2. 참고링크 

3. UTF8 변환 

UTF8 코드는 유니코드와 ASCII 코드의 중간 단계이기 때문에 다른 코드로 변환하기 위해서는 유니코드로 변환해야 한다. UNIX/LINUX 계열에서는 libiconv 라이브러리를 사용하여 변환할 수 있으며, Windows 에서는 WinAPI 중 MultiByteToWideChar()WideCharToMultiByte() 함수를 이용하여 변환한다.

3.1. UTF8 에서 CP949 로 변환 

UTF8 에서 CP949 ( MS Windows 에서 한글 코드페이지 ) 로 변환하기 위해서 다음과 같은 과정을 거친다.
  • UTF8 Code --> Unicode --> CP949 code
대략적인 코드는 다음과 같다.
  •    1 char szText[BUFFER_MAX];
       2 wchar_t wszBuffer[BUFFER_MAX];
       3 
       4 // UTF8 Code --> Unicode
       5 MultiByteToWideChar( CP_UTF8, 0, szText,    -1, wszBuffer, BUFFER_MAX );
       6 // Unicode --> CP949 code
       7 WideCharToMultiByte( CP_ACP,  0, wszBuffer, -1, szText,    BUFFER_MAX, NULL, NULL );
    

3.2. CP949 에서 UTF8 로 변환 

UTF8 에서 CP949 로 변환하는 과정의 반대로 처리한다.
  • CP949 code --> Unicode --> UTF8 Code
대략적인 코드는 다음과 같다.
  •    1 char szText[BUFFER_MAX];
       2 wchar_t wszBuffer[BUFFER_MAX];
       3 
       4 // CP949 Code --> Unicode
       5 MultiByteToWideChar( CP_ACP,  0, szText,    -1, wszBuffer, BUFFER_MAX );
       6 // Unicode --> UTF8 code
       7 WideCharToMultiByte( CP_UTF8, 0, wszBuffer, -1, szText,    BUFFER_MAX, NULL, NULL );
    
 
출처 : http://www.viper.pe.kr/cgi-bin/moin.cgi/UTF8_%EB%B3%80%ED%99%98

새로운 형 & 함수포인터 정의

형을 정의하는 법

 사용자가 필요로 하는 형(type)을 정의(definition)할 수 있는 방법을 C++는 제공한다. 형을 정의할 때는 이미 정의된 형을 이용할 수도 있고, 전혀 새로운형을 정의할 수도 있다. 또한 C++의 구조체(structure), 공용체(union)와 클래스(class)는 동적인 형(dynamic type)을 정의하는 기능을 제공한다. 형을 정의하는 방법은 다음과 같은 것이 있다. typedef , enum,  struc,t union,  class

typedef(TYPE DEFinition)
typedef는 형을 정의하는 C++의 공식적인 키워드이다. 하지만 typdef가 새로운 형을 정의할 수는 없다. 이미 존재하는 형의 별명을 정의하는 것이다.
  1. typedef unsigned char byte;
 typedef는 형을 정의하는 문장(statement)이므로 끝에 세미콜론이 필요하다. 마지막의 단어가 형으로 정의된다는 것을 주의하라.

특별한 형 정의는 함수 포인터 형(function pointer type)을 정의하는 경우에 발생한다.
  1. typedef long (*Fun)(long,long);
이 경우 형의 이름은 Fun이다. 이것은 긴 정수 2개를 파라미터로 받고 긴 정수를 리턴하는 함수 포인터 형이다. 만약 typedef가 생략되면 long (*Fun)(long,long); 처럼 되는데, 이 경우 Fun은 변수가 된다. 즉 typedef가 있느냐, 없느냐에 따라 형 혹은 변수가 되는 것이다.

 함수 호출 규약
출처 : http://www.winapi.co.kr/clec/cpp2/16-1-3.htm

앞 항에서 Add 함수의 어셈블리 코드를 통해 스택 프레임의 실제 모양을 확인해 보았다. 인수는 뒤쪽부터 순서대로 전달하며 인수 전달에 사용한 스택 영역은 호출원이 정리했는데 이는 C/C++ 언어의 기본 호출 규약인 __cdecl의 스택 프레임 모양일 뿐이다. 호출 규약이 바뀌면 스택 프레임의 모양과 관리 방법도 달라질 수 있다.
호출 규약은 호출원과 함수간의 약속이므로 양쪽이 다른 형태로 약속을 할 수도 있는 것이다. 그렇다면 __cdecl이 아닌 다른 호출 규약은 어떻게 스택 프레임을 작성하는지 차이점을 분석해 보자. 호출 규약에 따라 인수를 전달하는 방법과 스택의 정리 책임, 함수의 이름을 작성하는 방법이 달라진다.

호출 규약
인수 전달
스택 정리
이름 규칙
__cdecl
오른쪽 먼저
호출원
_함수명
__stdcall
오른쪽 먼저
함수
_함수명@인수크기
__fastcall
ECX, EDX 우선 전달. 나머지는 오른쪽 먼저
함수
@함수명@인수크기
thiscall
오른쪽 먼저, this 포인터는 ecx 레지스터로 전달된다.
함수
C++ 이름 규칙을 따름.
naked
오른쪽 먼저
함수
없음

리턴값을 돌려 주는 방식도 호출 규약에 따라 달라질 수 있는데 다행히 현존하는 모든 호출 규약의 리턴 방식은 동일하다. 4바이트의 값을 돌려줄 때는 eax 레지스터를 사용하며 8바이트의 값을 리턴할 때는 edx:eax 레지스터 쌍을 사용한다. 8바이트를 초과하는 큰 리턴값, 예를 들어 구조체 등은 임시 영역에 리턴할 값을 넣어 두고 그 포인터를 eax에 리턴한다.

__stdcall

Add 함수의 호출 규약을 __stdcall로 바꿔 보자. __stdcall은 윈도우즈 API 함수들의 기본 호출 규약이며 비주얼 베이직도 이 호출 규약을 사용한다. __cdecl과 인수를 전달하는 방법은 동일하되 인수 전달에 사용된 스택을 정리하는 주체가 호출원이 아니라 함수라는 점이 다르다. Add 함수의 호출 규약을 바꾸기 위해 다음과 같이 수정해 보자.

int __stdcall Add(int a, int b)
{
     int c,d,e;
     c=a+b;
     return c;
}

함수 이름앞에 __stdcall 키워드를 삽입하면 이 함수는 __stdcall 호출 규약을 사용한다. main에서 함수를 호출하는 부분이 다음과 같이 변경된다.

push 2
push 1
call Add
result=eax

인수를 스택에 밀어 넣는 것과 인수를 푸시하는 순서는 동일하다. 단, call Add 다음에 add esp,8 코드가 없어 함수가 리턴된 후에 인수 전달에 사용한 스택을 복구하지 않는다는 점이 __cdecl과 다르다. 인수 전달에 사용한 영역은 이제 Add 함수가 직접 정리한다. 이 함수의 접두, 본체는 __cdecl과 동일하며 접미 부분이 다음과 같이 변경된다.

push ebp
....
ret 8

복귀 코드가 ret에서 ret 8로 바뀌었으며 복귀하면서 esp를 8만큼 증가시킨다. 이 코드에 의해 함수는 실행을 마치고 복귀함과 동시에 인수 영역을 해제한다. Add 함수 자신이 복귀하면서 스택을 정리하므로 호출원에서는 스택을 정리할 필요가 없다. 호출원은 인수를 순서대로 스택에 푸시한 후 함수만 호출하면 된다.

__cdecl과의 차이점

__cdecl과 __stdcall의 가장 큰 차이점은 스택 정리 주체가 누구인가하는 점인데 사실 이 차이점이 컴파일된 결과 코드에 미치는 영향은 별로 없다. 스택 정리 주체와는 상관없이 스택은 항상 호출 전의 상태로 복구되며 프로그램의 동작도 완전히 동일하다. 실행 속도는 거의 차이가 없으며 프로그램의 크기는 비록 무시할만한 수준이기는 하지만 __stdcall이 조금 더 작다. 왜냐하면 함수를 여러 번 호출하더라도 스택을 정리하는 코드는 함수 끝의 접미에 딱 한 번만 작성되기 때문이다. 반면 __cdecl은 호출원이 스택을 정리하므로 호출할 때마다 정리 코드가 반복되어 프로그램 크기가 조금 더 커진다.

또 다른 중요한 차이점은 가변 인수 함수를 만들 수 있는가 아닌가 하는 점이다. __stdcall은 함수가 직접 스택을 정리하기 때문에 가변 인수 함수를 지원하지 않는다. 함수 접미에 스택 정리 코드를 작성하려면 인수의 총 크기를 미리 알아야 하는데 가변 인수 함수는 전달되는 인수 개수가 가변이므로 이 크기가 고정적이지 않아 접미에서 스택을 직접 정리할 수 없다. 컴파일러가 접미의 ret n 명령에 대해 n을 결정할 수 없는 것이다.
이에 비해 __cdecl은 함수가 스택을 정리할 책임이 없으며 호출원이 함수를 부를 때마다 스택을 정리한다. 함수를 호출하는 쪽에서는 인수를 몇개나 전달했는지 알 수 있으므로 실제 전달한 인수 크기만큼 스택을 정리할 수 있다. 그래서 printf나 scanf같은 가변 인수를 지원하는 함수는 모두 __cdecl 호출 규약을 사용한다. 또한 윈도우즈 API 함수의 기본 호출 규약은 __stdcall이지만 wsprintf는 예외적으로 __cdecl로 작성되어 있다.
호출 규약 중 호출원이 스택을 정리하는 것은 __cdecl밖에 없으며 그래서 가변 인수를 지원할 수 있는 호출 규약도 __cdecl이 유일하다. 가변 인수 함수를 만들려면 반드시 __cdecl 호출 규약을 사용해야 한다. 만약 가변 인수 함수를 __stdcall로 작성하면 컴파일러는 이를 무시하고 __cdecl로 강제로 바꾸어 버린다.

__fastcall

다음은 __fastcall 호출 규약을 테스트해 보자. 함수 정의부를 int __fastcall Add(int a, int b)로 수정하기만 하면 된다. 호출부의 코드는 다음과 같다.

mov edx,2
mov ecx,1
call Add
result=eax

__fastcall은 인수 전달을 위해 edx, ecx 레지스터를 사용하는데 두 개의 인수를 차례대로 edx, ecx에 대입했다. 만약 인수가 둘 이상이면 세 번째 이후의 인수는 __cdecl과 마찬가지로 스택에 밀어넣을 것이다. 인수 전달을 위해 스택을 쓰지 않고 레지스터를 우선적으로 사용하므로 인수 전달 속도가 빠르다는 이점이 있다. 함수의 코드는 다음처럼 작성된다.

push ebp
mov ebp,esp
sub esp,14h
mov [ebp-8],edx             // 첫 번째 인수를 지역변수로
mov [ebp-4],ecx             // 두 번째 인수를 지역변수로
mov eax,[ebp-4]
add eax,[ebp-8]
mov [ebp-0ch],eax               // c는 세 번째 지역변수가 된다.
mov eax,[ebp-0ch]
mov esp,ebp
pop ebp
ret

edx, ecx 레지스터를 통해 전달받은 인수 둘을 순서대로 지역변수 영역에 복사한 후 사용하는데 어차피 인수도 지역변수의 일종이므로 이렇게 해도 별 상관이 없다. VC는 fastcall 호출시 ecx, edx로 인수를 넘기기는 하지만 이를 다시 스택의 지역변수로 만드는데 이렇게 되면 fastcall을 하는 의미가 없다. 비주얼 C++은 fastcall을 형식적으로만 지원할 뿐 fastcall의 장점을 취하지는 않는데 이는 컴파일러 구현상 ecx, edx 레지스터가 꼭 필요하기 때문이다. 
스택 정리는 함수가 하는데 Add 함수의 경우 인수가 두 개 뿐이므로 인수 전달을 위해 스택을 사용하지 않았으며 그래서 정리할 내용이 없다. 만약 인수가 세 개라면 제일 끝의 ret는 ret 4가 될 것이다. 레지스터는 스택보다 훨씬 더 빠르게 동작하기 때문에 __fastcall은 이름대로 호출 속도가 빠르다. 대신 이식성에 불리하다는 단점이 있다. 이 호출 규약은 ecx, edx 레지스터를 사용하도록 되어 있는데 이 두 레지스터가 모든 CPU에 공통적으로 존재하는 것이 아니기 때문이다. 그래서 윈도우즈 API는 이 호출 규약을 지원하기는 하지만 사용하지는 않는다. 볼랜드의 델파이가 __fastcall을 사용한다.

thiscall

thiscall은 클래스의 멤버 함수에 대해서만 적용되는데 ecx로 객체의 포인터(this)가 전달된다는 것이 특징이며 나머지 규칙은 __stdcall과 동일하다. 예외적으로 가변 인수를 사용하는 멤버 함수는 __cdecl로 작성되며 이때 this는 스택의 제일 마지막에(그러므로 첫 번째 인수로) 전달된다.
이 호출 규약은 컴파일러가 멤버 함수에 대해서만 특별히 적용하는 것이므로 일반 함수에는 이 호출 규약을 적용할 수 없다. thiscall은 이 호출 규약의 이름일 뿐 키워드가 아니기 때문에 함수 원형에 thiscall이라고 쓸 수도 없다. 멤버 함수이기만 하면 컴파일러가 알아서 thiscall 호출 규약을 적용한다. 객체니 멤버 함수니 this니 하는 것들은 C++편에서 배우게 될 것이다.

__naked

__naked 호출 규약은 컴파일러가 접두, 접미를 작성하지 않는 호출 규약이다. 스택 프레임의 상태 보존을 위해 컴파일러가 어떤 코드도 작성하지 않으므로 접두, 접미는 사용자가 직접 작성해야 한다. 스택은 어셈블리 수준에서만 다룰 수 있으므로 인라인 어셈블리를 사용해야 하며 제약점도 많기 때문에 일반적인 목적으로는 사용되지 않는다.
이 호출 규약이 반드시 필요한 경우는 C/C++이 아닌 언어에서 호출하는 함수를 작성할 때이다. 예를 들어 어셈블리에서는 인수 전달에 스택을 쓰지 않고 범용 레지스터만으로도 인수를 전달할 수 있다. 이런 경우는 C컴파일러가 만들어주는 접두, 접미가 불필요하다. 또한 속도가 지극히 중요한 디바이스 드라이버를 작성할 때도 이 호출 규약을 사용한다. __naked 호출 규약을 사용하려면 함수의 정의부에 __declspec(naked)를 적어주면 된다.
여기서 알아본 호출 규약 외에도 __pascal, __fortran, __syscall 이라는 호출 규약이 있었으나 지금은 지원되지 않는다. 비주얼 C++은 과거와의 호환성을 위해 이 단어들을 키워드로 인정하기는 하지만 실제로 사용할 경우 에러로 처리한다. 이상으로 다섯 가지의 호출 규약에 대해 정리했는데 실제로 사용되고 사용자가 지정할 수 있는 호출 규약은 현실적으로 __cdecl, __stdcall 두 가지밖에 없는 셈이다.

C 프로그래머를 위한 C++

1절. C프로그래머를 위한 C++

1.1절. 새로운 include 방법

C++ 에서는 헤더파일을 인클루드 시키기 위해서 새로운 방법을 사용한다. C++ 에서는 C의 표준 헤더파일을 인클루드 시키기 위해서 ".h" 확장자를 사용하는 대신에 ".h"를 생략하고 헤더파일의 가장앞에 "c" 를 붙여서 인클루드 시킨다. 제대로된 인클루드를 위해서 "using namespace std;" 를 포함시키도록 한다. 표준 C++ 헤더는 확장자를 생략하면 된다 - 생략하지 않아도 문제는 없지만 -.
물론 기존의 C 스타일대로 헤더파일을 인클루드 시켜도 문제는 없다. 그러나 어떤 컴파일러의 경우(gcc 3.x 와 같은) 디버깅 옵션을 켜놓은 상태에서 컴파일할경우 warning 메시지를 출력하기도 한다.
// stdlib.h -> cstdlib
#include <cstdlib>
#include <iostream>

using namespace std;
int main()
{
    char *age = "25";

    cout << atoi(age) << endl;
}
   

1.2절. 라인단위 주석사용

C 에서와 마찬가지로 // 를 이용한 라인단위 주석의 사용이 가능하다.
#include <cstdlib>
#include <iostream>             // iostream 라이브러리 사용

using namespace std;           // 표준 라이브러리 namespace 지정
int main()
{
    char *age = "25";

    cout << atoi(age) >> endl; // 출력
    return 1;                  // 종료
}
   

1.3절. 간단하게 사용할수 있는 입출력 스트림

C 에서는 간단한 화면/키보드 입출력이라도 꽤 번거로운 과정을 거쳐야 하지만, C++ 에서는 cout <<, cin >> 을 이용해서 간단한 입출력을 쉽게 처리할수 있다.
#include <iostream>

using namespace std;
int main()
{
    int age;
    char name[32];
    cout << "hello world " << endl;
    cout << "your age : ";
    cin >> age;
    cout << "your name : ";
    cin >> name;

    cout << "Your input is " << name << ":" << age << endl;
}
   

1.4절. 변수선언 위치제한

C 의 경우 변수 선언은 함수의 가장첫부분에서 이루어져야 한다. 만약 중간에 선언이 이루어진다면, 컴파일시 에러를 발생하게 된다.
C++ 은 어느 위치에서라도 선언해서 사용할수 있다. 이러한 점이 때로는 코드를 난잡하게 만들기도 하지만, 오히려 코드를 보기쉽게 만들어줄때도 있다.
#include <iostream>

using namespace std;
int main()
{
    int a, b;

    cout << "A : " ;
    cin >> a ;
    cout << "B : " ;
    cin >> b ;

    int sum;
    sum = a + b;
    cout << a << "+" << b << "=" << sum << endl;
}
   

1.5절. 전역변수와 지역변수의 동일이름 사용

C 에서는 전역변수와 지역변수가 이름이 같을경우 무조건 지역변수의 값만을 사용할수 있었으나(전역변수 값은 사용 할수가 없다), C++ 에서는 각각 구분해서 사용가능하다.
#include <iostream>
using namespace std;

int my_age = 28;
int main()
{
    int my_age = 35;

    cout << "Local my_age " << my_age << endl;
    cout << "global my_age " << ::my_age << endl;

    return 0;
}
   

1.6절. 변수의 상호참조가능

다음과 같은 방법으로 하나의 변수를 다른변수에서 참조하여 사용하는게 가능하다.
#include <iostream>
using namespace std;

int main()
{   
    int a = 200;
    int &b = a;

    b = 100;
    
    cout << "a is "  << a << endl;
    return 0;
}
   
위의 코드를 실행시키면 100 이 출력된다.

1.7절. namespace 의 선언

namespace 를 이용해서 변수의 선언이 가능하며 :: 연산자를 통해서 선언 없이 곧바로 변수의 이용이 가능하다.
#include <iostream>
using namespace std;

namespace first
{
    int a;
    int b;
}
namespace second
{
    int a;
    int b;
}
int main()
{
    first::a = 100;
    first::b = 200;

    second::a = 400;
    second::b = 800;

    cout << first::a + second::a << endl;
    cout << first::b + second::b << endl;
}
   

1.8절. inline 함수의 사용

간단한 함수들은 inline 으로 선언해서 사용함으로써 몇가지 잇점을 얻을수 있다. inline 으로 선언된 함수는 일종의 macro 와 같이 작동을 하게 된다. 즉 필요할때 불러오는 방식이 아니라, 코드에 바로 insert 된 효과를 준다. 이것이 주는 잇점은 코드가 약간 커지긴 하겠지만, 빠른 실행 속도를 보장해 준다는 점이다.
#include <iostream>
#include <cmath>
using namespace std;

inline double mysqrt(double a, double b)
{
    return sqrt (a * a + b * b);
}
int main()
{
    double k = 6, m = 9;

    // 밑의 2개의 라인은 실행시에 완전히 
    // 동일하게 작동한다.  
    cout << mysqrt(k, m) << endl;
    cout << sqrt(k*k + m*m) << endl;

    return 0;
}
   
inline 인것과 아닌것의 차이를 비교해보고 싶다면, g++ -S 를 이용해서 어셈코드를 얻은다음에 직접 비교 해보기 바란다.

1.9절. 예외처리

당신이 C에서 사용하고 있다면, for, if, do, while, switch 와 같은 키워드들를 알고 있을것이다. C++ 에서는 예외처리(EXECPTION)와 관련된 또다른 키워드들을 제공한다. 선택문 혹은 예외처리를 위한 좀더 직관적이고 손쉬운 프로그래밍 작업을 가능하도록 도와준다.
#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    int age;
    char *no_vote[] = {"없습니다", "있습니다."};

    cout << "당신의 나이는 ? ";
    cin >> age;

    try
    {
        if (age > 18) throw 1;
        else throw 0;
    }
    catch(int result)
    {
        cout << "당신은 투표권이 " <<  no_vote[result] << endl;
    }

    return 0;
}
   

1.10절. default 인자사용 가능

함수의 인자를 사용할때 기본 인자를 설정할수 있다.
  
#include <iostream>
using namespace std;

int mysqrt(int a, int b = 2)
{
    int c = 1;
    for (int i =0; i < b; i++)
    {
        c *= a;
    }
    return c;
}
int main()
{
    cout << mysqrt(5) << endl;
    cout << mysqrt(5, 5) << endl;
}
   

1.11절. Parameters Overload

C++ 의 중요한 잇점중에 하나가 인자를 통한 함수 오버로드가 가능하다는 점이다. 오버로드 기능을 이용함으로써, 서로 다른 연산을 수행하는 함수를 하나의 이름으로 관리 가능 하도록 도와주며, 이는 코드의 유지/보수/가독성을 높여준다.
#include <iostream>

using namespace std;

double add (double a, double b)
{
    return a+b;
}

int add (int a, int b)
{
    return a+b;
}

int main()
{
    cout << add(1, 2) << endl;
    cout << add(1.2, 2.4) << endl;
}
   

1.12절. Operator overload

함수인자를 통한 오버로드 뿐만 아니라, 기본적인 연산자들의 오버로드역시 가능하다. 다시 말해서 연산자의 정의를 다시 내릴수 있도록 한다.
#include <iostream>

using namespace std;
struct vector
{
    double x;
    double y;
};

vector operator * (double a, vector b)
{
    vector r;
    r.x = a * b.x;
    r.y = a * b.y;

    return r;
};

int main()
{
    vector k, m;
    k.x = 2;
    k.y = 4;

    m = 3.141927 * k;
    cout << "(" << m.x << "," << m.y << ")" << endl;

    return 0;
}
   
연산자 오버로는 사칙연산자 외에도 +=, ++, [], (), << 등을 포함한 약 40개 이상의 연산자에 대해서도 가능하다.
#include <iostream>

using namespace std;
struct vector
{
    double x;
    double y;
};

ostream& operator << (ostream & o, vector a)
{
    o << "(" << a.x << "," << a.y << ")" ;
    return o;
}

int main()
{
    vector k;
    k.x = 2;
    k.y = 4;

    cout << k << endl;
    cout << "hello "<< endl;

    return 0;
}
   

1.13절. template

함수 오버로딩이 꽤 편하긴 하지만, 몇가지 불편함이 있다. 즉 인자의 갯수만큼의 함수를 만들어줘야 한다. 만약 int, float, double 연산을 위한 오버로드된 함수를 만들고자 한다면, 거의 똑같은 3개의 함수를 정의해야만 한다. template 를 사용하면 인자의 자료형에 관계없이 사용가능한 (범용한) 함수의 제작이 가능하다.
#include <iostream>

using namespace std;

template <class T>
T mymin (T a, T b)
{
    T r;
    r = a;

    if (b < a) r = b;

    return r;
}

int main()
{
    cout << "Litle is : " << mymin(2, 100) << endl;
    cout << "Litle is : " << mymin(2.6, 2.4) << endl;
}
   
위의 템플릿을 이용한 코드는 꽤 괜찮게 작동하긴 하지만, 한가지 문제가 있다. 위의 코드는 인자의 타입이 동일해야 한다. 만약 인자가 각각 int, double 타입을 가진다면, 컴파일시 에러를 발생시킬것이다. 이문제는 템플릿을 선언할때 서로 다른 인자를 받아들일수 있도록 선언하면 된다.
#include <iostream>

using namespace std;

template <class T1, class T2>
T1 mymin (T1 a, T2 b)
{
    T1 r, converted;

    r = a;

    converted = (T1) b;

    if (converted < a) r =  converted;

    return r;
}

int main()
{
    cout << "Litle is : " << mymin(2, 100) << endl;
    cout << "Litle is : " << mymin(2.6, 2.4) << endl;
    cout << "Litle is : " << mymin(3.4, 3) << endl;
}
   
그외에도 비교연산을 제대로 수행하기 위한 형변환이 필요할 것이다.

google_protectAndRun("ads_core.google_render_ad", google_handleError, google_render_ad);

1.14절. 메모리 할당/해제

메모리 할당과 해제를 위해서 newdelete 키워드를 사용할수 있다. 이들은 C 에서 사용하는 malloc, free 대신 사용할수 있다. 만약 배열의 할당을 원한다면 new[] delete[] 를 사용하면 된다.
#include <iostream>
#include <cstring>

using namespace std;

int main()
{
    int *d;

    // int 형을 포함할수 있는 새로운 메모리 공간확보하고 
    // 주소를 되돌려준다. 
    d = new int;
    *d = 21;

    cout << "Type a number : ";
    cin >> *d;
    cout << *d + 5 << endl;

    // 할당받은 메모리 영역을 해제한다.
    delete d;

    // 15개의 int 형자료를 저장할수 있는 새로운 메모리 
    // 공간을 확보하고, 주소를 되돌려준다. 
    d = new int[15];
    d[0] = 1234;
    d[1] = d[0] + 1234;

    cout << d[0] << ":"<< d[1] << ":" << d[2] << endl;
    delete []d;
    return 0;
}
   

1.15절. Class

간단히 생각해서 Class 란 발전된 형태의 struct 이다. 데이타와 함께, 데이타를 가공할 METHODS 가 선언될수 있다. 다음은 Class 설명을 위한 간단한 예제이다.
#include <iostream>
#include <cstring>

using namespace std;

class vector
{
    public:
        double x;
        double y;

    inline double surface()
    {
        double s;
        s = x*y;
        if (s < 0)
            s = -s;
        return s;
    }
};

int main()
{
    vector a;
    a.x = 3;
    a.y = 4;

    cout << a.surface() << endl;
    return 0;
}
   
위의 예제코드에서 a를 클래스 vector 의 인스턴스(INSTANCE)라고 한다.

1.16절. 생성자 / 소멸자

만들수 있는 메서드 중에는 생성자(Constructor)와 소멸자 (Destructor), 이것들은 인스턴스가 생성되고 소멸될때 자동적으로 호출되는 메서드이다.
생성자는 인스터스의 여러가지 변수를 초기화하거나, 메모리 할당등의 작업을 위해서 쓰인다. 다음은 오버로드된 2개의 생성자를 이용한 셈플코드이다.
#include <iostream>

using namespace std;

class vector
{
    public:
        double x;
        double y;
        vector()
        {
            x = 0;
            y = 0;
        }
        vector(double a, double b)
        {
            x = a;
            y = b;
        }

};

int main()
{
    vector k;
    cout << "vector k: " << k.x << "," << k.y << endl;

    vector m(45, 5);
    cout << "vector m: " << m.x << "," << m.y << endl;

    k = vector (22, 13);
    cout << "vector k: " << k.x << "," << k.y << endl;
}
   
하지만 이미 앞에서 배운 default parameter 을 사용하면, 번거롭게 overload 하지 않고 코드를 단순화 시킬수 있다.
#include <iostream>

using namespace std;

class vector
{
    public:
        double x;
        double y;
        vector(double a = 0, double b = 0)
        {
            x = a;
            y = b;
        }

};

int main()
{
    vector k;
    cout << "vector k: " << k.x << "," << k.y << endl;

    vector m(45, 5);
    cout << "vector m: " << m.x << "," << m.y << endl;

    vector p(5);
    cout << "vector p: " << p.x << "," << p.y << endl;
}
   
소멸자는 그리 필요하지 않는경우가 많다. 보통은 인스턴스가 제대로 종료되었는지 확인하고, 종료될때 어떤 값을 가지고 종료되는지 알고자하는 목적(DEBUG) 으로 많이 사용된다. 그러나 만약 인스턴스에서 메모리 할당을 했다면 (new 나 malloc 로) 인스턴스를 종료시키기 전에 반드시 메모리를 해제(free) 시켜줘야 한다. 이럴경우 소멸자는 매우 유용하게 사용된다.
#include <iostream>

using namespace std;

class person
{
    public:
        char *name;
        int age;

    person(char *n ="no name", int a = 0)
    {
        name = new char[40];
        strncpy(name, n, 40);
        age = a;
    }

    ~person()
    {
        cout << name << " : 40 byte is free : Instance going to be deleted" << e
ndl;
        delete []name;
    }
};

int main()
{
    person me("yundream", 25);
    cout << "name is " << me.name << endl;
    cout << "age is " << me.age << endl;

    person *my;
    my = new person("hello");
    cout << "name is " << my->name << endl;
    cout << "age is " << my->age << endl;
    delete my;
    return 0;
}
   
(할당된 메모리는 free 를 하거나 프로세스가 종료되지 않는한은 커널에 되돌려지지 않는다.)

1.17절. 클래스 메서드의 선언과 정의 분리

만약 메서드를 inline 으로 작성하고 싶지 않다면, 클래스에는 단지 선언만을 포함하게 유지하고, 메서드의 원형을 별도로 관리하도록 할수 있다.
#include <iostream>
using namespace std;

class vector
{
    public:
        double x;
        double y;

        double surface();
};

double vector::surface()
{
    double s= 0;
    for (double i = 0; i < x; i++)
    {
        s = s + y;
    }
    return s;
}

int main()
{
    vector k;

    k.x = 5;
    k.y = 6;
    cout << k.surface() << endl;

    return 0;
}
   
이렇게 분리할경우 inline 에 비해서 약간의 속도저하가 있을수 있겠지만, 유지/보수가 수월해질것이다.

1.18절. 객체의 배열

당연히 객체를 배열로 선언하는 것도 가능하다.
#include <iostream>
#include <cmath>
using namespace std;

class vector
{
    public:
        double x;
        double y;

        vector (double a=0, double b=0)
        {
            x = a;
            y = b;
        }

        double module()
        {
            return sqrt (x*x + y*y);
        }
};

int main()
{
    vector t[3] = {vector(4,5), vector(5,5), vector(2,5)};

    cout << t[0].module() << endl;
    cout << t[1].module() << endl;
    cout << t[2].module() << endl;

    return 0;
}
   

1.19절. 클래스 멤버변수의 static 선언

클래스 맴버변수는 static 로 선언될수 있으며, static 로 선언되었을경우 모든 인스턴스에서 공유해서 사용할수 있다. 단. static 으로 선언된 변수의 초기화는 클래스의 밖에서만 가능하다.
#include <iostream>
#include <cmath>
using namespace std;

class vector
{
    public:
        double x;
        double y;
        static int count;

        vector (double a=0, double b=0)
        {
            x = a;
            y = b;
            count ++;
        }

        ~vector()
        {
            count --;
        }
};

int vector::count = 0;

int main()
{
    cout << "Number of vector : " << endl;
    vector a;
    cout << vector::count << endl;
    vector b;
    cout << vector::count << endl;

    vector *r, *u;

    r = new vector;
    cout << vector::count << endl;
    u = new vector;
    cout << vector::count << endl;

    delete r;
    cout << vector::count << endl;
    delete u;
    cout << vector::count << endl;

    return 0;
}
   
위의 vector 클래스는 count 라는 static 변수를 가지고 있다. 이 변수는 현재 vector 클래스의 인스턴스의 갯수를 계수하기 위한 용도로 사용된다. vector 클래스의 새로운 인스턴스가 만들어지면 count 를 증가하고 인스턴스가 소멸되면 count 를 감소시킴으로써 인스턴스의 갯수를 유지한다.

1.20절. 클래스 멤버변수의 상수선언

클래스 멤버변수가 static 로 선언되는것과 마찬가지로 상수 (constant) 로 선언될수도 있다. 이 변수는 클래스안에서 값이 할당되며, 인스턴스에서 변경될수 없다. 그러나 단지 const 로만 선언했을경우 컴파일러에 따라서 컴파일이 안될수도 있다. 예를들어 gnu 컴파일러의 경우 const static 로 선언해야 될경우가 있다.
#include <iostream>
#include <cmath>
using namespace std;

class vector
{
    public:
        double x;
        double y;
        const static double pi = 3.1415927;

        vector (double a=0, double b=0)
        {
            x = a;
            y = b;
        }

        double cilinder_volume()
        {
            return x*x/4*pi*y;
        }
};

int main()
{
    cout << "pi is: " << vector::pi << endl;
    vector k (3,4);
    cout << "Result: " << k.cilinder_volume() << endl;
    return 0;
}
   

1.21절. this 포인터

클래스에서 각 메서드는 주소에 의한 방식으로 함수를 호출한다. 이렇게 할수 있는 이유는 this 라는 가상의 포인터 때문이다. 클래스에 선언된 모든 메서드는 this 를 명시하지 않더라도 this 가 있는것으로 간주되고 주소에 의해서 함수가 호출된다. 이렇게 하는 이유는 클래스내의 멤버함수를 객체에 의해서 소유하도록 하기 위함이 목적이다. 즉 this 는 보이지 않는 포인터로 객체와 멤버함수를 내부적으로 연결하는 일을 한다.
#include <iostream>
#include <cmath>

using namespace std;


class vector
{
    protected:
        double k;
    public :
        double x;
        double y;
        vector(double a= 0, double b= 0)
        {
            x = a;
            y = b;
        }
        double module()
        {
            cout << "module " <<  x << " : " << y<< endl;
            return sqrt(x*x + y*y);
        }

        void set_length(double a = 1)
        {
            double length;
            length = this->module();

            x = x/length *a;
            y = y/length *a;
        }
};


int main()
{
    vector a(3,5);
    cout << "--> " << a.module() << endl;
    a.set_length(2);
    cout << "--> " << a.module() << endl;
    a.set_length();
    cout << "--> " << a.module() << endl;
}
   

1.22절. 상속

클래스는 다른 클래스로 부터 파생(Derived)될수 있다. 이 새로운 클래스는 원본클래스의 메서드와 변수를 상속 (Inherits) 받게 된다. 이렇게 해서 파생된 클래스는 새로운 메서드와 변수들을 추가함으로써 확장시켜 나갈수 있게 된다.
 
#include <iostream>
#include <cmath>
using namespace std;
    
// 원본 클래스
class vector
{
    public:
        double x;
        double y;
        const static double pi = 3.1415927; 

        vector (double a=0, double b=0)
        {
            x = a;
            y = b;
        }

        double surface()
        {
            return x * y;
        }
};

// vector 로부터 파생된 새로운 클래스
// 원본 vector 클래스의 표면적을 구하는 작업외에 
// 체적을 구하는 작업을 할수있도록 확장되었다. 
class trivector: public vector
{
    public :
        double z;

        // trivector 생성자가 호출되기 전에
        // vector 생성자가 호출되어서 m, n 인자를 
        // 초기화 한후, 거기에 3차원 지원을 위해서 p 가 
        // 초기화 된다.  
        trivector(double m =0, double n =0, double p=0): vector(m,n)
        {
            z = p;
        }

        // 또다른 생성자로 만약에 2차원 정보가 
        // 들어왔을경우 3차원으로 변경한다.  
        trivector(vector a, double p = 0)
        {
            x = a.x;
            y = a.y;
            z = p;
        }

        // 3차원 데이타를 이용해서 체적을 구한다. 
        // surface()메서드를 호출해서 표면적을 구하고 
        // 거기에 높이인 z 를 곱해주면 된다. 
        double volume()
        {
            return this->surface() * z;
        }
};

int main()
{
    vector a(4, 5);
    trivector b(1, 2, 3);
    trivector c(a);

    cout << "surface a: " << a.surface() << endl;
    cout << "volume  b: " << b.volume() << endl;
    cout << "surface b: " << b.surface() << endl;
    cout << "volume  c: " << c.volume() << endl;

    trivector d(a,5.8);
    cout << "volume  d: " << d.volume() << endl;
}
   

1.23절. 다중상속

바로 위에서 상속에 대해서 알아봤는데, C++ 은 1개 이상의 클래스로 부터 상속받는 것도 가능하다. 그러나 다중상속을 이용해서 클래스를 만들경우 나중에 유지/보수가 곤란해지는 문제가 생길수 있음으로, 대체적으로 다중상속은 지양하는 추세이다.
#include <iostream>
#include <cmath>
using namespace std;

// 원본 클래스
class vector
{
    public:
        double x;
        double y;
        const static double pi = 3.1415927;

        vector (double a=0, double b=0)
        {
            x = a;
            y = b;
        }

        double surface()
        {
            return x * y;
        }
};

class height
{
    public :
        double z;
        height (double a)
        {
            z = a;
        }

        int is_negative()
        {
            if (z < 0) return 1;
            else       return 0;
        }
};

class trivector: public vector, public height
{
    public :
        trivector(double a= 0, double b=0, double c=0): vector(a,b), height(c)
        {
        }
        double volume()
        {
            return fabs(x* y* z);
        }
};

int main()
{
    trivector a(2, 3, -5);

    cout << a.volume() << endl;
    cout << a.surface() << endl;
    cout << a.is_negative() << endl;
}
   

1.24절. 캡슐화(은닉)

아마 당신이 C++ 을 처음접해 보았다면, 위의 코드에서 public: 라고 하는 생소한 키워드를 보았을것이다. 이것은 C++ 에서 새로추가된 키워드로 메서드나 멤버변수에 엑세스레벨을 부여하게 된다.
public: 는 프로그램어디에서든지 엑세스 할수 있음을 나타낸다. 이것은 원본클래스와 파생클래스에게 모두 동일하게 적용된다.
private: 는 단지 원본 클래스의 메서드를 통해서만 접근이 가능하다.
protected: private 와 비슷하게 클래스 메서드를 통해서만 접근이 가능하지만, private 와는 달리 원본뿐 아니라 파생된 클레스에서의 접근도 가능하다.
#include <iostream>
#include <cmath>

using namespace std;


class vector
{
    private:
        double x;
        double y;
    public :
        double surface()
        {
            return x * y;
        }
};

int main()
{
    vector b;
    b.x = 2; // 컴파일 에러발생
    b.y = 3; // 컴파일 에러발생
}
   
위의 경우 c++ 컴파일러로 컴파일할경우 `double vector::x' is private 와 같은 에러메시지를 출력하고 컴파일 중지된다. vector 클래스의 멤버변수 x, y 는 private 로 선언되어 있음으로 단지 현재 클래스의 메서드를 통해서만 접근가능하기 때문이다. 이럴경우 x, y 입력을 위한 전용 메서드를 하나 만들어야 할것이다.
#include <iostream>
#include <cmath>

using namespace std;


class vector
{
    private:
        double x;
        double y;
    public :
        double surface()
        {
            return x * y;
        }
        void input(double a, double b)
        {
            x = a;
            y = b;
        }
};

int main()
{
    vector b;
    b.input(11, 40.5);
    cout << b.surface() << endl;
}
   

1.25절. 가상함수

원본클래스에서 파생된 새로운 클래스는 원본 클래스의 메서드와 멤버변수를 상속받는다는 것을 배워서 알고 있다. 그런데 이런경우를 생각할수 있을것이다. vector 에 module 란 메서드가 있는데, 이 메서드는 다음과 같다.
double module()
{
    return sqrt(x*x + y*y); 
}
   
만약 vector 에서 파생된 trivector 이란 클래스를 선언했다면, trivector 클래스는 vector->module() 를 상속받게 될것이다. 그러나 trivector 의 경우 sqrt 연산을 할때 3차원 데이타를 가지고 연산을 해야 할것이다.
double module()
{
 return sqrt(x*x + y*y + z*z);
}
   
이처럼 메서드를 상속받았을때, 상속받은 메서드의 연산방식이 변경될경우 virtual 로 선언하면 된다.
#include <iostream>
#include <cmath>

using namespace std;


class vector
{
    public :
        double x;
        double y;
        virtual double module()
        {
            return sqrt(x*x + y*y);
        }
};

class trivector: public vector
{
    public :
        double z;

    trivector(double m=0, double n=0, double p=0)
    {
        x = m;
        y = n;
        z = p;
    }

    double module()
    {
        return sqrt(x*x + y*y + z*z);
    }
};

int main()
{
    trivector b(2,3,4);
    cout << b.module() << endl;
}
   

1.26절. 파일스트림 처리

C++ 은 파일처리를 위한 매우 간단한 방법을 제공한다. 다음은 파일을 읽기 위한 코드이다.
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    fstream f;
    char c;

    f.open("seek3.c", ios::in);
    while (! f.eof())
    {
        f.get(c);
        cout << c;
    }

    f.close();

    return 0;
}
   
다음은 파일에 쓰기 위한 코드이다.
#include <iostream>
#include <fstream>
#include <cstdio>
using namespace std;

int main()
{
    fstream f;
    f.open("text.txt", ios::out);

    f << "Hello world " << endl;

    f.close();
    return 0;
}
   

1.27절. 정형화된 출력

보통 표준 C 언어에서는 printf 를 이용해서 정형화된 출력을 수행한다. C++ 에서는 width() 와 setw()를 이용해서 정형화된 출력을 한다. 이것들은 단지 가장최근의 출력에만 영향을 미친다.
#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    for (int i = 1; i <= 1000; i *=2)
    {
        cout.width(7);
        cout << i << endl;
    }
    for (int i = 0; i <=10 ;i ++)
    {
        cout << setw(3) << i << setw(5) << i * i * i << endl;
    }
    return 0;
}
   

1.28절. 문자배열을 file 처럼이용하기

좀 이상하게(혹은 쓸모없는 것처럼) 들릴수 있겠지만, 문자배열을 파일처럼 연산하는게 가능하다. 이것은 파일 스트림과 메모리를 연결해서 사용하는 프로그래밍 기법을 가능하도록 해준다.
#include <iostream>
#include <cmath>
#include <cstring>
#include <strstream>

using namespace std;

int main()
{
    char a[1024];
    ostrstream b(a, 1024);

    b.seekp(0); // 스트림의 첫번째로 이동 
    b << "2+2 = " << 2+2 << ends; // ends 임에 주의
    cout << a << endl;

    double v = 49;
    strcpy(a, "A sinus: ");

    b.seekp(strlen(a));
    b << "sin (" << v << ") = " << sin(v) << ends;
    cout << a << endl;
}
   
#include <iostream>
#include <cmath>
#include <cstring>
#include <strstream>

using namespace std;

int main()
{
    char a[1024];
    istrstream b(a, 1024);

    strcpy(a, "45.656");
    double k, p;

    b.seekg(0);
    b >> k;

    k = k+1;
    cout << k << endl;

    strcpy(a, "444.23 56.89");
    b.seekg(0);
    b >> k >> p;

    cout << k << ", " << p + 1 << endl;
    return 0;
}

출처 : http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/C%2B%2B/Documents/CPP_Programing_for_Cprogramer