質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

1136閲覧

C 言語 scanf で入力された文字列の文字を調べたい

kokok

総合スコア145

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/07/30 01:43

c

1 2int check_number(char str[]); 3 4 5int main(void) { 6 7 char map[WORLD_H][WORLD_W]; 8 9 10 11 int checkno; 12 char inva[50]; //入力された値 13 14 printf("数字を入力してください(乱数) 文字または文字列を入力してください(ファイル読み込み) 21行以上エラー"); 15 scanf("%s", &inva); 16 17 checkno = check_number(inva); //数値か文字、文字列かのチェック。     18 19 20 if (checkno == -1) { //入力された値が文字か文字列だった場合 21 22 fileop(map); 23 } 24 25 else { //入力された値が数値だった場合 26 27 28 srand((unsigned)inva); 29 30 init_map(map); //初期化 31 } 32 33} 34 35 36//入力されたものが数値か文字、文字列か判定 37int check_number(char str[]) { 38 39 int retval = 0; 40 int len; 41 int i; 42 43 len = strlen(str); 44 45 if (len > 21) return -1; //21桁以上はエラー 46 47 for (i = 0; i < len; i++) { 48 49 if (str[i] < '0' || str[i] > '9') return -1; //0~9以外の文字val はエラー 50 51 retval = retval * 10 + (str[i]); 52 53 54 } 55 56 return retval; 57 58 59} 60

scanfで入力されたものが数値か文字、文字列かの判定を上記のコードでしました。(指摘点があればアドバイスお願い致します)

入力された文字、文字列の 後ろ4文字が .txt だったらテキストファイルを読み込み、違ったらテキストファイルではありません。  としたいのですが 一般的にどのようにして 後ろの文字が ,txtだったらのように 判定するのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takabosoft

2019/07/30 01:56 編集

これは課題か何かですか?(例えばWindowsであればWindows APIを利用する事は許可されていますか?)
kokok

2019/07/30 02:24

課題に自分で色々付けくわえてる感じです。 出来れば、APIを利用せずに書きたいと考えてます
guest

回答3

0

ベストアンサー

どのようにして、後ろの文字が ,txtだったら、のように判定する?

int check_txt(char str[]);
という、検査する文字列を引数として受け取り、

  • 文字列の最後が ".txt" だったら 1 を返す
  • そうでなかったら 0 を返す

関数を考えることにします。判定方法はいくつか考えられます。

  • str 文字列の先頭から '.' を探して、そこから 't', 'x', 't' と比較する。
  • まず、str 文字列の終端'\0'を見つけ、そこから逆順に 't', 'x', 't', '.' と比較する
  • まず、str 文字列の長さを求め、4文字戻って、そこから '.', 't', 'x', 't' と比較する。

他にもアイディアがあると思います。方法はひとつとは限りませんが、どちらかというと泥臭い感じです苦笑。でもコンピュータは、こういう泥臭いことを、何度でも、プログラムされた通り間違いなく、不平も言わずコツコツ(でも高速に)繰り返すことで、役にたつ作業をしてくれるんですよ。
テストデータも幾つか考えてみました。

  • "abcd.txt", "abcd.txtx", "txt", "abc_txt"
  • ".txt", "abc.txz.txt", "abc.txt.txt", "abc..txt"
  • "Abcd.TXT", "abcD.Txt"

これらの文字列をみて、1 を返すのはどれか、0 を返すのはどれか、ご自分で決めてください。check_txt()を設計する際に、どんな点に気をつければよいか、わかってくると思います。
ただし、実際にコードを作る時のコツは

  • 一度に完成させようとしない。段階的に進める
  • まず "abcd.txt" と "abcd.txtx" を判別できる程度の、ユルい関数を作ってみる
  • 他のテストデータに対応できないか、少しずつ考えていく
  • なぜ判定を間違う場合があるのか、間違う理由を見つけて対策を考える
  • 全てのテストデータに対応できなくても、なんとか実用になるものができたら、自分を褒める笑

文字列を扱うのですから、<string.h> に定義されている文字列操作関数を見てください。一通り目を通しながら、上で考えた判定方法の、どこかに使えそうな関数が無いか、考えてください。特に比較関数と探索関数です。

大文字・小文字をどう扱うかは、ファイル名を OS(Windows, Linux等)がどう扱うか調べれば、決められます。数字か文字か、大文字か小文字か等の判定には <ctype.h> に定義されている文字種分類関数が役に立ちます。

今のうちは後回しでかまいませんが、ある程度使える関数を作れたら、正規表現という言葉をググってみるとよいかもしれません。

Enjoy!

P.S.

C

1 retval = retval * 10 + (str[i]);

明らかなバグです。数字列(例えば"165")を入力し、変換した結果、正しい数値(この場合 165)になったことを確認しましたか?まったく動作確認してないことがバレバレなコードに見えます。こういう所をいいかげんにしていると、いつまでも初心者のままです。

投稿2019/07/31 00:47

編集2019/07/31 21:39
rubato6809

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

前回回答した、check_numberの作者です。
このように使われることは、想定していません。
21桁の数値を格納できる型をC言語は持ってません。int型で行う場合、10桁以上の数値は正しく変換できません。よって、check_numberは、文字列を数値にした結果を返すのでなく、
戻り値=0:全て'0'~'9'の文字で構成されている
戻り値=-1:全て'0'~'9'の文字で構成されていない(どこかに'0'~'9'以外の文字がある)
とすべきです。
そうすると、以下のようになります。

C

1int check_number(char str[]) { 2 3 int retval = 0; 4 int len; 5 int i; 6 7 len = strlen(str); 8 9 if (len > 21) return -1; //21桁以上はエラー 10 11 for (i = 0; i < len; i++) { 12 13 if (str[i] < '0' || str[i] > '9') return -1; //0~9以外の文字val はエラー 14 } 15 return 0; 16}

尚、言い忘れましたが、長さ0の文字列("")の場合は0が返ります。このケースをどうしたいかはあなたの判断で、対応してください。

もう一点、気になるのが
(unsigned)invaの箇所ですが、あなたの気持ちとしては、
入力された文字列が、"1234"なら1234という数値を作り出したいのかと想像できます。
残念ながら、そうはなりません。
srandで乱数の種を指定するなら、現在の時刻をしてするのが一般的ですが、そうしたくない理由がなにかあるのでしょうか。(同じデータに対しては、同じ乱数を生成したいとか等)

投稿2019/07/30 02:22

tatsu99

総合スコア5438

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kokok

2019/07/30 04:15

ありがとうございます。 とても勉強になります。
rubato6809

2019/07/30 23:13

> (unsigned)invaの箇所ですが char inva[50]; と定義した「配列の先頭アドレス」が「inva」の値です。そこに格納した文字・数字とは一切関係の無い値です。(unsigned) というキャストは、「そのアドレスを unsigned の値として扱う」というだけ。
guest

0

文字列の後ろ4文字目からstrcmp関数で ".txt" と比較する、というテですが、
大文字小文字を問わず、としたいなら自前でそういう関数を組む必要がありますね

投稿2019/07/30 01:55

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kokok

2019/07/30 02:20

ありがとうございます。 配列の後ろから4文字比較の仕方があまり分かりませんでした。 一度、配列の後ろ4文字も取り出したほうが良いのでしょうか?
y_waiwai

2019/07/30 02:25

strlenで文字列の長さがわかります 文字列のアドレスがs とすると、 s+strlen(s)-4 で、後ろ4文字目のアドレスが出てきますんで、 strcmp(s+strlen(s)-4,".txt") とします
kokok

2019/07/30 04:15

ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問