2011년6월17일_문자열에서 토큰(token, 어휘)뽑는 함수 strtok( )를 사용해 보자.
★ 창의성 = 기존방식 + 찾아낸 것 ★ 처음부터 찾는 것은 만용(蠻勇)이다. |
어제 연습하였던 문자열을 어휘단위로 분해해 출력하는 Code에서 strncpy( )대신에 API함수를 사용하여 보자.
(병도햄 & 세선氏 소스코드 + Text배열의 열번호추가)
1: // API함수 strtok()를 사용해 문자열을 token(어휘)단위로 분해해 출력
2: #include <stdio.h>
3:
4: int main()
5: {
6: char Text[] = "This is a ATmega";
7: char *p;
8: char *p2 = Text;
9:
10: p = (char *)strtok(Text, " ");
11:
12: while(NULL != p)
13: {
14: printf("%d %s\n", p - Text, p);
15:
16: p = (char *)strtok(NULL, " ");
17: }
18:
19: return 0;
20: }
신기하게 string.h를 전처리하지 않아도 잘 된다.
1: //stdio.h에 정의된 NULL
2: #ifndef NULL //NULL이 정의되어 있지 않으면,
3: #define NULL ((void *)0) //void포인터로 캐스팅된 0번지? 0번지 = 0이고 void포인터이니 어떤 자료형과도 궁합이 잘 맞는다.
4: #endif
NULL이 어디에 정의되어 있는지 알아보니 친숙한 stdio.h에 정의되어 있다.
조건부컴파일문 #ifndef은 상기와 같이 사용하면 되고,
#ifndef와 #endif사이에 하나의 명령문뿐만 아니라 여러 줄을 넣을 수도 있다.
조건부컴파일문(전처리)을 잘 사용하면 기존의 Code를 일일이 수정할 필요 없이 새로운 프로젝트에 적용이 가능하니 꼭 알아 둘 것.
strtok( )함수가 어떤 함수인지 알아 보기 위해 linux manual (man page)를 보자…
아래와 같이 터미널에서 명령문을 입력하면,
# man strtok
//여기부터 man page내용 시작
● 사용법
#include <string.h>
char *strtok(char *s, const char *delim);
● 토큰(Torken)이란 문자열 delim(구분문자)에 없는 문자들의 비어 있지 않은 문자열이며 ‘\0’이나 delim에 있는 문자가 뒤따른다.
strtok( )함수는 문자열s를 파싱하기 위해...
처음 호출은 처음인자에 s(문자열을 저장할 배열)를 넣고,
연속적인 호출은 처음인자를 NULL로 설정해야 한다.
각 호출은 다음 토큰에 대한 포인터를 반환하거나 더 이상 토큰이 발견되지 않는다면 NULL을 반환한다.
● 토큰이 구분자로 끝난다면, 이 구분자는 ‘\0’로 겹쳐지며,(구분자가 들어 있는 공간에 NULL문자(‘\0’)가 들어감.)
다음 문자에 대한 포인터가 strtok( )에 대한 다음 호출을 위해 저장된다. (static(정적변수)를 사용한 것 같다.)
구분 문자열 delim는 각 호출시 다를 수 있다.
● strtok( )의 버그
이 함수를 사용해서는 안 된다. (그럼 왜 만들었지? –_-;) 만일 여러 분이 사용한다면 다음을 주의할 것...
① 이 함수는 처음 인자를 수정한다. (원본이 변형된다. 구분문자대신에 NULL문자가 들어가므로)
② 구분자의 원본은 잃게 된다. (이 부분은 잘 이해가 가지 않으나 배열을 선언하여 두 번째 인자에 넣는 실험을 하면 될 것이다.)
③ 이 함수는 상수 문자열에서는 사용해서는 안 된다. (const char *형은 상수이므로 수정하면 에러다.)
④ strtok( )함수는 파싱하는 동안 정적버퍼를, (한정된 크기의 배열인가? 문자열을 임시로 담을 공간을 확보하는데 크기를 알 수 없음?)
사용한다. 그래서 thread safe가 아니다.
만일 이것이 문제라면 strtok_r( )를 사용하라.
● 반환값
strtok( )는 다음 토큰에 대한 포인터를 반환하거나 만일 토큰이 없다면 NULL을 반환한다.
//여기까지 man page내용 끝
상기의 그림을 보면 원본 문자열 “This is a ATmega”에서,
”This”
”is”
”a”
”ATmega” 이렇게 순서대로 4개의 token으로 분해된 다는 것을 알 수 있다.
① 첫 번째 호출할 때는 문자열이 들어간 배열s의 시작주소를 넘겨주고 반환값으로 다음 token이 시작주소를 받는다.
② 두 번째 부터 네 번째까진 처음 호출시 배열s의 시작주소를 넘겨주었으므로 이번엔 NULL을 인자로 넘겨준다.
○ 만약 구분문자대신 NULL문자(‘\0’)를 만났을 경우엔 문자열의 끝이라 다음 token이 없으므로 NULL값을 반환한다.
'내장형하드웨어 > 일일보고서' 카테고리의 다른 글
2011년6월17일_C언어 변수선언과 대입한 코드를 disassembly하여 데이터이동명령에 대해 자세히 알아보자. (0) | 2011.06.20 |
---|---|
2011년6월17일_const(상수, 읽기전용), 어떤 메모리영역에 위치해 있나? (0) | 2011.06.20 |
2011년6월16일_ATmega128 Datasheet page.23까지(칩의 스펙, Block Diagram, AVR CPU core, Memory(Flash + SRAM + EEPROM)) (0) | 2011.06.17 |
2011년6월16일_문장을 어휘단위로 분해하기(문자열을 token단위로 잘라내기) (0) | 2011.06.17 |
2011년6월15일_어셈블리어로 작성된 코드(함수, 프로시저)를 C코드에서 호출 (0) | 2011.06.16 |