size_t Strlen(const char* sz)
{
size_t len = 0;
while (*(sz++))
++len;
return len;
}
char* Strcpy(char * dest, const char * sour)
{
char* temp = dest;
while (*(temp++) = *(sour++));
return dest;
}
char* Strncpy(char *dest, const char *sour, size_t count)
{
for (size_t i = 0; i < count; ++i)
dest[i] = sour[i];
return dest;
}
//strncpy_s는 count개의 문자를 복사하다가 dest의 크기 SIZE를 넘어서면 assert를 던진다.
template <size_t SIZE>
char* Strncpy_s(char (&strDest)[SIZE], const char* strSource, size_t count)
{
for (size_t i = 0; i < count; ++i)
{
assert((i < SIZE));
strDest[i] = strSource[i];
}
return strDest;
}
char * Strcat(char * strDest, const char * strSource)
{
size_t destLen = strlen(strDest);
Strcpy(strDest + destLen, strSource);
return strDest;
}
int Strcmp(char* str1, char* str2)
{
while (*str1 || *str2)
{
if (*str1 < *str2) return -1;
else if (*str1 > *str2) return 1;
++str1;
++str2;
}
return 0;
}
strcmp는 조건이 조금 까다롭다.
char* Strchr(char * str, int ch)
{
while (*(str++))
if (*str == ch) return str;
return nullptr;
}
char* Strstr(char* str, char* sub)
{
size_t lenStr = Strlen(str);
size_t lenSub = Strlen(sub);
if (lenStr < lenSub || !lenSub) return str;
for (size_t i = 0; i < (lenStr - lenSub) + 1; ++i)
{
for (size_t j = 0; j < lenSub; ++j)
{
if (str[i + j] != sub[j]) break;
if (j == lenSub - 1) return str + i;
}
}
return nullptr;
}
조금 비용이 비싸보이는데...
char* Strtok(char* str, char* delim)
{
static char* AdressSaved = nullptr;
if (!str)
{
if (AdressSaved) str = AdressSaved;
else return nullptr;
}
char* pTokenStart = nullptr;
while (*str)
{
bool isDelim = false;
for (char* d = delim; !isDelim && *d; ++d)
{
if (*str == *d)
{
if (pTokenStart)
{
AdressSaved = str + 1;
*str = '\0';
return pTokenStart;
}
else
isDelim = true;
}
}
if (!isDelim && !pTokenStart)
pTokenStart = str;
str++;
}
AdressSaved = nullptr;
return pTokenStart;
}
/*
Strtok은 우선 str이 nullptr인지 확인하고 null이라면 이전에 잘라놓은 곳+1을 저장해놓은 static주소를 시작점으로 사용한다.
다음은 구분문자를 체크해 나가는 과정인데 구분 문자를 발견했을 때
새 토큰의 시작점(이번 단계에서 처음으로 구분문자가 아닌 문자가 있는 주소)이 저장되어있다면(pTokenStart == true)
구분문자가 있는 곳에 '/0'을 넣어서 반환한다 (반환하기전에 static 변수에 바로 다음 주소를 저장해놓는다).
이렇게 하나의 문자열토큰이 완성된다.
반대로 토큰의 시작점이 없는 상태(!pTokenStart)라면 처음부터 계속 구분문자밖에 없었던 것이다.
처음으로 등장하는 '구분문자가 아닌 문자'의 주소가 시작점이 된다.
만약 구분문자가 아닌 문자가 없는 문자열이거나 처음 입력한 문장의 끝에 도달하면 nullptr를 리턴한다.
구분문자임을 알았을 때 빠져나오면서 플래그로 쓰려고 isDelim을 사용하였다.
*/
strtok이 생각보다 어렵다..! 정리한게 저정도인데 음.. 뭔가 찝찝한데
자려고 하다가 수정해봄.
bool checkDelim(char* str, char* delim)
{
for (char* d = delim; *d; ++d)
if (*str == *d)
return true;
return false;
}
char* Strtok(char* str, char* delim)
{
static char* AdressSaved = nullptr;
if (!str)
if (AdressSaved) str = AdressSaved;
else return nullptr;
char* pTokenStart = nullptr;
for ( ; *str; ++str)
{
bool isDelim = checkDelim(str, delim);
if (isDelim && pTokenStart)
{
AdressSaved = str + 1;
*str = '\0';
return pTokenStart;
}
else if(!isDelim && !pTokenStart)
pTokenStart = str;
}
AdressSaved = nullptr;
return pTokenStart;
}
다음은 테스트 코드.
테스트케이스를 밑에처럼 고치면서 하기보다 귀찮아도 케이스를 여러개 만들어서 하는게 나중에 보기엔 좋은거 같네.
void test()
{
char szTest[20] = "once upon a time\n";
cout << "strlen : " << Strlen(szTest) << endl;
//
// char szDest[10]{}; //고의적인 에러
// cout << "strcpy : " << Strncpy_s(szDest, szTest, strlen(szTest)) << endl; //error!
//
char szCpy[20]{};
cout << "strcpy : " << Strcpy(szCpy, szTest) << endl;
char szCpy2[20]{};
cout << "strncpy : " << Strncpy(szCpy2, szTest, strlen(szTest)) << endl;
char szCpy3[20]{};
cout << "strncpy_s : " << Strncpy_s(szCpy3, szTest, strlen(szTest)) << endl;
//
char szCat1[60] = "there was a invisible dragon";
char szCat2[40] = ", who was invincible";
cout << "strCat : " << Strcat(szCat1, szCat2) << endl;
//
char szCmp1[40] = "Khaa";
char szCmp2[40] = "Khaab";
cout << "strCmp : " << Strcmp(szCmp1, szCmp2) << endl;
//
char szChr[30] = "abcdefghiklmnopqrstu";
cout << "strchr : " << Strchr(szChr, 'e') << endl;
//
char szStr[40] = "find a needle in a haystick";
char* ptr = Strstr(szStr, "needle");
if (ptr)
cout << ptr << endl;
}
void testTokk()
{
char str[] = ",,2,34.456-abcd,,,5,6,-";
char* pch;
char delim[] = " ,.-";
printf("문자열 \"%s\"을 토큰 \"%s\"으로 나눈다:\n", str, delim);
pch = Strtok(str, delim);
while (pch != nullptr)
{
cout << pch << endl;
pch = Strtok(NULL, delim);
}
}
int main()
{
test();
testTokk();
}
'프로그래밍 > C, C++ 공부' 카테고리의 다른 글
std::vector, list, deque의 벤치마크 (0) | 2018.03.05 |
---|---|
free,와 delete[]는 배열의 크기를 어떻게 아는걸까? (0) | 2018.03.02 |
왜 strchr의 두번째 인자는 char가 아닌 int일까? (0) | 2018.02.25 |
C에서의 파일 입출력 (0) | 2018.02.23 |
함수 포인터 (0) | 2018.02.21 |