c++ strtok

프로그래밍/C/C++ 2014. 12. 13. 16:08


1
2
3
4
5
6
7
8
9
    char s[] = "Hello world good day to die";
    // strtok => "Hello\0world\0good\0day\0to\0die" 으로 변경됨
 
    for (char *p = strtok(s, " "); p != 0; p = strtok(0, " "))
    {
        printf("%s\n", p);
    }
 
    printf("%s\n", s);


'프로그래밍 > C/C++' 카테고리의 다른 글

스마트 포인터  (0) 2014.11.28
메모리 관리 함수(memset, memcpy, memmove)  (0) 2014.10.24
C++ 파일 입출력  (0) 2014.02.24
함수 주요 형태(_stdcall, _cdecl, _fastcall)  (0) 2014.02.24
비트 연산자  (0) 2014.02.12

스마트 포인터

프로그래밍/C/C++ 2014. 11. 28. 03:31

동적 메모리 할당 과 해제에서 개발자의 실수로 메모리 누수(memory leak) 등이 발생하는 확률이 높다.

프로그램 규모가 커질수록 클래스의 내부 멤버들이 많아지고, 이를 동적 메모리로 할당해서 관리하면,

new와 delete를 자주 사용하게 된다. new로 할당받은 객체속 메모리는 반드시 delete로 해제하여야 한다.

그렇지 않으면 메모리 누수가 발생하게 된다.


C++11 표준에서 소개하는 스마트 포인터를 사용하면 편리하게 메모리 누수를 관리할 수 있다.


예제1. 스마트포인터 auto_ptr 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <memory>
#include <string>
using namespace std;
 
class food
{
    string name; // 이름
    int price; // 가격
 
public:
  // 생성자
    food(string _name, int _price){        
        this->name = _name;
        this->price = _price;
        cout << "생성자 호출" << endl;
    }
  // 소멸자
    ~food() {
        cout << "소멸자 호출" << endl;
    }
  
  // 정보 출력
    void printData() {
        cout << "name = " << this->name << ", price = " << this->price << endl;
    }
};
 
int main()
{
    auto_ptr<food> test(new food("apple", 30));
    test->printData();
    return 0;
}


결과


스마트 포인터 auto_ptr를 이용한 동적메모리 할당에서는 개발자가 따로 delete를 하지 않아도 

소멸자를 호출하면서 할당된 메모리를 자동으로 해제한다.


만약 동일 객체를 두 개의 포인터로 가리키게 하면 두 개의 포인터 각각의 메모리를 해제하였을 때,

중복으로 메모리를 해제하는 경우가 발생해 오류가 발생하게 된다.


메모리를 자동으로 해제해 주는 auto_ptr를 사용하면 편리하지만 한편으로는 개발자에게 매우 위엄한 상황이

발생되기도 한다. 엄밀히 말하면 C++11 표준에서는 auto_ptr 사용을 권고하지 않는다. 그렇다면 해결책이 없는것일까?


이 경우 unique_ptr를 사용하면 된다.


unique_ptr는 C++11 표준에서 사용할 수 있는 스마트 포인터이다.

unique_ptr는 auto_ptr와 유사하게 가리키는 객체의 소유권을 그대로 강조하지만, 메모리 중복 해제로

인한 런타임 오류가 발생하지는 않는다. 컴파일러가 미리 이런 오류를 처리해 준다.


unique_ptr를 사용하여 어느 정도 스마트 포인터의 요구 사항을 충족하긴 했지만, 

하나의 객체를 여러 스마트 포인터로 가리키길 원할 수 있다.

이 경우 컴파일 타임이나, 런타임에서 오류 없는 스마트 포인터를 C++11에서 제공한다.

shared_ptr라는 스마트 포인터를 사용하면 된다.




'프로그래밍 > C/C++' 카테고리의 다른 글

c++ strtok  (0) 2014.12.13
메모리 관리 함수(memset, memcpy, memmove)  (0) 2014.10.24
C++ 파일 입출력  (0) 2014.02.24
함수 주요 형태(_stdcall, _cdecl, _fastcall)  (0) 2014.02.24
비트 연산자  (0) 2014.02.12

메모리 관리 함수(memset, memcpy, memmove)

프로그래밍/C/C++ 2014. 10. 24. 00:19

메모리 관리 함수

메모리 관리함수는 문자열에 제한하지 않고 , 메모리에 할당된 값을 직접적으로 바꾸기 때문에 자료형에 상관없이 

사용할수있다몇몇 메모리 관리함수는 문자열 함수와 기본적인 동작 방식은 비슷하다. 하지만 다음과 같은 

차이점이 있다.

1. 인수와 리턴값의 타입이 다르다. 메모리 관리 함수는 거의 대부분 void *형태이다

    메모리의 바이트 단위로 작업을 하기때문에 자료형을 몰라도 되기 때문이다.

2. 문자열은 끝을 알리는 NULL 때문에 최대값 범위를 따로 지정안해줘도 되는 함수가 있었지만

    메모리는 어디까지 작업해야하는지 알려줘야하기 때문에 count 라는 인수를 써야한다.


memcpy(메모리 복사) 


1
void *memcpy(void *dst, const void *src, size_t count);

memcpy는 두 메모리의 값을 복사할때 사용한다. 복사될 대상의 주소 (매개변수1) , 복사할 대상의 주소(매개변수2) , 

그리고 복사할 크기(매개변수3) 을 써준다면 src의 값이 dstcount 만큼 복사될것이다. 배열은 요소끼리 개별적으로 

대입해야하는데 , memcpy는 메모리에 값을 바로 주소값으로 전달해서 복사하기때문에 바로 대입이 된다.


또한 memcpy는 대응되는 바이트 끼리 기계적으로 복사하기때문에 대상의 논리적인 구조는 무시한다

구조체 배열도 memcpy를 통해서 복사할수있다 .

  

memset(메모리 초기화 및 설정)


1
void *memset(void *dst, int c, size_t count);

memset은 보통 선언과 동시에 배열 초기화를 하지 않았을때, 혹은 실행중 특정값으로 바꾸고싶을때 사용한다.

사용법은 우선 *dst 에 복사될 대상의 주소 (매개변수1) 넣어주고, int c(2번째 매개변수) 에 바꿀 값(보통은 초기화 시

킬값), count*dst의 사이즈를 넣어주면 된다.

그러면 dst 의 시작 주소로 부터 count 만큼의 메모리 (보통은 count sizeof(dst)식으로 넣어서 값을 지정)가 전부 

int c 로 변한다.

 

memmove(메모리 이동)


1
void *memmove(void *dst, const void *src, size_t count);

 

memmove 는 메모리의 내용을 지정한 만큼 다른곳으로 옮긴다. 이 함수를 사용하면 배열 중간을 뒤쪽으로 밀어서 

빈공간을 만든후 그 공간에 다른 내용을 삽입해 넣을수도 있다

dst 에 이동할 위치 . src 에 이동대상의 시작점 , count 에 움직일 대상의 크기(문자열이면 NULL문자를 포함하자) 를 

적는다. (dst - src = 넣을 대상의 크기가 된다.)

 

'프로그래밍 > C/C++' 카테고리의 다른 글

c++ strtok  (0) 2014.12.13
스마트 포인터  (0) 2014.11.28
C++ 파일 입출력  (0) 2014.02.24
함수 주요 형태(_stdcall, _cdecl, _fastcall)  (0) 2014.02.24
비트 연산자  (0) 2014.02.12

C++ 파일 입출력

프로그래밍/C/C++ 2014. 2. 24. 05:22

파일 클래스는  ifstream, ofstream, fstream으로 지정할수 있고, 개방 모드로는 입출력 동작 모드를

지정하는 ios::in, ios::out등을 사용한다.



의 미 

 in

파일 입력(파일 읽기) 

 out

 파일 출력(파일 쓰기)

 ate

 파일 개방 후, 파일 끝으로 이동

 app

 파일 추가(append)

 trunc

 존재하는 파일 제거(truncate)하고 새로운 파일로 연다

 binary

 텍스트(text)가 아닌 바이너리(binary)로 출력


  

☞ 파일 입출력 간단히 소개

//"data.in" 파일을 입력 파일로 개방

ifstream infile("data.in", ios::in);

 

//"data.out" 파일을 출력 파일로 개방

ofstream outfile("data.out", ios::out);

 

//"myfile.dat" 파일을 입출력 상태로 개방

fstream myfile("myfile.dat", ios::in | ios::out);

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
 
int main()
{
   ofstream fo("test.dat");
   
   if(!fo) {
      cout << "파일 열기 실패!\n"
      exit(1);
   }
   
   fo << "Hello!\n";
   fo << 123 << " " << hex << 123 << endl;
   fo.close();
 
   ifstream fi("test.dat");
 
   if(!fi) {
      cout << "파일 열기 실패!\n";
      exit(1);
   }
 
   char s[81];
   int n;
   fi >> s >> n;
   cout << s << " : " << n << endl;
   fi.close();
 
   return 0;
}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
 
int main()
{
    char ch;
    ifstream fin;
    
    fin.open("test.dat");
    if(!fin) {
       cout << "파일 열기 실패\n";
       exit(1);
    }   
    
    fin.unsetf(ios::skipws); // skipws 형식 플래그 클리어, 공백 문자도 입력
    while(!fin.eof()) { // 파일 끝이 아니면
        fin >> ch;
        if(ch == ' ')
          ch = '%';
        cout << ch;
    }
 
    return 0;
}

 

※결과

파일에 test.dat에 다음과 같은 내용이 저장되었을때

Hello, everybody  !

This is a test file test.dat

 

공백마다 %가 출력됨

Hello%everybody%% !

This%is%a%test%file%test.dat

 

'프로그래밍 > C/C++' 카테고리의 다른 글

스마트 포인터  (0) 2014.11.28
메모리 관리 함수(memset, memcpy, memmove)  (0) 2014.10.24
함수 주요 형태(_stdcall, _cdecl, _fastcall)  (0) 2014.02.24
비트 연산자  (0) 2014.02.12
함수 포인터  (0) 2014.02.12

함수 주요 형태(_stdcall, _cdecl, _fastcall)

프로그래밍/C/C++ 2014. 2. 24. 04:51

1. _cdecl

C 또는 C++ 프로그램에서 파라미터 전달시 디폴트로 사용

파라미터 전달은 오른쪽에서 왼쪽 방향으로 스택에 저장

파라미터 해제는 프로시저를 호출한 것이 책임짐(스택정리)

 

 

2. _stdcall

Windows API 프로시저에서 사용

파라미터 전달은 _cdecl과 동일

파라미터 해제는 프로시저 복귀 전에 이루어짐

장점

- 함수 독립성이 뛰어남

- 프로시저를 부르기 전에 스택에 파라미터를 쌓아놓고 그 프로시저를 부르기만 하면 그 함수가 리턴된 후에는 그 프로시저의 스택 포인터가

이전 상태로 복원되었으므로 복귀된 후에 호출한 프로시저에 대하여 신경쓸 필요가 없음.

- _cdecl 방식의 콜링컨벤션에 비해 코드 크기가 줄어든다.

- 스택을 해제하는 코드가 호출한 프로시저 안에 있으므로 이 프로시저가 여러 곳에서 호출된다 할지라도 스택 해제하는 코드는

프로시저 내에 하나만 존재함

 

 

3. _fastcall

처음 두 개까지의 파라미터는 스택을 사용하지 않고, ecxedx 레지스터를 사용함

그 이상의 파라미터에 대해서만 오른쪽에서 왼쪽으로 스택에 저장

스택 제거는 _stdcall과 동일

 

'프로그래밍 > C/C++' 카테고리의 다른 글

메모리 관리 함수(memset, memcpy, memmove)  (0) 2014.10.24
C++ 파일 입출력  (0) 2014.02.24
비트 연산자  (0) 2014.02.12
함수 포인터  (0) 2014.02.12
[STL]컨테이너 선택  (0) 2014.02.09

비트 연산자

프로그래밍/C/C++ 2014. 2. 12. 14:17

비트 연산자의 필요성

8개의 LED조명을 제어하기 위한 프로그램을 생성한다고 할때

  enum {LED0 = 0, LED1, LED2, LED3, LED4, LED5, LED6, LED7};

  enum {LED_OFF = 0, LED_ON = 1};

  char mmio[8] = {0, }; // 8개의 배열을 만든뒤

  mmio[LED1] = LED_ON; //LED1의 조명 ON

  mmio[LED3] = LED_OFF; //LED3의 조명 OFF 

로 조명을 제어 할수 있습니다.

하지만 이 부분에서의 문제점은 총 8개의 비트(0, 1)만으로 충분하지만, 사용 메모리 크기는 8비트 * 8개(64비트)

공간을 할당하여 사용하고 있다는 것입니다. 각 char형의 1비트 밖에 사용하지 않고 7비트트 * 8개(56비트)의

공간이 낭비되고있는 문제점입니다.

 

이 문제를 해결하기 위해서는 8비트를 사용하여 8개의 LED를 제어하는 방법을 사용하여야합니다.

char 형의 문자형을 하나 사용하여 8비트(1바이트) 공간을 사용하는 방법을 소개합니다.

이 문제를 해결하기 위해서는 비트연산자를 활용해 각 비트의 연산이 필요합니다.

 

1. AND연산

 

 

AND연산은 위 그림과 같이 1과 1이 입력될때만 1이 출력되고 그 외의 연산은 0이 출력되는 게이트를 말합니다.

 

2. OR연산

 

 

 

OR연산은 위 그림과 같이 0과 0이 입력될때만 0이 출력되고 그 외의 연산은 1이 출력되는 게이트를 말합니다.

(입력 게이트로 하나라도 1이 포함되면 1이 출력)

 

3. NOT연산

NOT연산은 위 그림과 같이 0을 NOT연산자를 취하면 1이 출력되고, 1을 NOT연산자를 취하면 0이 출력됩니다.(반대로 출력)

 

4. SHIFT 연산

  데이터 << 이동할 비트 수

 데이터 >> 이동할 비트 수

 

SHIFT연산은 메모리 상을 비트 단위로 이동하는 것을 말합니다. 데이터를 비트 단위로 좌, 우로 이동하는

기능을 합니다.

규칙1. 특정 비트를 설정하려면 OR연산자를 사용합니다.

 char mmio = 0; // 0000 0000

규칙2. 특정 비트를 검색하려면 AND연산자를 활용합니다.

규칙3. 특정 비트를 초기화하려면 &연산자와 비트 반전 연산자(~, NOT)을 사용합니다.

 

 

 

 

'프로그래밍 > C/C++' 카테고리의 다른 글

C++ 파일 입출력  (0) 2014.02.24
함수 주요 형태(_stdcall, _cdecl, _fastcall)  (0) 2014.02.24
함수 포인터  (0) 2014.02.12
[STL]컨테이너 선택  (0) 2014.02.09
[STL] 제네릭 알고리즘 Generic Algorithm  (0) 2014.02.09

함수 포인터

프로그래밍/C/C++ 2014. 2. 12. 04:22

우리가 알고있는 일반적인

함수의 선언은 리턴타입 (함수명 ([파라미, ...])) 형식을 갖습니다.

함수의 포인터 선언 방법은 함수의 심볼은 반드시 리턴 타입과 매개변수 사이에 위치해야 합니다.

함수의 포인터 선언은 리턴타입 (*포인터명) ([파라미터, ...]) 형식을 갖습니다.(괄호 필수,

미괄호시 파라미터 부터 해석해서 리턴타입을 리턴타입을 포인터로 리턴하는 함수로 인식합니다.)

함수호출, 함수의 포인터 호출 방법은 아래와 같습니다.

 


하지만 이러한 방법은 매우 복잡합니다. 함수의 포인터 호출 방법을 아무도 사용하지 않을 것입니다.

하지만 전처리기 #define문을 사용해 함수의 포인터를 간단히 치환할수 있습니다.

 

출력 결과

 called foo(10);

 called foo(10);

 called foo(10);

 called foo(10);

 

위의 주석으로 처리된 함수 포인터는 #define선언된 함수의 포인터 타입으로 변경되어 간단히 사용할수 있습니다.

[STL]컨테이너 선택

프로그래밍/C/C++ 2014. 2. 9. 14:12

컬렉션 내의 값들을 어떤 방식으로 접근하는가에 따라 컨테이너 선택이 달라져야 합니다.

 

▶ 컬렉션 내에 임의 접근이 자주 필요할시

    vector와 deque를 사용하고, 순차접근만으로 충분하다면 다른 컨테이너를 써도 무방합니다.

 

▶ 컬렉션 내의 값들을 순서 매길 필요가 있을시

    Set을 사용하는게 좋습니다. 매순간 순서가 필요없고 특정 순간에 필요하다면 list혹은 vector에 값을 대입하고 필요시

    정렬하는 방법을 사용하는 것이 좋습니다.

 

▶ 데이터 구조 내에서 유지되는 값들의 순서가 필요할시

     stack이나 list를 선택하는것이 좋습니다.

 

▶ 실행중에 데이터 구조가 광범위 하게 변활시

    list와 set을 선택하는 것이 좋습니다.  vector, deque는 컬렉션으로 부터 원소들을 제거한 뒤에 데이터 이동이

    이루어지기 때문에 부하의 원인이 됩니다.

 

▶ 어떤 값이 컬렉션 내에 포함되어 있는지 확인하는 빈도가 높으시

    set이나 map을 선택하는 것이 좋습니다.

 

▶ 컬렉션에 대해 인덱싱이 필요할시

    vector, deque를 사용하고, 키 값이 어떤 순서가 있는 데이터 형이라면(문자, 문자열, 사용자 정의 데이터 타입)

    map을 사용합니다.

 

▶ 두개 이상의 수열을 하나로 합치는 일이 자주 발생할 경우

    set이나 list가 유용합니다. 어떤 것을 선택할지는 순서가 유지되는가의 여부에 따라 결정하는 것이 좋습니다.

 

▶ 컬렉션 중간에서 데이터 삽입, 삭제가 자주 이루어질시

    list가 최선의 선택이며, 앞쪽에서 삽입된다면, deque , list 끝에서 삽입과 삭제가 이루어진다면 stack, deque를 사용하는 것이 좋습니다.

'프로그래밍 > C/C++' 카테고리의 다른 글

비트 연산자  (0) 2014.02.12
함수 포인터  (0) 2014.02.12
[STL] 제네릭 알고리즘 Generic Algorithm  (0) 2014.02.09
[STL] 정렬 컨테이너1 (set, multiset, map, multimap)  (0) 2014.02.09
[STL] 제네릭(generic) 기초 정리  (0) 2014.02.09

[STL] 제네릭 알고리즘 Generic Algorithm

프로그래밍/C/C++ 2014. 2. 9. 04:29

Generic Algorithm이란 컨테이너에 대해서 적용할 수 있는 기능들을 체계적으로 정리해놓은 함수를 말합니다. 일반적이

기 때문에, 특정 컨테이너에 종속된 것이 아니라 모든 컨테이너에서 사용할수 있습니다. 알고리즘 함수들은 특정 컨테이

너의 멤버 함수가 아닌 일반 전역 함수로 작성되어 있습니다.

 

  ☞ find 예제

 

  ☞ copy 예제

 

  ☞ sort 예제

  ☞ reverse 예제

 reverse_copy를 사용하면, reverse대상은 그대로 두고 복사시킬수 있습니다.

 → reverse_copy(vec1.begin(), vec1.end(), 참조 객체 );

 

 

[STL] 정렬 컨테이너1 (set, multiset, map, multimap)

프로그래밍/C/C++ 2014. 2. 9. 04:01

▶ STL-Set, Multiset

 Set은 key만을 저장하는 자료구조 입니다.

 Set은 중복되지 않은 key를 저장합니다.(multiset은 중복되지 않은 key를 저장-중복 허용)

 Set에 값을 한번 넣어보는것 만으로 중복된 값이 있는지 찾을수 있습니다.

 

  ☞ Set함수의 생성

    Set<int> a; //오름 차순 정렬

    Set<int, greater<int>> a; //내림차순으로 정렬

    Set<int> a(List.begin(), List.end()); //List를 미리 넣음

    Set<int, greater<int>> a(List.begin(), List.end());

 insert문을 통해 해당 타입에 맞는 값을 넣을수 있습니다.

 find문을 통해 특정 값을 인자로 취해서 set내에 값이 존재하면 그 값의 위치를 반복자를 리턴합니다.

 (없을시 end of set을 리턴)

 

▶ STL-Map, Multimap

 Map은 key와 value 정보를 가지고 있는 자료구조 입니다.

 Multimap은 같은 key로 인덱싱 되는 여러개의 다른 원소를 허용합니다.

 

 Map은 vector나 deque와 같이 인덱싱이 가능합니다.

    map<int, int> myMap;

    myMap.insert(map<int, int>::value_type(5, 7);

    myMap[5] = 7;

    cout << myMap[5];  // -> 7

 Map과 deque, vector 의 차이는 key값이 꼭 숫자일 필요가 없다는 것입니다.

 또한 Map은 정렬된 데이터의 구조를 가지고 있습니다(Tree, hash)

 set과 마찬가지로 insert를 통해 해당 타입에 맞는 값을 넣을수 있습니다.(인덱싱)

 find문을 통해 특정 값을 인자로 취해서 map내에 값이 존재한다면 그 위치를 나타내는 반복자를 리턴합니다.

 (없을시에는 end에 해당하는 반복자를 리턴)