strtok에의한 결과가 strcmp로 다르게 나오는데 원인이 무엇인가요?

pedor의 이미지

제가 구현하고자 하는 부분은 파일에서 값을 읽어와서 실제 값을 비교해보는 내용인데요
test.txt 파일에는 (12,12) <-- 이렇게만 써 놓고 "12"와 파일에서 읽어온 "12"의 값을 비교하는 내용입니다

파일에서 값을 읽어와서 ,를 이용해 구별을 한후 각 버퍼에 집어 넣은다음에
"12"와 직접 비교를 하게 되는데 같지 않다고 나오네요..

원인이 무엇인지 파악좀 부탁드립니다....이론상으로는 같아야 할것 같은데...

출력을 시켜보면
----
pFir : 12
pSed : 12

end
----
이렇게 나오고 있습니다

#include
#include
#include
#include
int main()
{
char szFileBuf[100];
char pFir[100];
char pSed[100];
char *pszBuf;
int fd;
fd = open("./test.txt", O_RDONLY);
if(fd<0)
{
printf("open error\n");
return 0;
}
else
{
read(fd, szFileBuf, 100);
pszBuf = strtok(szFileBuf,",");
sprintf(pFir, pszBuf);
pszBuf = strtok(NULL,",");
sprintf(pSed, pszBuf);

printf("pFir : %s\n", pFir);
printf("pSed : %s\n", pSed);

if(0==strcmp("12",pFir))
{
if(0==strcmp("12",pSed))
printf("success\n");
}
printf("end\n");

}
return 0;
}

mirheekl의 이미지

숫자 앞뒤로 공백(스페이스, 탭, 개행문자, 기타등등)이 있는게 아닐까 생각됩니다. 가령 이렇게.. "12 , 34 , 56 , ..."
이러면 토큰으로 뽑아낼때 공백이 같이 뽑히겠죠. 현재의 코드로는 이부분을 확인할 수 없을것 같네요. 특히 공백이 숫자 앞이 아니라 숫자 뒤에 있다면 더더욱..

strtok에 주는 토큰을 확장해서 공백문자를 같이 잘라내게 해보시면 도움이 될듯 합니다. 또는 숫자가 확실할경우 숫자로 변환해서 비교해봐도 되겠고..
그래도 동작이 되지 않는다면 브레이크포인트를 걸어서 (또는 데이터를 확인하는 코드를 넣어서) 실제로 넘어온 값이 무엇인지 바이트단위로 확인해보시기 바랍니다. %s로 찍지 마시고요.

--

jick의 이미지

sprintf를 저런 식으로 쓰는 건 매우 위험하며 실생활에서 절대 써서는 안되는 방법입니다. 파일 안에 %s 같은 문자열이 들어있으면 바로 프로그램이 죽을 수 있습니다.

strcpy를 쓰세요.

* 안타깝게도 이거랑 지금 안되는 것과는 별 상관 없는 것 같습니다만... -.-

mirheekl의 이미지

본문에서
sprintf -> strcpy_s, strncpy_s (물론 sprintf를 본문과 달리 제대로 된 목적으로 쓰신 경우에는 당연히 sprintf_s를 쓰면 됩니다)
strtok -> strtok_r (VC는 strtok_s) 이건 재귀호출이나 멀티스레드 등이 없을 경우에는 신경 안써도 되지만 새 펑션을 쓴다 해서 해가 될게 없으므로 항상 이것만 쓰는게 좋지요

그리고 사소한 거지만 파일을 닫는 구문이 빠져있네요.
또한가지.. strtok의 리턴값을 체크하는것도 빠져있군요. NULL이 리턴될수도 있습니다. 이러면 예외가 발생하겠죠.
또또한가지.. read 리턴값 체크도 빠져있네요. 이경우 기존의 데이터가 그대로 버퍼에 남으므로 역시 오류의 소지가 됩니다. 리턴값 및 EOF검사를 하셔야 합니다.

간단한 테스트프로그램이라 모든 걸 그냥 생략하고 만드셨을거라 생각하지만 혹시나 해서 노파심에 적어봅니다.

--

pedor의 이미지

참고하도록 하겠습니다

익명 사용자의 이미지

저도 같은 문제 때문에 골머리를 썩고 있습니다.

babbab의 이미지

제가 지금 리눅스 앞에 않앉아있어서 소스를 좀 고쳤는데 결과가 이렇게 나옵니다.

C:\Windows\system32\cmd.exe /c ( ^"test^" )
pFir : 12
pSed : 12
success
end
Hit any key to close this window...

소스는 표준 라이브러리로 대체했습니다.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    char szFileBuf[100];
    char pFir[100];
    char pSed[100];
    char *pszBuf;
    FILE *fd;
    fd = fopen("./test.txt", "r");
    if(fd == NULL)
    {
        printf("open error\n");
        return 0;
    }
    else
    {
        fgets(szFileBuf, 100, fd);
        pszBuf = strtok(szFileBuf,",");
        sprintf(pFir, pszBuf);
        pszBuf = strtok(NULL,",");
        sprintf(pSed, pszBuf);
 
        printf("pFir : %s\n", pFir);
        printf("pSed : %s\n", pSed);
 
        if(0==strcmp("12",pFir))
        {
            if(0==strcmp("12",pSed))
                printf("success\n");
        }
        printf("end\n");
 
    }
return 0;
}
shint의 이미지

32비트 윈도우XP cygwin 으로 컴파일했을 경우는 잘 되었는데...

http://kldp.org/node/153795
이분도 비슷한 어려움이 있네요.

리눅스 지역설정. 언어설정. 파일이름등에서 euc-kr과 utf-8 혹은 unicode 등에 문자도 확인해보셔야 할거 같습니다.

fgets()를 사용하는 경우. \n 값이 함께 얻어지니 주의해야 합니다.

\r\n 도 확인해야 할겁니다.

close(int); 를 해주셔야 합니다.

첨부된 파일 소스는. 32비트 윈도우XP에서 cygwin으로 확인한 내용입니다.

댓글 첨부 파일: 
첨부파일 크기
Package icon test strcmp()와 strtok() 사용방법.zip39.65 KB

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

ymir의 이미지

출력 결과를 보시면 pSed 아래에 빈줄이 하나 더 들어가 있는 걸 보실 수 있을겁니다.
코드 상으로 보면 빈줄이 나올 상황이 아니죠.

test.txt 파일 안의 마지막 라인에 \n 이 붙어 있기 때문에..
, 를 delimiter 로 주고 잘랐을 때, 두번째 token 에는 12\n 이 들어가 있어서..
두 번째 pSed 를 찍었을 때 빈줄이 하나 더 들어간 것일 겁니다.

파일에서 읽은 후에 마지막의 \n 을 잘라주시거나, strtok 에 whitespace 문자도 포함시켜 주면 되겠네요.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.