ページ 11

strtok

Posted: 2008年7月02日(水) 13:42
by Haru
いつもお世話になってます。Haruです。Strtokでスペースを区切り文字とし、文字列を分解する作業をしているのですが、スペースのみで入力した場合と、文字列の最後にスペースを入力した場合に、スペースを読み込んでしまうんですが、読み込まないようにするにはどうすればよいのでしょうか?私が考えている原因としては、上の二つの場合だと、スペースがNULLにかえってない(?)からだと思うのですが・・・。良い対処法を教えてください。お願いします。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int main(void)
{
	int i,c = 0;
	int argc;
	int sentou = 0;
	char *argv[256];
	char *tp;
	char str[256];

	while((str[c++] = getchar()) != '\n');  /* 改行まで読み込み */
	puts(str);

	tp = strtok(str," ");  	/*  文字列strをスペースごとの字句(トークン)に分ける。一度目は分解対象の文字列を指定 */
	i = 0;

	printf("[%d]  =  [%s] \n",i,tp);               /* i = 回数 tP = スペースで分解した文字列strの1番目 */

	i = 1;                                         /* 0は既に表示しているので1から */
	
	while(tp != NULL)                              /*  tp = NULLでなければループ  */
	{
		tp = strtok(NULL," ");                 /* 2度目以降はNULLを指定 */
 
		if((tp != NULL) && (tp != " "))        /* もしtp = NULLでなければ  */

		{
			printf("[%d]  =  [%s] \n",i,tp);
			i++;
        	}
	}
	printf(" %d \n",i);
	return 0;
}

Re:strtok

Posted: 2008年7月02日(水) 14:35
by バグ
このソースでも駄目ですか?
#include <stdio.h>
#include <string.h>

int main(void)
{
	char string[256];
	char* split = " ";
	char* token;

	strcpy(string, "I Like Programing");
	printf("%s\n", string);

	token = strtok(string, split);
	while (token != NULL)
	{
		printf("%s\n", token);
		token = strtok(NULL, split);
	}

	return 0;
}

Re:strtok

Posted: 2008年7月02日(水) 14:57
by Mist
> スペースがNULLにかえってない(?)からだと思うのですが・・・。
思うだけじゃなくてデバッグで確認して欲しいところですが。
(tpの値を出力すればすぐにわかること)

修正したほうがいいところ
1.str配列は'\0'で初期化すべき
  strtokは文字列終端を\0で判断するから
  今のプログラムだと\nより後ろは不定値
2.区切り文字の判断には\nを追加しておいたほうがいい
  文字列の最後が\nになるから(\nもひとつのトークンとしてみなすのであれば別ですが)
3.(tp != " ") はたぶん間違ってる
  tpが指す文字列の先頭が空白でないかをチェックしたいのなら
  (*tp != ' ')
提示プログラムを動作確認出来たらまた回答します。

Re:strtok

Posted: 2008年7月02日(水) 17:25
by Haru
>バグさん

そのソースコードでは、うまくできます!
キーボードで自由に文字列を入力させたときにスペースがはいっちゃうんですよ(^^;

>Mistさん

>> スペースがNULLにかえってない(?)からだと思うのですが・・・。
>思うだけじゃなくてデバッグで確認して欲しいところですが。
>(tpの値を出力すればすぐにわかること)

失礼しました。一応デバッグをして確認はしたのですが、自信がないものでつい、「~と思う」
と言ってしまいました。
Mistさんの修正した方が良いところを注意して修正したいと思います!

Re:strtok

Posted: 2008年7月02日(水) 19:24
by バグ
その文字は本当にスペースですか?改行文字ではありませんか?

Re:strtok

Posted: 2008年7月03日(木) 09:09
by Haru
>バグさん
すいません。改行でした。
printf("DEBUG:%s,tp); としてたので、てっきりスペースだと思い込んでました。
申し訳ないです。。

Re:strtok

Posted: 2008年7月03日(木) 09:42
by Mist
それならば、私の指摘の1と2で直るでしょう。
スタックな文字配列変数は初期化する癖つけておいたほうがいいと思います。

Re:strtok

Posted: 2008年7月03日(木) 10:08
by Mist
私が作った修正ソースです。
参考までにどうぞ。(環境Xp + VC++2008EE)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int main(void)
{
	int i,c = 0;
//	int argc;
//	int sentou = 0;
//	char *argv[256];
	char *tp;
	char str[256];

	memset(str, 0, sizeof(str));	// *-*

	while((str[c++] = getchar()) != '\n');  /* 改行まで読み込み */
	puts(str);

	tp = strtok(str," \n");  		// *-* /*  文字列strをスペースごとの字句(トークン)に分ける。一度目は分解対象の文字列を指定 */
	i = 0;

	if (tp != NULL) {
		printf("[%d]  =  [%s] \n",i,tp);               /* i = 回数 tP = スペースで分解した文字列strの1番目 */

		i = 1;                                         /* 0は既に表示しているので1から */
	
		while(tp != NULL)                              /*  tp = NULLでなければループ  */
		{
			tp = strtok(NULL," \n");    // *-*         /* 2度目以降はNULLを指定 */
 
			if(tp != NULL)				// *-*		/* もしtp = NULLでなければ  */
			{
				printf("[%d]  =  [%s] \n",i,tp);
				i++;
			}
		}
	}

	printf(" %d \n",i);

//	system("PAUSE");

	return 0;
}

Re:strtok

Posted: 2008年7月03日(木) 11:17
by Haru
>Mistさん
いつもありがとうございます!おかげでできるようになりました!!
文字配列変数を初期化するのも勉強になりました!