atoiを使って文字列から数字を抜き出すのがうまくいきません

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
フィア

atoiを使って文字列から数字を抜き出すのがうまくいきません

#1

投稿記事 by フィア » 12年前

メッセージの表示速度を命令があれば変更するプログラムを作ろうとしているのですが、atoiを使って文字列の中から数字の部分を抜き取って、数字に変換して命令を与えようとしているのですがうまくいきません。
どうしたら良いでしょうか?

---op.sの内容---
???:「@rs 400・・・・・・。@rs 200どうやら

---ソース---
#include "DxLib.h"

#define MOJI_SIZE 24 // 文字のサイズ
#define SCREEN_X 936 // 画面の横幅
#define SCREEN_Y 702 // 画面の縦幅
char script[10000]={0};//文字データ全体
char LoadFname[100];
int LoadFsize;

int DrawPointX , DrawPointY; // 文字列描画の位置
int CP; // 参照する文字列中の文字ポインタ

// 改行関数
int Kaigyou( int h ){

// 描画行位置を一つ下げる
DrawPointY ++;

if(h){
DrawPointX = 2 ;
}

else{
// 描画列を最初に戻す
DrawPointX = 1 ;}

return 0 ;
}

// テキストファイルのロード
int loadfile(char *filename){

int y=0;
int i=0;
int m=0;
bool sw=true;
char c;
FILE *fp;

for(i=0;i<100;i++){
LoadFname=NULL;
}//FILENAMEをNULLで初期化する。

for(i=0;i<100;i++){
if(filename!='\0'){
LoadFname=filename;
LoadFsize=i+1;
}
}

i=0;

fp = fopen(filename,"r");

if(fp!=NULL){
for( ; ; ){

c=fgetc(fp);

if( feof( fp ) ) {
break;
}

else if(script[i-1]=='/' && c=='/'){
script[ i-1]=0;
script[ i ]=0;
sw=false;
i-=1;
}

else if( c == '\n' ){

script='\0';
sw=true;
}

else if(sw==true){
script=c;
i++;
}

m=i;
}
}

fclose(fp);

return m;
}

int JC(unsigned char code){

if( (code >= 0x81 && code <= 0x9F) ||
(code >= 0xE0 && code <= 0xFC) ) {
return 1;
}
return 0;
}

void scriptOrder(int z){

CP=0;
bool sw=true;
bool b_sw=false;
char One[ 2 ];
char Two[ 3 ];
int kei=0;
int kio=0;
int i=0;
int j;
int g=NULL;

DrawPointX = 1 ;
DrawPointY = 23 ;

int h = LoadGraph("ren_ga.gph");
int m = LoadGraph("mado.gph");
int n = LoadGraph("name_g.bmp");
int kF = LoadGraph("F.gph");
int kH = LoadGraph("H.gph");

SetDrawScreen(DX_SCREEN_BACK);
while( ProcessMessage() == 0 && CP < z ){

if( script[CP] == '@' ){
CP++;
//問題の箇所はここ
if(strnicmp(&script[ CP ],"rs",2)==0){
CP+=3;
if(isdigit(script[ CP ])){
g=atoi(&script[ CP ]);
j=1;
while(1){
if(isdigit(script[ CP + j ])){
g=atoi(&script[ CP + j ]);
}

else{
break;
}
j++;
}

WaitTimer( g ) ;
CP+=j;
}
}
}

else if( script[ CP ] == ':'){
DrawPointX = 1 ;
DrawPointY = 25 ;

sw=false;

Two[ 0 ] = script[ CP + 1 ];
Two[ 1 ] = script[ CP + 2 ];
Two[ 2 ] = '\0';

if( strcmp(Two,"「") == 0 ){
b_sw=true;
}

CP++;
}

else{
if(JC(script[CP])){
Two[ 0 ] = script[ CP ];
Two[ 1 ] = script[ CP + 1 ];
Two[ 2 ] = '\0';

if(sw){
DrawString( DrawPointX * MOJI_SIZE+12 , DrawPointY * MOJI_SIZE , Two , GetColor(255,255,255) ) ;
}

else{
DrawString( DrawPointX * MOJI_SIZE , DrawPointY * MOJI_SIZE , Two , GetColor(255,255,255) ) ;
}

ScreenFlip();
CP+=2;
}

else{
One[ 0 ] = script[ CP ];
One[ 1 ] = '\0';

if(sw){
DrawString( DrawPointX * MOJI_SIZE+12 , DrawPointY * MOJI_SIZE , One , GetColor(255,255,255) ) ;
}

else{
DrawString( DrawPointX * MOJI_SIZE , DrawPointY * MOJI_SIZE , One , GetColor(255,255,255) ) ;
}
ScreenFlip();
CP++;
}

// カーソルを一文字文進める
DrawPointX ++ ;

}
}

}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){

int i=0;

int DrawPointX=0;
int DrawPointY=0; // 文字列描画の位置
int col=GetColor(255,255,255);

char fn[100]="op.s";
int z;

//ログを出力しない
SetOutApplicationLogValidFlag( FALSE );

SetGraphMode( SCREEN_X , SCREEN_Y , 16 ) ;
ChangeWindowMode(true);
if( DxLib_Init() == -1 ) // DXライブラリ初期化処理
{
return -1; // エラーが起きたら直ちに終了
}

SetFontSize( MOJI_SIZE ) ;

z=loadfile(fn);
scriptOrder(z);

DxLib_End() ; // DXライブラリ使用の終了処理

return 0 ; // ソフトの終了

}

nil
記事: 428
登録日時: 13年前

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#2

投稿記事 by nil » 12年前

コードタグでコードを囲んでください。

フィア

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#3

投稿記事 by フィア » 12年前

失礼しました
こう書けばいいんでしょうか?

コード:

#include "DxLib.h"

#define MOJI_SIZE 24 // 文字のサイズ
#define SCREEN_X 936 // 画面の横幅
#define SCREEN_Y 702 // 画面の縦幅
char script[10000]={0};//文字データ全体
char LoadFname[100];
int LoadFsize;

int DrawPointX , DrawPointY;	// 文字列描画の位置
int CP;	// 参照する文字列中の文字ポインタ

// 改行関数
int Kaigyou( int h ){

	// 描画行位置を一つ下げる
	DrawPointY ++;

	if(h){
	 DrawPointX = 2 ;
	}

	else{
	 // 描画列を最初に戻す
	 DrawPointX = 1 ;}

	return 0 ;
}

// テキストファイルのロード
int loadfile(char *filename){

	int y=0;
	int i=0;
	int m=0;
	bool sw=true;
	char c;
	FILE *fp;
	
	for(i=0;i<100;i++){
		LoadFname[i]=NULL;
	}//FILENAMEをNULLで初期化する。

	for(i=0;i<100;i++){
		if(filename[i]!='\0'){
			LoadFname[i]=filename[i];
			LoadFsize=i+1;
		}
	}

	i=0;

	fp = fopen(filename,"r");

	if(fp!=NULL){
		for( ; ; ){

			c=fgetc(fp);

			if( feof( fp ) ) {
				break;
			}

			else if(script[i-1]=='/' && c=='/'){
				script[ i-1]=0;
				script[ i ]=0;
				sw=false;
				i-=1;
			}

			else if( c == '\n' ){

				script[i]='\0';
				sw=true;
			}

			else if(sw==true){
				script[i]=c;
				i++;
			}

			m=i;
		}
	}

	fclose(fp);
	
	return m;
}

int JC(unsigned char code){

        if( (code >= 0x81 && code <= 0x9F) || 
                (code >= 0xE0 && code <= 0xFC) ) {
                        return 1;
        }
        return 0;
}

void scriptOrder(int z){
	
	CP=0;
	bool sw=true;
	bool b_sw=false;
	char One[ 2 ];
	char Two[ 3 ];
	int kei=0;
	int kio=0;
	int i=0;
	int j;
	int g=NULL;

	DrawPointX = 1 ;
	DrawPointY = 23 ;

	int h = LoadGraph("ren_ga.gph");
	int m = LoadGraph("mado.gph");
	int n = LoadGraph("name_g.bmp");
	int kF = LoadGraph("F.gph");
	int kH = LoadGraph("H.gph");

	SetDrawScreen(DX_SCREEN_BACK);
	while( ProcessMessage() == 0 && CP < z ){

		if( script[CP] == '@' ){
			CP++;
			
			//問題点はここ
			if(strnicmp(&script[ CP ],"rs",2)==0){
				CP+=3;
				if(isdigit(script[ CP ])){
					g=atoi(&script[ CP ]);
					j=1;
					while(1){
						if(isdigit(script[ CP + j ])){
							g=atoi(&script[ CP + j ]);
						}

						else{
							break;
						}
						j++;
					}
				
					WaitTimer( g ) ;
					CP+=j;
				}
			}
		}

		else if( script[ CP ] == ':'){
			DrawPointX = 1 ;
			DrawPointY = 25 ;
			
			sw=false;

			Two[ 0 ] = script[ CP + 1 ];
			Two[ 1 ] = script[ CP + 2 ];
			Two[ 2 ] = '\0';

			if( strcmp(Two,"「") == 0 ){
				b_sw=true;
			}

			CP++;
		}

		else{
			if(JC(script[CP])){
				Two[ 0 ] = script[ CP ];
				Two[ 1 ] = script[ CP + 1 ];
				Two[ 2 ] = '\0';

				if(sw){
					DrawString(  DrawPointX * MOJI_SIZE+12 , DrawPointY * MOJI_SIZE , Two , GetColor(255,255,255) ) ;
				}

				else{
					DrawString(  DrawPointX * MOJI_SIZE , DrawPointY * MOJI_SIZE , Two , GetColor(255,255,255) ) ;
				}
				
				ScreenFlip();
				CP+=2;
			}

			else{
				One[ 0 ] = script[ CP ];
				One[ 1 ] = '\0';

				if(sw){
					DrawString(  DrawPointX * MOJI_SIZE+12 , DrawPointY * MOJI_SIZE , One , GetColor(255,255,255) ) ;
				}

				else{
					DrawString(  DrawPointX * MOJI_SIZE , DrawPointY * MOJI_SIZE , One , GetColor(255,255,255) ) ;
				}
				ScreenFlip();
				CP++;
			}

			// カーソルを一文字文進める
			DrawPointX ++ ;

		}
	}

}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){

	int i=0;

	int DrawPointX=0;
	int DrawPointY=0;	// 文字列描画の位置
	int col=GetColor(255,255,255);

	char fn[100]="op.s";
	int z;

	//ログを出力しない
	SetOutApplicationLogValidFlag( FALSE );

	SetGraphMode( SCREEN_X , SCREEN_Y , 16 ) ;
	ChangeWindowMode(true);
	if( DxLib_Init() == -1 )	// DXライブラリ初期化処理
	{
		 return -1;				// エラーが起きたら直ちに終了
	}

	SetFontSize( MOJI_SIZE ) ;

	z=loadfile(fn);
	scriptOrder(z);

	DxLib_End() ;				// DXライブラリ使用の終了処理

	return 0 ;					// ソフトの終了

}


アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#4

投稿記事 by softya(ソフト屋) » 12年前

問題点と書いている所での処理で、原因と思われるのは、
isdigitは文字を数値かチェックする関数ですが、atoiは文字列を数値に変換する関数です。
扱いの違いが分かりますか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

フィア

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#5

投稿記事 by フィア » 12年前

<<isdigitは文字を数値かチェックする関数ですが、atoiは文字列を数値に変換する関数です。

これは理解しています。

<<扱いの違いが分かりますか?
そのため数字の文字部分を抜き出して、数字に変える
ようにしている「つもり」ではあるのですが

実際にはできてないって事なんですね

扱いの違いっと申されましたが
扱い方というのは「その関数がそれがどういう関数」で「どうしたら動くか」?
という事を言っているのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#6

投稿記事 by softya(ソフト屋) » 12年前

そうです。動きの違いです。

文字列はナル文字'\0'までが終端です。
atoi(&script[ CP ])
であれば、script配列のCP番目からナル文字が出てくるまでをatoi変換しようとします。
つまり、文字列終端直前まで数値であることが保証されている必要があります。
にもかかわらずisdigit(script[ CP ])は開始の先頭文字が数値しかチェックしていません。

あとWaitTimer()でタイミングを取っていることに気づきましたが、将来的にはWaitTimer()に頼らないプログラムの書き方を身につけて下さいね。
WaitTimer()に頼るとバグに悩まされるとおもいますよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

フィア

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#7

投稿記事 by フィア » 12年前

<<文字列はナル文字'\0'までが終端です。
atoi(&script[ CP ])
であれば、script配列のCP番目からナル文字が出てくるまでをatoi変換しようとします。
つまり、文字列終端直前まで数値であることが保証されている必要があります。
にもかかわらずisdigit(script[ CP ])は開始の先頭文字が数値しかチェックしていません。

わかりました。
ヒントを元に改めて改良してみます。

<<あとWaitTimer()でタイミングを取っていることに気づきましたが、将来的にはWaitTimer()に頼らないプログラムの書き方を身につけて下さいね。
WaitTimer()に頼るとバグに悩まされるとおもいますよ。

確かリフレッシュレートでしたっけ?
あれを使うようにあれこれ書かれていることがよく目にしますね。

まだ、DXライブラリに慣れていないのでしばらくはWaitTimer()の使用することになりそうです。
ですが、大体慣れてきたらリフレッシュレートを使用することを考案してみます。

ありがとうございました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#8

投稿記事 by softya(ソフト屋) » 12年前

フィア さんが書きました: 確かリフレッシュレートでしたっけ?
あれを使うようにあれこれ書かれていることがよく目にしますね。

まだ、DXライブラリに慣れていないのでしばらくはWaitTimer()の使用することになりそうです。
ですが、大体慣れてきたらリフレッシュレートを使用することを考案してみます。
フレームですね。経過時間でタイミング制御した方が良いとは思いますが。

少なくともWaitTimer()をつかって大きくなったプログラムを後々直すのは、ほぼ不可能だとおもいます。
プログラムが小さいうちに直すか、このプログラムを将来的に捨てて新たに作りなおすかどちらかだと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

non
記事: 1097
登録日時: 14年前

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#9

投稿記事 by non » 12年前

64行目でi=0のとき範囲外を参照します。

73行目ではiを進めなくていいのでしょうか?
故意かな?その下のプログラムを見ていないので・・・
non

フィア

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#10

投稿記事 by フィア » 12年前

改良に数値をチェックしていれて最後にNULLを入れたような気がします。

改良を試行錯誤したのですがうまくいきませんでした。
どこら辺がまずいのでしょうか?

コード:

char kei[5];	//新たに変数追加 5桁まで数字が入るように
	//初期化
	for(i=0;i<5;i++){
		kei[ i ]=NULL;
	}

コード:

			if( _strnicmp(&script[ CP ] , "rs" , 2 ) == 0 ){
				CP+=3;

				for(i=0;i<5;i++){
					if(isdigit(script[ CP+i ])){
						kei[i]=script[ CP+i ];
					}
						
					else{
						kei[i]=NULL;
						break;
					}
				}

				g=atoi(kei);
				WaitTimer( g );

				CP+=i;
				
				//また使うかもしれないから初期化しておく
				for(i=0;i<5;i++){
					kei[i] = NULL;
				}

			}

<<フレームですね。経過時間でタイミング制御した方が良いとは思いますが。
経過時間で制御タイミングとは

「あいうえお」

という文字列を表示するのに

「あ」 が表示されたら一定秒数 とりあえずここでは1秒としますが

一秒後に

「い」

さらに一秒後に

「う」

といった感じで経過時間を調節するっと言う解釈でよろしいでしょうか?

<<64行目でi=0のとき範囲外を参照します。
あああ本当だ
最初にコメントアウトする場合を考えていませんでした。
教えていただきありがとうございました。

改良しないといけませんね

<<73行目ではiを進めなくていいのでしょうか?
故意かな?その下のプログラムを見ていないので・・・

変なプログラムに見えますが故意です。
実は\0を入れているようでファイルの最後でなければすぐに上書きするようにしています。

文末は命令語を作って処理すれば良いやっとおもってたのでこうしました。


それにしてもここはいいところですね
自分が多分大丈夫だろうと思っていたところをおかしいと指摘されるとは

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#11

投稿記事 by softya(ソフト屋) » 12年前

ナル文字とNULLの混同は望ましくないです。ちゃんと使い分けましょう。
それと5桁の数値文字を入れるならナル文字を含めると6文字ですよ。

>といった感じで経過時間を調節するっと言う解釈でよろしいでしょうか?

どうやって制御するかがイマイチ見えませんが、毎フレームの単一のメインに戻ることだけは守って下さい。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

フィア

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#12

投稿記事 by フィア » 12年前

<<ナル文字とNULLの混同は望ましくないです。ちゃんと使い分けましょう。

すみません。
勘違いしていました今までナル文字のことをNULLだと思っていました
\0のことですね。

こんな感じで直してもうまくいきません。

コード:

			if( _strnicmp(&script[ CP ] , "rs" , 2 ) == 0 ){
				CP+=3;

				for(i=0;i<5;i++){
					if(isdigit(script[ CP+i ])){
						kei[i]=script[ CP+i ];
					}
						
					else{
						kei[i]='\0';
						break;
					}
				}

				if(i==5){
					kei[i]='\0';
				}

				g=atoi(kei);
				WaitTimer( g );

				CP+=i;

				for(i=0;i<5;i++){
					kei[i] = NULL;
				}

			}
<<どうやって制御するかがイマイチ見えませんが、毎フレームの単一のメインに戻ることだけは守って下さい。

解釈の仕方が違うのであれば

経過時間でタイミング制御した方が良いとはどのようなことを意味しているのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#13

投稿記事 by softya(ソフト屋) » 12年前

>こんな感じで直してもうまくいきません。

デバッガで問題は調べましたか?

>経過時間でタイミング制御した方が良いとはどのようなことを意味しているのでしょうか?

メインのループは毎フレーム1/60秒で回しますので、「あ」の表示なら毎フレーム「あ」を表示します。
表示を開始してから一定時間が経過したら(GetNowCount();でms単位の時間計測)次に「あい」と表示するようにバッファを書き換えると言うことです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

フィア

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#14

投稿記事 by フィア » 12年前

変更してみました

コード:

 
	bool mese_sw=false;
	bool han_sw=true;
	char kei[ 6 ];

コード:

 
			if( _strnicmp(&script[ CP ] , "rs" , 2 ) == 0 ){
				CP+=3;

				for(i=0;i<6;i++){
					if (i==5){
						kei [ 5 ] = '\0';
						if(han_sw){
							j=5;
							han_sw=false;
						}
					}

					else if( isdigit( script[ CP + i ] ) && i<5 ){
						kei [ i ] = script[ CP + i ];
					}
		
					else{
						kei [ i ] = '\0';
						if(han_sw){
							j=i;
							han_sw=false;
						}
					}
				}

				g=atoi(kei);

				CP+=j;

				for(i=0;i<6;i++){
					kei[i] = '\0';
				}

				han_sw=true;
				mese_sw=true;

			}



今までつかったことのなかったデバッガの使い方を調べて使ってみたのですがエラーとなっている場所はisctype.cの56行目

_ASSERTE((unsigned)(c + 1) <= 256);

の部分みたいで、atoiが問題ではなくisdigitが問題なのかなと思いました。

このバグは入れる文字を0~255の範囲にしなさいよ
という物でよくわからないけど入れているらしいことまでがわかりました。

だからデバッガで調べて何の値が入ってるのか調べるべしと書かれていたのですが
問題はデバッガを使いはしたもののデバッガの見方がわからず、何を入れてるのかわからん
ということです。

対話型云々とか書かれてるのにまったくわからない

フィア

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#15

投稿記事 by フィア » 12年前

ああデバッガの使い方わかった
バグがどこででたのかわかりました
改良してみます

フィア

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#16

投稿記事 by フィア » 12年前

できませんでした。

isdigit に-127 の判定が入るらしく(これが原因でエラー)
これを直前で符号なしにしようにもif やelse の判定が先におこなわれてしまうため(デバッガで初めて知った)符号なしにする前に判定されてしまうため、isdigit以外の方法で入っている変数を数字か判定する関数ってないのでしょうか?

フィア

Re: atoiを使って文字列から数字を抜き出すのがうまくいきません

#17

投稿記事 by フィア » 12年前

あ、いけました
自作関数を作っちゃえばいいんだ
isdigitにエラーがでるのでisdigitkaiという関数を作ったら何とかなりました。

コード:

int	isdigitkai(char a){

	int i;
	for(i=48;i<58;i++){
		if(i==a){
			return 1;
		}
	}

	return 0;
}

閉鎖

“C言語何でも質問掲示板” へ戻る