C言語関係掲示板

過去ログ

No696 ファイルの文字列を数字に変換して配列に格納

[戻る] [ホームページ]
No.8185

atoiを使って整数に変換
投稿者---BEE(2003/07/09 21:00:08)


こんにちは。
あるファイルからfgetsを使って数字を文字列として読み込み、
配列に格納した後に、それを整数に変換しようとして
以下のようにしてみたのですがうまくいきません。
理由がわからないので、よろしければ教えていただきたいです。

#include<stdio.h>
#include<stdlib.h>

void main(void){
  FILE *fq;
  char ma[16][16];
 int y;
    fq=fopen("maze1.dat","r");
  for(i=0;i<15;i++){
    fgets(ma[i],32,fq);
  }
  fclose(fq);
  y=atoi(ma[0]);
  printf("%d\n",y);
}


こうすると、307163531と表示されてしまいました。
ちなみに「maze1.dat」というファイルには
数字の1,2,3が書かれており、
1が壁、2が人、3が道を表し、これらで迷路を表現しています。
ma[0][0]は文字列として「1」が格納されていますので、
yは1であって欲しいのですが。

windowsXPで、BCC5.5++を使ってコンパイルしました。

No.8187

Re:atoiを使って整数に変換
投稿者---nop(2003/07/09 21:10:26)


>ちなみに「maze1.dat」というファイルには
>数字の1,2,3が書かれており、
>1が壁、2が人、3が道を表し、これらで迷路を表現しています。
>ma[0][0]は文字列として「1」が格納されていますので、
>yは1であって欲しいのですが。

「maze1.dat」の中身をUPしてみそ。

No.8189

Re:atoiを使って整数に変換
投稿者---BEE(2003/07/09 21:37:51)


111111111111111
121000101000001
101010101101101
101010000001001
101010111111011
101110100001001
100010101101101
101010100100101
101010110101101
101000100100001
101111101111111
101000100000101
101011111010101
101000000010003
111111111111111

これになります。

No.8194

Re:atoiを使って整数に変換
投稿者---nop(2003/07/09 23:06:46)


>111111111111111
>121000101000001
>101010101101101
>101010000001001
>101010111111011
>101110100001001
>100010101101101
>101010100100101
>101010110101101
>101000100100001
>101111101111111
>101000100000101
>101011111010101
>101000000010003
>111111111111111

>
>これになります。

この場合なら、fgets()で一行読み込むより、
fgetc()で一文字づつ読み込んで、読み込んだ文字に対して

 数字であれば数字を数値に変換
 改行文字であれば行を移動し列インデックスを初期化
 数字でも改行文字でもない場合にはエラー又は無処理

と言う処理をファイルの終わりまで繰り返す。
と言うのが妥当では無いでしょうか?

No.8191

Re:atoiを使って整数に変換
投稿者---ともじ(2003/07/09 21:44:56)


こんばんは。
>  y=atoi(ma[0]);
>  printf("%d\n",y);
>こうすると、307163531と表示されてしまいました。

  printf("%d\n",ma[0][0]-'0');
とすると、1が得られます。

ma[0][0]に入ってるのは、文字の'1'で、文字列の"1"ではないのです。
ma[0]に、文字列の"000000000000001"が入ってれば、atoiの結果は
1になります。ma[0]に、"000000000000010"が入っていれば、atoiの結果は
10になります。ma[0]に、"100000000000000"が入ってれば、intでは表現
できないので、atoiの結果は307163531になってしまうかもしれません。


No.8192

Re:atoiを使って整数に変換
投稿者---BEE(2003/07/09 22:41:41)


>printf("%d\n",ma[0][0]-'0');</pre>とすると、1が得られます。
>ma[0][0]に入ってるのは、文字の'1'で、文字列の"1"ではないのです。

なるほど、文字列ではなく文字の"1"ですね。
ではどのようにして文字の1を整数に変換すれば良いのでしょうか。
お手数ですが、教えていただけると幸いです。
atolにしてもやはりうまくいきませんでした。

>ma[0]に、文字列の"000000000000001"が入ってれば、atoiの結果は
>1になります。ma[0]に、"000000000000010"が入っていれば、atoiの結果は
>10になります。ma[0]に、"100000000000000"が入ってれば、intでは表現
>できないので、atoiの結果は307163531になってしまうかもしれません。

ma[0]には111…が入っていますが、
atoi(ma[0])としたときは、ma[0]の先頭アドレスが、
つまり&ma[0][0]と同じ意味になるのではないでしょうか。

No.8195

Re:atoiを使って整数に変換
投稿者---かずま(2003/07/09 23:57:07)


> ではどのようにして文字の1を整数に変換すれば良いのでしょうか。

1文字の数字を整数として読みたいのなら、fscanf を使えばよいでしょう。
    int i, j, k;

    for (i = 0; i < 15; i++) {
        for (j = 0; j < 15; j++) {
            if (fscanf(fp, "%1d", &k) != 1)
                puts("can't read data"), exit(1);
            ma[i][j] = k;
        }
    }


No.8197

Re:atoiを使って整数に変換
投稿者---BEE(2003/07/10 00:04:06)


なるほど、ありがとうございました。
良く覚えておきたいと思います。


この投稿にコメントする

削除パスワード

No.8196

Re:atoiを使って整数に変換
投稿者---ともじ(2003/07/10 00:02:08)


>なるほど、文字列ではなく文字の"1"ですね。

文字は''で囲みます。""で囲むと文字列になります。つまり、
"1"は、'1'と'\0'からなる文字列です。

>ではどのようにして文字の1を整数に変換すれば良いのでしょうか。

ファイルから2次元配列maに読むときは、fgetsで文字列で読み、
使用するときのみ整数にすればいいのですか。でしたら、さっき書いた
ように、
ma[0][0]-'0'
でいいのではないですか。
例えば、"012"という文字列は、'0','1','2','\0'というデータです。
それぞれ'0'を引くと、0,1,2という整数に変換できます。

それとも、ファイルからmaに読む時点で整数として読みたいのでしょうか。
それでしたら
    for(i = 0; i < 15; i++){
        for (j = 0; j < 15; j++) {
            if (fscanf(fq, "%1d", &ma[i][j]) != 1) {
                printf("file format error\n");
                fclose(fq);
                return 1;
            }
        }
    }
と1バイトずつ読んではいかがでしょう。

>ma[0]には111…が入っていますが、
>atoi(ma[0])としたときは、ma[0]の先頭アドレスが、
>つまり&ma[0][0]と同じ意味になるのではないでしょうか。

atoiが変換するのは文字列なので、'\0'が出てくるまで変換します。
つまり、ma[0][0]に入っているのが'1'でも、ma[0][15]の'\0'まで
一気に整数変換してしまいます。


No.8201

Re:atoiを使って整数に変換
投稿者---BEE(2003/07/10 01:32:17)


>ma[0][0]-'0'でいいのではないですか。
>例えば、"012"という文字列は、'0','1','2','\0'というデータです。
>それぞれ'0'を引くと、0,1,2という整数に変換できます。

なるほど、''で囲まれた文字は0をひくと数字に変換できる
出来るのですね。参考になります。

fgetsでのやり方、fscanfでのやり方、共にしっかりと
覚えておきたいと思います。

>atoiが変換するのは文字列なので、'\0'が出てくるまで変換します。
>つまり、ma[0][0]に入っているのが'1'でも、ma[0][15]の'\0'まで
>一気に整数変換してしまいます。


ふむふむ。文字列を変換するということは、文字列の終わりを示す
'\0'を読むまで変換を続けるということなのですね。
非常に良くわかりました。

詳しい説明ありがとうございました。
また勉強に励みたいと思います。

No.8205

Re:atoiを使って整数に変換
投稿者---かずま(2003/07/10 09:19:28)


>          if (fscanf(fq, "%1d", &ma[i][j]) != 1) {

char ma[15][15]; と宣言されていたら、これはダメです。
%d に対応する引数は int * でないといけません。

うまくいっているように見えるのは、リトルエンディアンの CPU で、かつ
ワード境界以外でのワードアクセスを許し、さらに ma[14][14] の次を
書き換えても支障のないという特殊な場合だけです。


No.8212

Re:atoiを使って整数に変換
投稿者---ともじ(2003/07/10 12:54:23)


> char ma[15][15]; と宣言されていたら、これはダメです。
> %d に対応する引数は int * でないといけません。

ご指摘ありがとうございます。仰るとおりです。

>BEEさん
fscanf(fq, "%1d", &ma[i][j])
とする場合には、
int ma[15][15];
としてください。

どういうことかというと、以下のようにchar型に"%d"で入力すると、別領域を破壊します。
#include <stdio.h>

int main(void)
{
	char a[10] = "1234567890";
	int i;

	for (i = 0; i < 10; i++)
		printf("%#x ", a[i]);
	printf("\n");

	printf("整数値の入力>");
	scanf("%1d", &a[0]);

	for (i = 0; i < 10; i++)
		printf("%#x ", a[i]);
	printf("\n");

	return 0;
}

実行結果
0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 
整数値の入力>5
0x5 0x0 0x0 0x0 0x35 0x36 0x37 0x38 0x39 0x30 


No.8282

Re:atoiを使って整数に変換
投稿者---BEE(2003/07/11 16:45:48)


皆様ありがとうございます。
%dとするのに、char型で宣言するのが間違いだというのは
あまりにもごもっともでした。

リトルエンディアン、ビッグエンディアンについては
正直まだ知識として確立出来ていない私ですので、
また本を読むなどして勉強しておこうと思います。

返信が遅くなったことをお詫びしますとともに、
本当にありがとうございました。