• 締切済み

整数型の配列に a,b,c,: などの文字を入れたら・・・

整数型の配列に整数データを格納するプログラムで、 入力時に文字を入力してしまった場合、 エラーチェックを行いたいのですが、 具体的にどのような方法があるのでしょうか? 文字を入力した場合に、 とてつもないことがDos画面でおこってしまいます。 どうか皆さん、よろしくお願いします。 言語はC言語で、 visualC++6.0を使っています。

みんなの回答

回答No.11

fgetsについて >こちらは'\0'ターミネートが保証されます。 これは、此方の勘違いでした。 #strncpyあたりと勘違いしてたようです。 >strtolは現在主流のANSI-C(C89)では定義されていません。 これについては、JIS X3010-1993の7.10.1.5に定義されてます。 ANSI/ISOについてのソースが手元にないですが、原文ISO9899(C89)にも乗っているはずですが。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.10

strtolは現在主流のANSI-C(C89)では定義されていません。 strtolのサポートはC99からで、Visual C++6.0はC89準拠です。 よって、 > ここまでくるとその処理系が本当にANSI Cかどうか疑いたくなる 「処理系のANSI-C準拠」と「strtolの挙動に対して予防線を張ること」に矛盾は生じません。 > strtolはpを走査の終了位置を示す文字へのポインタにするので、 > p == &str[strlen(str)] つまり *p == '\0' >となり、p == NULL にはならないです。 前述のようにC89におけるstrtolの挙動は処理系依存である確率が高く、このような断言は危険です。 > fgetsはgetsのように'\n'を'\0'に変換しないのでチェックは必要ですよ? そうですね。 カン違いでした。 > また、'\0'でターミネートされた値が確実に入るわけではないのでその辺も注意が必要です。 こちらは'\0'ターミネートが保証されます。 (C89,C99ともに)

回答No.9

> 質問の趣旨が「入力文字エラーチェック」ですから不正文字入力を認識するためにstrtol()を使うべきと考えました。 この点に付いてはどちらでも目的を達成できるので異論はないですが、 > pがNULLなら変換不能文字無し(=文字列は全て10進数に変換された) strtolはpを走査の終了位置を示す文字へのポインタにするので、 p == &str[strlen(str)] つまり *p == '\0' となり、p == NULL にはならないです。 > fgets()だから'\n'チェックは不要だし、 fgetsはgetsのように'\n'を'\0'に変換しないのでチェックは必要ですよ? また、'\0'でターミネートされた値が確実に入るわけではないのでその辺も注意が必要です。 > '\0'を変換不能文字だと認識するようなstrtolの実装は見たことが無いのですが、 ここまでくるとその処理系が本当にANSI Cかどうか疑いたくなる。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.8

2度目です。 質問の趣旨が「入力文字エラーチェック」ですから不正文字入力を認識するためにstrtol()を使うべきと考えました。 long strtol(char *, int, char **) ; 文字列を数値に変換 関数値: 変換後の数値。 文字列に変換不能文字があった場合、変換可能文字までを変換する(1zの場合、1)。 文字列が先頭から変換不能文字であった場合0。 第1引数: 変換対象の文字列。 第2引数: 変換の基数。 10→10進変換 16→16進変換 8 →8進変換 0 →C言語の定数記述規約に従い変換(0x=16進。0=8進) 第3引数: 変換不能文字を発見した場合、発見した変換不能文字のアドレスを設定する。 10XYZと文字列であれば'X'のアドレス。 この引数がNULLであった場合変換不能文字の報告を行わない val[no] = strtol(str, 10, &p) ; val[no]には変換できたところまでの数値が入ります。 pには変換不能だった文字のアドレスが設定されます。 pがNULLなら変換不能文字無し(=文字列は全て10進数に変換された) *pが文字なら入力文字列に含まれた変換不能文字そのものへのアドレスです。 *p != '\0' && *p != '\n'の部分は「'\0'や'\n'が変換不能文字として報告されたら困る」という場合のチェックです。 fgets()だから'\n'チェックは不要だし、'\0'を変換不能文字だと認識するようなstrtolの実装は見たことが無いのですが、老婆心で常に入れるクセついてて… エラールートなので(P!=NULLの時しか通らない)処理効率と関係ないので「nul文字と改行は無関係」という仕様を示す意味もあって入れてたりします。 sscanfやatoiは変換不能文字の報告を行わない(ssacnfでは可能だが、利用法が煩雑)ため、「エラーチェック」を趣旨とするこの質問には合致しないと考えます。

回答No.7

>ret = sscanf(buffer, "%d%[\n]", &data[i], &dummy); ↑の行間違い本当は↓ ret = sscanf(buffer, "%d%1[\n]", &data[i], &dummy); どう違うかは考えてみてください。

回答No.6

何か問題を難しく考えすぎているようですが、 #1のやり方でgetsをfgetsにすれば一番単純では? わざわざ一文字づつ調べる必要もないとけど。 とりあえずこんな感じ↓ #include <stdio.h> #include <stdlib.h> #define DATA_SIZE 10 #define BUFFER_SIZE 256 int main(void) {  int ret, i;  int data[DATA_SIZE];  char buffer[BUFFER_SIZE];  char dummy;  for(i = 0; i < DATA_SIZE; i++)  {   printf("input data[%d] > ", i);   fgets(buffer, BUFFER_SIZE, stdin);   ret = sscanf(buffer, "%d%[\n]", &data[i], &dummy);   if(ret != 2)   {    printf("\ndata err!!\n\n");    --i;   }  }  for(i = 0; i < DATA_SIZE; i++)   printf("data[%d] = %d\n", i, data[i]);  return 0; }

  • MovingWalk
  • ベストアンサー率43% (2233/5098)
回答No.5

#4です。 >上記のサンプルは文字0から9の入力の場合には、配列に入力文字を格納するものですが、 >これでは126とか-46など、2桁以上の数字や、負の整数には対応できないようです。 先頭文字のチェックをしていませんの符号文字の入力には対応していません。 必要なら先頭文字のときに符号文字をチェックすればいいと思いますが。(ご自分でどうぞ) 2桁以上の数字には対応していませんか? どう読んだのでしょうか? これは、1つの数値を文字列として格納する部分です。 これを数値データにして、数値配列に格納する部分は含まれていませんが。 尚、これがコンソールのアプリケーションの場合、 BSキーなどによる編集機能に対応するとか、 1文字入力関数もgetchar()でなく画面エコーしない関数を使うとか、 他にも考慮すべき点が多々ありますが、質問とかけ離れますので割愛しています。 要は、1文字ずつ入力して、都度チェックしてバッファにためる数値文字入力専用の関数を 作ればいいのではないでしょうか。 1行入力して、文字列の中身を検査して不適当な文字があれば再入力するようにするのが 一番簡単ですが、そういうものをご希望なんですか。

  • MovingWalk
  • ベストアンサー率43% (2233/5098)
回答No.4

#3に方のご指摘のように、gets() は使用しないほうがいいですよ。 セキュリティホールの元凶になっている関数です。 文字数が制限できないので、バッファが溢れると弊害が出ます。 VCではどうか知りませんが、gccなどで"dangerous"というWarningが出ます。 ところでDOSアプリケーションでしたら、 getchar()で1文字入力が可能じゃなかったでしょうか。 で、こんな感じではどうでしょう。  int c, n=0;  char buf[BLEN+1];  while((c=getchar()) != '\r') {   if(('0' <= c) && (c <= '9')) {     buf[n++]=c;     if(n > BLEN)      break;    }  }  buf[n]='\0';

maruchan432
質問者

補足

回答頂きましてありがとうございます。 上記のサンプルは文字0から9の入力の場合には、 配列に入力文字を格納するものですが、 これでは126とか-46など、 2桁以上の数字や、負の整数には対応できないようです。 こちらの質問の方法が不充分だったようで、 申し訳ありませんでした。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.3

私なら… int val[MAX], no ; char str[LEN] ; char *p ; for (no = 0 ; no < MAX && fgets(str, LEN, stdin) != NULL ; no++) {   val[no] = strtol(str, 10, &p) ;   if (p != NULL && (*p != '\0' && *p != '\n')) {     //10進数でない入力     //エラー処理   } } こんな感じにするかと… gets関数の問題点: 入力文字数を制限できないのでエラー入力が想定できる場合は使用しないほうがよい。

maruchan432
質問者

補足

回答くださいましてありがとうございます。 読ませていただいたところ、 自分の知識不足で読み解けないコーディングがあります。 for (no = 0 ; no < MAX && fgets(str, LEN, stdin) != NULL ; no++) {   val[no] = strtol(str, 10, &p) ;   if (p != NULL && (*p != '\0' && *p != '\n')) {     //10進数でない入力     //エラー処理 恥ずかしながら、知らない関数があったりして、 論理構造が読み解けません。   人の好意に甘えて怠けすぎるのもいけないと思うので、 自分でも理解できるようもう少し調べてみようと思います。 ヒントをありがとうございます。

  • mneko
  • ベストアンサー率33% (46/139)
回答No.2

キー入力を原則的に文字列で入力します。 No.1のkyeongilさんの書かれているgets関数でchar型の配列に入れ、 これをisdigit関数で1文字ずつチェックして0~9までの文字であれば そのまま正常にatoi関数で整数に変換して戻し値にして、0~9以外の 文字が含まれていたらエラーコードを返す関数を作っておきます。 なお、isdigit関数は#include<ctype.h>    atoi関数は #include<stdlib.h> をインクルードいて置きます。 判らないときは、補足でレス下さい、サンプルコードを書きます。。

maruchan432
質問者

補足

回答していただきありがとうございます。 getsやgetcharでは、 一文字ずつしか読み込めず、 複数桁やマイナスの整数には対応できないようです。 その場合はどうすべきか、 自分でももうちょっと考えてみようと思います。 ヒントをくださり、ありがとうございます。

関連するQ&A

  • C言語の整数の判別

    最近C言語の勉強を始めたのですが、 C言語で、整数だけの入力を許可してそれ以外(文字等)が入力された場合は整数を入力して下さいというメッセージにとばすプログラムを作りたいのですがどうも作り方が良く分からず困っています、いったいどのように作れば良いでしょうか?? 宜しくお願いいたします!

  • 整数分割

    乱数で発生させた整数を配列に格納してその配列の整数を桁ごとに分割する簡単な方法はありますか。 例えば123を1と2と3に分割 整数を文字列に直して分割しようとしたけど整数は配列に格納されている (a[0]=123のように)のでできません。javaでプログラムを教えてください

  • 配列に好きな個数の整数を格納したい

    配列に好きな個数の整数を格納したい 以下のようにプログラムを組んだのですが、 Ctrl+Zを入力してもEOFと判断されず繰り返しが終了しませんでした。 int vc[100] , no=0; puts("整数を入力してください。"); while(1){ scanf("%d",&vc[no]); if(vc[no]==EOF) break; no++; } 使わないような数9999等にするしかないのでしょうか?

  • processingの文字入力について

    現在、プログラミング言語processingを勉強しているのですが、どのようにプログラムを書いたらいいか分からないので、教えてください。 作ろうとしているのは、フラッシュ暗算を行うプログラムなのですが、 processingの場合は、文字入力するときに、1文字しか認識されませんが、 もし2文字、3文字などを入力したい時は、どのようにすればいいのでしょうか? 例えば、フラッシュ暗算で、合計値が52だったとき、52を入力すると、正解とでるプログラムを作りたいわけですが、おそらく配列を使うと思いますが、いったいどのようにしたら52という数字を配列に格納させればいいのでしょうか?

  • 大きさ10の配列に次の10個の整数が格納されている。

    大きさ10の配列に次の10個の整数が格納されている。   2、-8、5、-4,6,5,7、-3、-9,1 奇数、偶数、負の数がそれぞれいくつあるかを数え表示するプログラムはどのように書けばいいですか、教えてください。 奇数=6 偶数=4 負=4 と表示されるようにしたいです。

  • c# 配列の受け取り方

    こんにちは、 c#言語で、RETURNの返しが配列の場合 どのように疎ければよいのでしょうか? メイン処理 strmtcにrun_mainから帰ってくる配列を格納したい string[] strmtc = run_main(""); run_main処理 // カンマ区切りで分割して配列に格納する string[] sarray; sarray = s.Split(','); return sarray;

  • C言語配列

    c言語初心者ですよろしくお願いします。 ファイルから読み込んだ100万件のデータをstaticを使わずに配列に格納したいのですが。 どういった方法があるでしょうか? 私のpcでは変数名[10000]くらいがエラーのでない限界みたいです。

  • C言語の文字列操作について

    C言語について質問です。 整数を入力させ、その入力された整数に’1’が含まれているかどうかを調べるプログラムを作りたいのですが、うまくできません。 文字列操作を使えばよいのですかね? 可能であればプログラムを書いていただきたいです。

  • C言語で全角文字を扱いたいのですが、

    C言語で全角文字を扱いたいのですが、 全角文字列を入力して特定の箇所の文字(例えば3文字目)を抜き出して、表示するという感じのプログラムをしたいのですが、うまくいきません。 半角文字ならば、配列を使ってできるのですが・・・・・

  • C言語 文字列格納

    テキストファイルから整数データ又は文字列を読み込んで配列に格納する動作についての質問です。 テキストファイルが1行区切りの整数型なら1次元配列で for(i = 0; i < maxSize; i++) { fscanf(fp,"%d", &data[i]); } テキストファイルが1行区切りの文字列なら2次元配列で for(i = 0; i < MAXSIZE; i++) { if (fscanf(fp,"%s", &data[i][300]) == EOF) break; } for(j = 0; j < i; j++) printf("%s\n", data[j]); みたいな具合に格納できたんですが、 テキストファイルが1行区切りのデータではなく、空白文字区切りの文字データだった場合、それぞれどのようにして配列に格納すればいいかがわかりません。 イメージとしては、1文字目から見ていって空白が出ればそこで切って格納していくというかんじなのですが・・・ 質問の内容がわかりにくいかもしれませんが、是非教えてください。お願いします。

専門家に質問してみよう