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

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

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

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

Q&A

解決済

4回答

2417閲覧

整数型の最大値より大きな値、または最小値よりも小さな値となった場合には変換しないようにしたい

party_0621

総合スコア9

C

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

0グッド

1クリップ

投稿2020/08/18 18:27

編集2020/08/18 19:46

下のような感じで数字の文字列を整数値に変換するプログラムを作ってみました。このプログラムを整数型の最大値より大きな値、または最小値よりも小さな値となった場合には変換しないようにしたいんですが、どのようにしたらうまくいきますか?
また、下のプログラムでダメな部分があれば教えてください!!

#include<stdio.h> #include<ctype.h> int str2value(const char suuji[]) { if(isdigit(suuji[0])){ int seisuu = suuji[0] - '0'; for(int i = 1; isdigit(suuji[i]); i++){ seisuu *= 10; seisuu += suuji[i] - '0'; } return seisuu; } else return 0; } int main(void) { char s[256]; while(scanf("%s", s) == 1){ const int n = str2value(s); printf("%d\n", n); } return 0; }

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

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

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

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

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

cateye

2020/08/18 20:53

環境(OS,コンパイラ等)は何でしょう?
mjk

2020/08/18 22:30

文脈から察するにint型の範囲内、負数も処理(※isdigitは0-9しか判定出来ない)、条件外は0を返すということならまだ処理出来ていないと思われます。 以下取り急ぎご参考までに。 https://nashiza-blog.com/2020/04/25/ressonc-013/
guest

回答4

0

sizeof(int) < sizeof(long long) の前提で書いてみました。

C

1#include <stdio.h> // scanf, printf 2#include <ctype.h> // isspace, isdigit 3#include <limits.h> // INT_MIN, INT_MAX 4 5int str2value(const char suuji[]) 6{ 7 unsigned char *p = (unsigned char *)suuji; 8 while (isspace(*p)) p++; 9 int neg = 0; 10 if (*p == '-') neg = 1, p++; 11 else if (*p == '+') p++; 12 if (!isdigit(*p)) return 0; 13 long long val = *p++ - '0'; 14 while (isdigit(*p)) { 15 val = val * 10 + *p++ - '0'; 16 if (neg ? -val < INT_MIN : val > INT_MAX) return 0; 17 } 18 return (int)(neg ? -val : val); 19} 20 21int main(void) 22{ 23 char s[256]; 24 while (scanf("%255s", s) == 1){ 25 const int n = str2value(s); 26 printf("%d\n", n); 27 } 28 return 0; 29}

atoi と同じ仕様で、+ と - の符号があってもよく、
さらにその前に空白があってもよいものとします。
また、数字の後に数字以外の文字があってもよいものとします。

isdigit(c) の c は unsigned charの値、または EOF の値なので、
-1~255 しか許されません。
char が符号付で -128~127 だと負の値を渡すことがあって動作は未定義です。
半角片仮名や平仮名や漢字だとそうなります。
それも考慮して unsigned char *p; を使っています。

投稿2020/08/19 13:51

kazuma-s

総合スコア8224

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

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

0

愚直に書いてみたら意外と面倒でした。
(もっとスマートな回答がされることを期待します。)

入力された文字列がint型の最大最小範囲内ならint型の変数に代入し同じものを出力する。
数値に変換出来ない文字だったり範囲外ならint型ではない旨のメッセージを出力する。

C

1#define _CRT_SECURE_NO_WARNINGS 2#include <ctype.h> 3#include <stdbool.h> 4#include <stdio.h> 5#include <stdlib.h> 6 7// int型の数値の範囲ならtrueを返す 8bool isInt(const char strNumber[], const int strSize) { 9 10 // 先頭1桁目の数値判定と負数判定 11 bool flag_minus = false; 12 if (strNumber[0] == '-') { 13 flag_minus = true; 14 } else if (!(isdigit(strNumber[0]))) { 15 return false; 16 } 17 18 // 桁数取得 19 int digitSize = 0; 20 for (int i = 1; i < strSize; i++) { 21 if (strNumber[i] == '\0') { 22 digitSize = i; 23 break; 24 } 25 if (!(isdigit(strNumber[i]))) { 26 return false; 27 } 28 } 29 30 // 11桁以上または0桁以下は範囲外 31 if (digitSize < 1 || digitSize > (10 + flag_minus)) { 32 return false; 33 } 34 35 // int型最大値=2147483647 36 const int intMaxDigitNumbersPlus[10] = {2, 1, 4, 7, 4, 8, 3, 6, 4, 7}; 37 // int型最小値=-2147483648 38 const int intMaxDigitNumbersMinus[10] = {2, 1, 4, 7, 4, 8, 3, 6, 4, 8}; 39 40 if (flag_minus) { 41 // 10桁の場合のみ全桁チェック 42 if (digitSize == (11)) { 43 for (int i = 0; i < digitSize; i++) { 44 if (intMaxDigitNumbersMinus[i] < strNumber[i + 1] - '0') { 45 return false; 46 } else if (intMaxDigitNumbersMinus[i] == strNumber[i + 1] - '0') { 47 continue; 48 } else { 49 return true; 50 } 51 } 52 } 53 } else { 54 // 10桁の場合のみ全桁チェック 55 if (digitSize == (10)) { 56 for (int i = 0; i < digitSize; i++) { 57 if (intMaxDigitNumbersPlus[i] < strNumber[i] - '0') { 58 return false; 59 } else if (intMaxDigitNumbersPlus[i] == strNumber[i] - '0') { 60 continue; 61 } else { 62 return true; 63 } 64 } 65 } 66 } 67 68 // 正:10文字未満、または10文字で2147483647ならtrue 69 // 負:11文字未満、または11文字で-2147483648ならtrue 70 return true; 71} 72 73// int型の数値の最大値: 2147483647 74// int型の数値の最小値: -2147483648 75// int型の数値の範囲ならint型に変換する 76int main(void) { 77 char strNumber[256]; 78 while (scanf("%s", strNumber)) { 79 int strSize = 256; 80 // 先にint型範囲内の整数に変換可能かisInt()関数で判定する 81 // isInt()関数の結果がtrueならatoi()関数で文字列からint型の整数に変換して出力 82 int intNumber; 83 if (isInt(strNumber, strSize)) { 84 intNumber = atoi(strNumber); 85 printf("%d\n", intNumber); 86 } else { 87 printf("%s %s\n", strNumber, " は、int型ではありません。"); 88 } 89 } 90 getchar(); 91 return 0; 92}

txt

11234567890 21234567890 32147483647 42147483647 52147483648 62147483648 は、int型ではありません。 7-1234567890 8-1234567890 9-2147483648 10-2147483648 11-2147483649 12-2147483649 は、int型ではありません。 130 140 15abc 16abc は、int型ではありません。 17あいう 18あいう は、int型ではありません。 19

投稿2020/08/19 07:03

mjk

総合スコア303

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

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

kazuma-s

2020/08/19 08:35

桁数で判定していいのでしょうか? 007 は正しい int で、 00000000007 は正しい int ではないのですか?
mjk

2020/08/19 10:03

ご指摘ありがとうございます。そこまで気付きませんでした。 1桁目が0の扱いをどうするかなど細かいルールがあれば再度検討してみます。
guest

0

負値は変換してないようなので、0 以下はあり得ないので
最大値だけで良さそうです。
#include <limits.h>
を追加して、
for(int i = 1; isdigit(suuji[i]); i++){
if((INT_MAX - (suuji[i] - '0'))/10 < seisuu) return 0; // 追加
seisuu *= 10;
seisuu += suuji[i] - '0';
}

くらいでいいのでは?
それまでの数値までだけ変換するのであれば
return 0; でなく break; にすればいいかな?

追加
n2q37_cppさんのソースに付加するのも気が引けるので
自分が書いたソースに付加しておきます

#include <stdio.h> #include <ctype.h> #include <limits.h> int str2value(const char *p) { char minus = 0; unsigned ret = 0; switch (*p) { case '-': minus = 1; case '+': p++; } unsigned limits = minus ? 0U - INT_MIN : INT_MAX; while (isdigit(*p)) { int no = *p++ - '0'; if ((limits - no) / 10 < ret) break; ret = ret * 10 + no; } return minus ? -ret : ret; } int main() { char str[16]; while (fgets(str, sizeof str, stdin)) printf("%d\n", str2value(str)); return 0; }

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10230218750?__ysp=c3RyMnZhbHVl

投稿2020/08/18 22:22

編集2020/08/19 13:35
PingHermit

総合スコア478

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

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

0

ベストアンサー

#include <limits.h>
とすると、シンボル INT_MAX, INT_MINが使えるようになります。それぞれintの最大値、最小値です。
値を操作して桁あふれが発生してしまうと最大値以下の値(あるいは最小値より大きい値)になってしまうので、
「値を何かしら操作する前に、操作しても大丈夫なのかどうか」という形で検査を行う必要があります。

C

1 if(INT_MAX/10 >= seisuu){ 2 //10倍しても最大値を超えない 3 seisuu *= 10; 4 }else{ 5 //最大値を超える 6 seisuu = 0; 7 break; 8 } 9 if (INT_MAX - seisuu >= suuji[i] - '0') { 10 //足しても最大値を超えない 11 seisuu += suuji[i] - '0'; 12 } else { 13 //最大値を超える 14 seisuu = 0; 15 break; 16 }

下のプログラムでダメな部分

いうまでもなく、負数に対応していないところ。
「整数型の最小値よりも小さな値」を問題にするということは当然負の数も対象ですね?

while(scanf("%s", s) == 1){
ではループから脱出できないのでは。

ダメではないけれど、
char s[256];
は余裕がありすぎに思えます。

投稿2020/08/18 22:16

編集2020/08/19 12:44
thkana

総合スコア7703

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

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

kazuma-s

2020/08/18 23:47

INT_MAX が 2147483647 の場合がほとんどですが、 この修正では、その値が入力できず 0 になってしまいます。 また、4300000000 を入力しても 0 になりません。
thkana

2020/08/19 03:34

> kazuma-sさん ですねぇ。10倍して超えるのを見逃してちゃだめじゃん。あとで直します。
thkana

2020/08/19 12:44

直しました。
PingHermit

2020/08/19 13:39

while(scanf("%s", s) == 1){ でのループから脱出は、ctrl+z で出きます。 Windows の場合、2~3度 ctrl+z が必要かもしれないが。
thkana

2020/08/19 13:46

質問者ではなくプログラムの製作者は while(scanf("%s", s) == 1){ はそこでCtrl-Zを入力するという意図だったようです。なるほどそれなら抜けられる。
thkana

2020/08/19 13:48

っと、かぶったか。Windowsの場合、というよりMicrosoft Cがなんか変なんじゃない、という話ですね>Ctrl+Z何回か
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問