四則演算プログラムについて
四則演算プログラムについて
いつもお世話になっております@とんぷぅ~です。
今回も四則演算のプログラムなのですが、条件としては
①括弧を用いた計算を可能にする。
②スペースを入れなくても計算できるようにする。
③どんな整数を入力しても計算結果が正しく表示されるようにする。
というものなんですが、②については1 + 1 = 2を1+1=2でも計算
できるようにするということです。これはコマンドライン引数
から取得する方法でも可能なんでしょうか?
③については具体的に、桁の数を20や30にしても計算できるように
するということなんですが、これは型といったことを全く無視して
行うのでしょうか?どうすればよいのか全く思いつきません。
皆様よろしくお願いします。
今回も四則演算のプログラムなのですが、条件としては
①括弧を用いた計算を可能にする。
②スペースを入れなくても計算できるようにする。
③どんな整数を入力しても計算結果が正しく表示されるようにする。
というものなんですが、②については1 + 1 = 2を1+1=2でも計算
できるようにするということです。これはコマンドライン引数
から取得する方法でも可能なんでしょうか?
③については具体的に、桁の数を20や30にしても計算できるように
するということなんですが、これは型といったことを全く無視して
行うのでしょうか?どうすればよいのか全く思いつきません。
皆様よろしくお願いします。
Re:無題
まず、四則演算を計算するには、スタックが有効ではないかと思いますが、スタックの利用方法についてはよろしいでしょうか?
(どこから解説すればよいかが変わってきますので)
あと、スタックで計算する場合、
1 + 1
は
1 1 +
になりますが、後者のままではよくないのでしょうか?
昔似たような投稿がありました。
http://www.play21.jp/board/formz.cgi?ac ... q&rln=2980
Justyさんのお書きになったサンプルは時間がたったため自動削除されてしまったようですが、
スタックを使った四則演算プログラムならすぐ作れます。
(どこから解説すればよいかが変わってきますので)
あと、スタックで計算する場合、
1 + 1
は
1 1 +
になりますが、後者のままではよくないのでしょうか?
昔似たような投稿がありました。
http://www.play21.jp/board/formz.cgi?ac ... q&rln=2980
Justyさんのお書きになったサンプルは時間がたったため自動削除されてしまったようですが、
スタックを使った四則演算プログラムならすぐ作れます。
Re:無題
# @とんぷぅ~さん
>取得する方法でも可能なんでしょうか?
問題なく可能です。
複数のコマンドライン引数で与えられた計算式でも、1つの文字列に結合するか、
要素毎に分離するかしてしまえば楽に処理できるはずです。
>どうすればよいのか全く思いつきません
桁数が大きい数値の演算をするには、1つの手として多倍長整数を使うというのがあります。
ググれば出てきますので、調べてみてください。
# 管理人 さん
>時間がたったため自動削除
懐かしいスレですね。
あー、添付した物は過去ログ行きになると消えるんですね。
消えてくれると嬉しい物もあったりするので、助かるといえば助かります(w
>取得する方法でも可能なんでしょうか?
問題なく可能です。
複数のコマンドライン引数で与えられた計算式でも、1つの文字列に結合するか、
要素毎に分離するかしてしまえば楽に処理できるはずです。
>どうすればよいのか全く思いつきません
桁数が大きい数値の演算をするには、1つの手として多倍長整数を使うというのがあります。
ググれば出てきますので、調べてみてください。
# 管理人 さん
>時間がたったため自動削除
懐かしいスレですね。
あー、添付した物は過去ログ行きになると消えるんですね。
消えてくれると嬉しい物もあったりするので、助かるといえば助かります(w
Re:無題
LONGLONG型を使ってみるのもいいかと思います。
#include <stdio.h> #include <windows.h> int main(){ int i; LONGLONG a=1; for(i=1;i<64;i++) printf("2^%-2d = %I64d\n",i,a*=2); return 0; } 実行結果 2^1 = 2 2^2 = 4 2^3 = 8 ・・・(略) 2^60 = 1152921504606846976 2^61 = 2305843009213693952 2^62 = 4611686018427387904 2^63 = -9223372036854775808
Re:無題
あら・・、学校でスタックを使ったサンプルを作ってたのに、忘れてて帰ってきてしまった(T_T
すみません、、、。
しかし今回の課題を見るとスタックを使った方法では実現出来そうにないですね。
1 + 1
を
1 1 +
と入力する事になりますが、スペースをなくすと11になってしまいますし。
http://www.google.co.jp/search?hl=ja&q= ... %83%89&lr=
この辺を参考に調べてみてください。
私はスタックを利用した四則演算しかパッと思いつかないのですが、
サンプルをもう一度作ってみます。
後は全てカッコや四則演算子を全て個別に一つずつ解析していく方法しか思いつきませんが、
それは賢くないですよね。。
すみません、、、。
しかし今回の課題を見るとスタックを使った方法では実現出来そうにないですね。
1 + 1
を
1 1 +
と入力する事になりますが、スペースをなくすと11になってしまいますし。
http://www.google.co.jp/search?hl=ja&q= ... %83%89&lr=
この辺を参考に調べてみてください。
私はスタックを利用した四則演算しかパッと思いつかないのですが、
サンプルをもう一度作ってみます。
後は全てカッコや四則演算子を全て個別に一つずつ解析していく方法しか思いつきませんが、
それは賢くないですよね。。
Re:無題
スタックについてはご存知のようですので、そのまま スタックを使った四則演算のサンプルを提示します。 以下のような計算式は (1+1) * (2+2) / (4-2) このように書きます。 1 1 + 2 2 + * 4 2 - / 実行計算過程はこのようになります。 1 1 + 2 2 + * 4 2 - / データ: 1 データ: 1 1 データ: 2 データ: 2 2 データ: 2 2 2 データ: 2 4 データ: 8 データ: 8 4 データ: 8 4 2 データ: 8 2 データ: 4 4 以下サンプルプログラムです。 #include <stdio.h> #include <stdlib.h> #define RET 0 #define NUMBER 1 #define PLUS 2 #define MINUS 3 #define MULT 4 #define DIV 5 #define OTHER 6 #define stack_size 100 int stack[stack_size]; int sp; void push(int x){//配列要素番号を1増やして引数を格納する。 if (sp < stack_size-1) stack[++sp] = x; else { printf("スタックがいっぱい。 \n"); exit(1); } } int pop(){//返り値に配列要素を返して配列要素番号を1減らす if (sp >= 0) return stack[sp--]; else { printf("スタック空っぽエラー.\n"); exit(1); } } void print_stack(){ int i; if (sp < 0) { printf("スタックがからっぽ\n"); return; } printf("データ: "); for(i=0; i<=sp; i++) printf("%d ", stack); printf("\n"); } int gettoken(int *num){ int c, n; while ((c = getchar()) == ' ' || c == '\t');//スペースを読み飛ばす switch(c){ /*ここから入力文字列を数値に変換*/ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = c - '0';//文字を数値に変換 while(1) {//入力された文字列を数値に変換 c = getchar();//1文字取得 if ('0' <= c && c <= '9'){//0~9まで n = 10*n + c - '0'; } else { break; } } *num = n; /*ここまで*/ return NUMBER; //読んでいる入力情報によって返り値を分岐 case '+' : return PLUS; case '-' : return MINUS; case '*' : return MULT; case '/' : return DIV; case '\n': return RET; default : return OTHER; } } int main(){ int token, num, x; token = gettoken(&num);//numに数値を入れ、tokenに識別番号を入れる。 sp =-1; //sp初期化 while(token != RET) {//tokenが改行で無い限り switch(token){ case NUMBER: push(num); break;//数値ならプッシュ case PLUS : push(pop() + pop());//プラスなら2つ取り出して取り出した2つを格納する。 break; case MINUS : x = pop(); push(pop() - x); break; case MULT : push(pop() * pop()); break; case DIV : x = pop(); if (x != 0) { push(pop() / x); break; } else { printf("0割り禁止\n"); exit(1); } case OTHER : printf("不正な文字\n"); exit(1); } print_stack(); token = gettoken(&num); } if (sp+1== 1) printf("%5d\n", pop()); else { printf("シンタックスエラー\n"); exit(1); } return 0; }
Re:無題
管理人さん。boxさんありがとうございました。
>後は全てカッコや四則演算子を全て個別に一つずつ解析していく方法しか
私も調べたところ、この方法が一番いいのかと思ったのですが、あまり賢い
方法ではないかもしれませんね。
>数値用のスタックと演算子(カッコを含む)用のスタックを別々に用意
そんな方法があるのですね。しかし難しそうですね。
スタックについてもまだまだ勉強しなければいけないですね。
>スタックを使った四則演算のサンプル
サンプルありがとうございました。動かしてみたんですが、やはり逆ポーランド
ではなく、一般的な表記法 1 + ( -5 ) = -4になるような方法じゃないと無理
みたいです。
ちなみに以前作成したサンプルです。関数化してない為見にくいと思いますが
これは整数型の四則演算を行うプログラムです。扱える範囲を2147483647~-2147483648としています。
これにベースに上記の3つの条件を付け足したプログラムを作成しろということなんですが、
これまではオーバーフローばかりを気にしていたのに、今度は全く逆に何桁
でも計算出来るようにすると言ったギャップにとまどっています(笑)
長くなってしまって申し訳ありません。
>後は全てカッコや四則演算子を全て個別に一つずつ解析していく方法しか
私も調べたところ、この方法が一番いいのかと思ったのですが、あまり賢い
方法ではないかもしれませんね。
>数値用のスタックと演算子(カッコを含む)用のスタックを別々に用意
そんな方法があるのですね。しかし難しそうですね。
スタックについてもまだまだ勉強しなければいけないですね。
>スタックを使った四則演算のサンプル
サンプルありがとうございました。動かしてみたんですが、やはり逆ポーランド
ではなく、一般的な表記法 1 + ( -5 ) = -4になるような方法じゃないと無理
みたいです。
ちなみに以前作成したサンプルです。関数化してない為見にくいと思いますが
これは整数型の四則演算を行うプログラムです。扱える範囲を2147483647~-2147483648としています。
これにベースに上記の3つの条件を付け足したプログラムを作成しろということなんですが、
これまではオーバーフローばかりを気にしていたのに、今度は全く逆に何桁
でも計算出来るようにすると言ったギャップにとまどっています(笑)
/**************************************** * * * NAME 【sisokenzan.c】 * * SYNOPSIS【sisokenzan lop op rop】* * * *****************************************/ #pragma warning ( disable : 4996 ) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <limits.h> #include <math.h> int main ( int argc, char *argv[/url] ) { int max = INT_MAX; // 表現可能な最大値 int min = INT_MIN; // 表現可能な最小値 long long lop; // 左のオペランドに入力する値 long long rop; // 右のオペランドに入力する long long mod; // 除算の余り long long result; // 計算結果を格納 char *check; // 変換不可能な文字を格納 char op; // 入力する演算子 // 引数の個数チェック if ( argc != 4 ) { printf ( "usage : %s lop(Left operand) op(Operator) rop(Right operand)\n", argv[0] ); exit ( 0 ); } // 引数を整数型に変換 lop = atoi ( argv[1] ); rop = atoi ( argv[3] ); // 引数の取得(配列中の先頭文字) op = ( argv[2][0] ); // lopが整数であるか文字であるかのチェック lop = strtol ( argv[1], &check, 10 ); if ( errno != ERANGE ) { if ( *check != '\0' ) { printf ( "error : Please input the integer\n" ); exit ( 0 ); } // lopに範囲を超えた値が入力された場合 } else { printf ( "error : The range of the int type is exceeded\n" ); exit ( 0 ); } // ropが整数であるか文字であるかのチェック rop = strtol ( argv[3], &check, 10 ); if ( errno != ERANGE ) { if ( *check != '\0' ) { printf ( "error : Please input the integer\n" ); exit ( 0 ); } // lopに範囲を超えた値が入力された場合 } else { printf ( "error : The range of the int type is exceeded\n" ); exit ( 0 ); } if ( strlen ( argv[2] ) >= 2 ) { printf ( "error : Please input the operator correctly\n" ); exit ( 0 ); } // 演算子ごとに計算 switch ( op ) { case '+' : result = lop + rop; break; case '-' : result = lop - rop; break; case '*' : result = lop * rop; break; case '/' : if ( rop == 0 ) { printf ( "error : 0 division is a prohibition\n" ); exit ( -1 ); } // 除算のオーバーフローを考慮 if ( ( lop == min ) && ( rop == -1 ) ) { printf ( "error : The overflow learns by experience\n" ); exit ( 0 ); } result = lop / rop; mod = lop % rop; // 割り算の結果として余りが出なかった場合 if ( mod == 0 ) { printf ( "%lld %c %lld = %lld", lop, op, rop, result ); exit ( 0 ); // 割り算の結果として余りが出た場合 } else if ( mod != 0 ) { printf ( "%lld %c %lld = %lld余り%lld", lop, op, rop, result, mod ); exit ( 0 ); } break; default: printf ( "error : Please input either of operator '+', '-', '*', '/'\n" ); exit ( 0 ); } // 加、減、乗算のオーバーフローを考慮 if ( ( result > max ) || ( result < min ) ) { printf ( "error : The overflow learns by experience\n" ); exit ( 0 ); } // 数値1 演算子 数値2 = 演算結果の形式で出力する printf ( "%lld %c %lld = %lld", lop, op, rop, result ); exit ( 0 ); }
長くなってしまって申し訳ありません。
Re:無題
管理人さん。boxさん。レスありがとうございます。
<スペースがなくても(そして、あっても)
これはスペース無しだけの場合ならコマンドライン引数を
取得する方法で可能なのでしょうか?
<コマンドラインから行う方がよけいに面倒な処理になると思います
そうですよね。すごく大変そうです。明日もう一度確認してみますね。
<カッコを含むスタックを個別に用意する方法
私もこれを考えたのですが、どうコーディングしようか考え中です。
皆様の意見を参考にしながら、明日もう一度調べてみます。
そしてたぶんまた来ます(笑)
ちなみに、①~③まで一度に出来ればいいのでしょうけど、私には
難しそうなので、まずどの条件からクリアすればよいのかアドバイス頂ければ
幸いです(もしくは一度にやった方がよいのでしょうか?)
よろしくお願いします。
<スペースがなくても(そして、あっても)
これはスペース無しだけの場合ならコマンドライン引数を
取得する方法で可能なのでしょうか?
<コマンドラインから行う方がよけいに面倒な処理になると思います
そうですよね。すごく大変そうです。明日もう一度確認してみますね。
<カッコを含むスタックを個別に用意する方法
私もこれを考えたのですが、どうコーディングしようか考え中です。
皆様の意見を参考にしながら、明日もう一度調べてみます。
そしてたぶんまた来ます(笑)
ちなみに、①~③まで一度に出来ればいいのでしょうけど、私には
難しそうなので、まずどの条件からクリアすればよいのかアドバイス頂ければ
幸いです(もしくは一度にやった方がよいのでしょうか?)
よろしくお願いします。
Re:無題
>多倍長整数とは難しそうですが
たしかに多倍長整数を効率よく処理するルーチンをいきなり書くのは大変かもしれませんが、
多少効率を無視していいのなら比較的簡単です。
小学校の頃に加減乗除の筆算って習いませんでしたか?
加算なら縦に2つの数字を並べて下の桁から1桁ずつ対応した桁同士を処理し、
溢れたら溢れた分を次の桁に、ってアレです。
アレをそのままプログラムに落とし込めば・・・40桁限定なら、10進数での桁数、
各桁の数字(40個の配列)、符号の情報を構造体にして管理すればかなり簡単に
多倍長整数を扱えるはずです。
>引数については結合か結合
どちらかといったら結合の方がいいかもしれませんね。
ついでにスペースやタブなどの空白が含まれていたら削りながら
結合すると、必要な式の部分だけが残ってより解析しやすくなるはずです。
>スペース無しだけの場合ならコマンドライン引数を取得する方法で可能なのでしょうか?
式が入っている引数の数の分だけ文字列を結合するのが面倒であれば、
最悪、コマンドラインから与える式を ""(ダブルクォーテーション)で囲めば1つの
引数として式が main関数に入ってきますよ。
>①~③まで一度に出来ればいいのでしょうけど
>まずどの条件からクリアすればよいのか
んー、私なら、
1 まず本当にコマンドラインから式を受け取る必要があるのかどうか
必要があるなら、コマンドライン引数から文字列の結合を行い式を組み立てる。
必要がないなら、適当にユーザーに入力させる
2 桁数の問題
3 最後に括弧を含む式の解析。
ですね。
たしかに多倍長整数を効率よく処理するルーチンをいきなり書くのは大変かもしれませんが、
多少効率を無視していいのなら比較的簡単です。
小学校の頃に加減乗除の筆算って習いませんでしたか?
加算なら縦に2つの数字を並べて下の桁から1桁ずつ対応した桁同士を処理し、
溢れたら溢れた分を次の桁に、ってアレです。
アレをそのままプログラムに落とし込めば・・・40桁限定なら、10進数での桁数、
各桁の数字(40個の配列)、符号の情報を構造体にして管理すればかなり簡単に
多倍長整数を扱えるはずです。
>引数については結合か結合
どちらかといったら結合の方がいいかもしれませんね。
ついでにスペースやタブなどの空白が含まれていたら削りながら
結合すると、必要な式の部分だけが残ってより解析しやすくなるはずです。
>スペース無しだけの場合ならコマンドライン引数を取得する方法で可能なのでしょうか?
式が入っている引数の数の分だけ文字列を結合するのが面倒であれば、
最悪、コマンドラインから与える式を ""(ダブルクォーテーション)で囲めば1つの
引数として式が main関数に入ってきますよ。
>①~③まで一度に出来ればいいのでしょうけど
>まずどの条件からクリアすればよいのか
んー、私なら、
1 まず本当にコマンドラインから式を受け取る必要があるのかどうか
必要があるなら、コマンドライン引数から文字列の結合を行い式を組み立てる。
必要がないなら、適当にユーザーに入力させる
2 桁数の問題
3 最後に括弧を含む式の解析。
ですね。
Re:無題
何だか話がちぐはぐになってきた気がしています。
>コマンドラインから受け取った引数が 1 * 2の3つの場合
3つ、つまりargv[1]~argv[3]に受け取ったということは、
1と*と2の間にそれぞれスペースがあった、ということです。
したがって、
>引数に空白無し
>ファイル名.exe 1*2 = 2
こちらのケースはありません。
>引数に空白無し
>ファイル名.exe 1*2 = 2
こうなるのは、1と*と2を続けて(スペースを空けずに)書いたときで、
この場合、argv[1]に"1*2"という内容を格納しています。
1と*と2の間にそれぞれスペースを空けて書いたのなら
argv[1]~argv[3]の3つを結合して最終的に"1*2"という文字列を
組み立てればよいです。
一方、1と*と2をスペースなしに書いたのなら、
見るべきところはargv[1]だけなので、最初から"1*2"という文字列を得ています。
いずれにせよ、argv[1]~argv[n]のn個(nは1以上)の文字列を結合して
数式の文字列(途中にスペースがない)を得ればよいのです。
その後、文字列の中身の解析を行ないます。
>コマンドラインから受け取った引数が 1 * 2の3つの場合
3つ、つまりargv[1]~argv[3]に受け取ったということは、
1と*と2の間にそれぞれスペースがあった、ということです。
したがって、
>引数に空白無し
>ファイル名.exe 1*2 = 2
こちらのケースはありません。
>引数に空白無し
>ファイル名.exe 1*2 = 2
こうなるのは、1と*と2を続けて(スペースを空けずに)書いたときで、
この場合、argv[1]に"1*2"という内容を格納しています。
1と*と2の間にそれぞれスペースを空けて書いたのなら
argv[1]~argv[3]の3つを結合して最終的に"1*2"という文字列を
組み立てればよいです。
一方、1と*と2をスペースなしに書いたのなら、
見るべきところはargv[1]だけなので、最初から"1*2"という文字列を得ています。
いずれにせよ、argv[1]~argv[n]のn個(nは1以上)の文字列を結合して
数式の文字列(途中にスペースがない)を得ればよいのです。
その後、文字列の中身の解析を行ないます。
Re:無題
boxさんありがとうございました。
<1と*と2の間にそれぞれスペースを空けて書いたのなら
argv[1]~argv[3]の3つを結合して最終的に"1*2"という文字列を
組み立てればよいです。
これはコマンドライン引数をargv[1]~argv[3]まで取得したという
ことですよね?それなら結合しなくても結果は出るのではないでしょうか?
どうしても結合するということが理解できません。
<いずれにせよ、argv[1]~argv[n]のn個(nは1以上)の文字列を結合
して数式の文字列(途中にスペースがない)を得ればよいのです。
コマンドライン引数を取得して実行する方法は普通、プロンプトで
引数にスペースを空けて行いますよね? 例 1 + 1
それが引数にスペースを空けないで実行するということが
やはり引っかかってきます。 例 1+1
1 + 1の場合は引数がargv[1]~argv[3]に格納されていることは
理解できるのですが、1+1の場合は一つの文字列としてargv[1]のみ
に格納されているといった考えでよいのでしょうか?
もしその考えが合っているならば、引数のチェック(この場合だと)
if ( argc != 4 ) {
printf ( "usage : %s lop(Left operand) op(Operator) rop(Right operand)\n", argv[0] );
exit ( 0 );
}
この部分からおかしいということなのでしょうか?
混乱してきました。知識不足で申し訳ありません。
文章がおかしい部分も多々あると思いますが、よろしくお願いします。
<1と*と2の間にそれぞれスペースを空けて書いたのなら
argv[1]~argv[3]の3つを結合して最終的に"1*2"という文字列を
組み立てればよいです。
これはコマンドライン引数をargv[1]~argv[3]まで取得したという
ことですよね?それなら結合しなくても結果は出るのではないでしょうか?
どうしても結合するということが理解できません。
<いずれにせよ、argv[1]~argv[n]のn個(nは1以上)の文字列を結合
して数式の文字列(途中にスペースがない)を得ればよいのです。
コマンドライン引数を取得して実行する方法は普通、プロンプトで
引数にスペースを空けて行いますよね? 例 1 + 1
それが引数にスペースを空けないで実行するということが
やはり引っかかってきます。 例 1+1
1 + 1の場合は引数がargv[1]~argv[3]に格納されていることは
理解できるのですが、1+1の場合は一つの文字列としてargv[1]のみ
に格納されているといった考えでよいのでしょうか?
もしその考えが合っているならば、引数のチェック(この場合だと)
if ( argc != 4 ) {
printf ( "usage : %s lop(Left operand) op(Operator) rop(Right operand)\n", argv[0] );
exit ( 0 );
}
この部分からおかしいということなのでしょうか?
混乱してきました。知識不足で申し訳ありません。
文章がおかしい部分も多々あると思いますが、よろしくお願いします。
Re:無題
@とんぷぅ~さん、この課題は多分例によって上司の方に出されたものだと思うのですが、
この問題は少し敷居が高い感じがします。
前と同じように新人研修の課題ですか?
>どうしても結合するということが理解できません
もう既に理解されているかもしれませんが、一応簡単に。
argv[1] ・・・ "1+3"
argv[2] ・・・ "(-"
argv[3] ・・・ "4"
argv[4] ・・・ "*-2"
argv[5] ・・・ ")"
という状態で main関数に文字列が渡ってきます。
これを解析する場合、変数が複数に分かれているので、とても扱いづらい状態です。
(表示することを考えても5つもあると面倒ですよね? ましてや実行してみないといくつに
わかれているかはわからない)
そこで、
combine[/url] ・・・"1+3(-4*-2)"
とこのように1つの文字列にして纏めてしまえば、解析・表示が楽になる、
というわけです。
これが文字列の「結合」です。
[color=#d0d0d0" face="sans-serif]# ちなみに挙動としてはこんな感じですかね? (calc_test.exe)
[/color]
07/05/24 22:32 バージョンアップ
この問題は少し敷居が高い感じがします。
前と同じように新人研修の課題ですか?
>どうしても結合するということが理解できません
もう既に理解されているかもしれませんが、一応簡単に。
[color=#d0d0ff" face="monospace] > xxxx.exe 1+3 (- 4 *-2 )[/color]
この状態で実行するとargv[1] ・・・ "1+3"
argv[2] ・・・ "(-"
argv[3] ・・・ "4"
argv[4] ・・・ "*-2"
argv[5] ・・・ ")"
という状態で main関数に文字列が渡ってきます。
これを解析する場合、変数が複数に分かれているので、とても扱いづらい状態です。
(表示することを考えても5つもあると面倒ですよね? ましてや実行してみないといくつに
わかれているかはわからない)
そこで、
combine[/url] ・・・"1+3(-4*-2)"
とこのように1つの文字列にして纏めてしまえば、解析・表示が楽になる、
というわけです。
これが文字列の「結合」です。
[color=#d0d0d0" face="sans-serif]# ちなみに挙動としてはこんな感じですかね? (calc_test.exe)
[/color]
07/05/24 22:32 バージョンアップ
Re:無題
バイトで遅くなりました・・((グッタリ
お力になれず、すみません、、。
あ、コマンドラインの受け取った文字列達をまとめると言うのはJustyさんの仰ったとおりです。
コマンドラインの入力値を一つの文字列にまとめるプログラムのサンプルだけお書きします。
省きましたけど途中に
とか実際は書いた方がいいと思います。
おやすみなさいませ・・zzZZ
お力になれず、すみません、、。
あ、コマンドラインの受け取った文字列達をまとめると言うのはJustyさんの仰ったとおりです。
コマンドラインの入力値を一つの文字列にまとめるプログラムのサンプルだけお書きします。
#include <stdio.h>
#include <stdlib.h>
#define N 1000
int main( int argc , char *argv[ ] ){
int i,j,s=0;
char st[N];
for(i=1;i<argc;i++){
j=0;
while(argv[j]!=NULL)
st[s++]=argv[j++];
}
st='\0';
printf("%s\n",st);
return 0;
}
実行結果
C:\test3\Debug>test3 (1+2) * (a /b - 1) /2.1 +1
(1+2)*(a/b-1)/2.1+1
省きましたけど途中に
if(s>=N){
printf("多すぎ");
exit(99);
}
とか実際は書いた方がいいと思います。
おやすみなさいませ・・zzZZ
Re:無題
あ、途中配列要素数の所に++使っている部分が解り難かったかも知れませんので、
補足です。
以下を見てもらえたら解るとおり、i++は値が評価された後で1増やす。
++iはまず最初に1増やすと言う事です。
つまり、式の中でとiを指定してその後、i++;と2行に分けて書くのと同じ事です。
補足です。
以下を見てもらえたら解るとおり、i++は値が評価された後で1増やす。
++iはまず最初に1増やすと言う事です。
つまり、式の中でとiを指定してその後、i++;と2行に分けて書くのと同じ事です。
#include <stdio.h> int main(){ int i=0; char st[/url]="123456"; printf("%c\n",st[i++]); printf("%c\n",st[i++]); printf("%c\n",st[i++]); printf("%c\n",st[i++]); return 0; } 実行結果 1 2 3 4 #include <stdio.h> int main(){ int i=0; char st[/url]="123456"; printf("%c\n",st[++i]); printf("%c\n",st[++i]); printf("%c\n",st[++i]); printf("%c\n",st[++i]); return 0; } 実行結果 2 3 4 5
Re:無題
例えば今、 int a[10]; で宣言すると、初期化をしていないので、中身はゴミが入っていますね。 [0] [1] [2] [3] [4]............ --------------------------.......... | | | | | |.......... --------------------------.......... ↓ -------------------------- |ゴミ|ゴミ|ゴミ|ゴミ|ゴミ| -------------------------- a[0]='a'; a[1]='b'; a[2]='c'; と代入すれば [0] [1] [2] [3] [4] -------------------------- | a | b | c |ゴミ|ゴミ| -------------------------- こんな感じになります。 コンパイラは入っているものがゴミなのか、代入した値なのかわかりませんから、 %s(終端記号までの文字列を表示せよ)で表示すると、終端記号まで探して表示しますから、ゴミまで表示されます。 ですから'c'を代入したところで文字列を終わりにしたいならちゃんと終端記号をいれてやらないと a[3] = '\0'; [0] [1] [2] [3] [4] -------------------------- | a | b | c | \0 |ゴミ| -------------------------- 文字列がどこまでなのかわかりません。 今回は%sで表示すると、[2]までの値が表示されるはずです。 文字列の最後には必ず終端記号が必要です。 char a[10]="abc"; と宣言してもちゃんとコンパイラがa[3]='\0';してくれているので、きちんと表示できるのです。 終端記号をいれずに表示してみてください。ゴミも表示されるはずです。
Re:無題
argvは2次元配列だと思って、そのそれぞれにスペースで区切った文字列が入るイメージを思い浮かべればいいです。
test.exe (3+ 1)/23-9 + 41*2 char argv[5][10]; strcpy(argv[0],"test.exe"); strcpy(argv[1],"(3+"); strcpy(argv[2],"1)/23-9"); strcpy(argv[3],"+"); strcpy(argv[4],"41*2"); 実際こうではないですが、こういうイメージです。 ん~逆にややこしいですかね。 まぁとにかく argv[1] [2] [3] [4] "(3+" , "1)/23-9" , "+" , "41*2" にわかれている文字列を st "(3+1)/23-9+41*2" にしたいんです。 で、 st[0] = argv[1][0]; をすると "(" が入るのはわかりますよね?argv[1][1]は "3" argv[1][2]は "+" argv[1][3]はヌルです。 これがヌルではない間コピーします。すると最初の文字列がコピーできます。 stに入れた添え字はそのままに、次に新しい文字列 "1)/23-9" を格納すると連続してコピーできます。 それを最後までコピーしていって、最後にヌル文字いれれば全部コピー完了した文字列の出来上がりです。
Re:無題
>思い通りに動くようになったら、コードを1文ずつ説明して、
うわー、それはキッツイですね。
それじゃぁ、曖昧な部分があったら速攻で突っ込まれますからね、大変だ。
>Justyさんが配布してくれたプログラムのような
>動きに少しでも近づけるように頑張ります。
計算結果しか出していないんで、どれだけ参考になるかわかりませんが、
@とんぷ~さんのプログラムが完成した際の結果の検証くらいには使えるかと。
あ、そうそう。
ちょっとバグがあったので上のプログラムを更新してあります。
一見無限桁の演算ができるようにみえて、実は理論的に5万桁以上同士の乗算をしたときに
計算結果が希におかしくなる問題があったのでこっそり修正しました。
まだ何か結果がおかしいようでしたら言って下さい。
うわー、それはキッツイですね。
それじゃぁ、曖昧な部分があったら速攻で突っ込まれますからね、大変だ。
>Justyさんが配布してくれたプログラムのような
>動きに少しでも近づけるように頑張ります。
計算結果しか出していないんで、どれだけ参考になるかわかりませんが、
@とんぷ~さんのプログラムが完成した際の結果の検証くらいには使えるかと。
あ、そうそう。
ちょっとバグがあったので上のプログラムを更新してあります。
一見無限桁の演算ができるようにみえて、実は理論的に5万桁以上同士の乗算をしたときに
計算結果が希におかしくなる問題があったのでこっそり修正しました。
まだ何か結果がおかしいようでしたら言って下さい。
Re:無題
2次元配列になったからといって特に難しい事はないですよ。
配列の先頭アドレスが[0]から順に入っていった配列が上にもう一つあるということです。
st[0]は"abcdef"をさしていて、
st[1]は"ghujkl"をさしています。
st[0][0]は'a'をさしていて、
st[2][1]は'n'をさしています。
理論は難しくなくてもなれていないと難しく感じるものですよね。
要は慣れですので、とにかく色んな配列のサンプルを実行したり、
自分でプログラムを書いてドンドンコンパイルする事が一番だと思います。
頑張ってください。
配列の先頭アドレスが[0]から順に入っていった配列が上にもう一つあるということです。
char st[4][10]={ {"abcdef"}, {"ghijkl"}, {"mnopqr"}, {"stuvwx"} }
st[0]は"abcdef"をさしていて、
st[1]は"ghujkl"をさしています。
st[0][0]は'a'をさしていて、
st[2][1]は'n'をさしています。
理論は難しくなくてもなれていないと難しく感じるものですよね。
要は慣れですので、とにかく色んな配列のサンプルを実行したり、
自分でプログラムを書いてドンドンコンパイルする事が一番だと思います。
頑張ってください。
Re:無題
1文字ずつ調査すればいいのではないでしょうか?
例えば
argv[1][0]には今「1」が入っていますよね?
argv[1][0+1]には「+」が入っています。
この数字と文字を分けたいということなんですよね?
現在調査している要素が文字なら、そこで調査を一時停止して、そこまでを一つの文字列とし、
atoiなどを用いて文字を数値に変換します。
調査を開始して、次は文字のはずですから、1文字とってきて演算子として記憶する、次はカッコか数値のはずですからそれ以外ならエラー、などではどうでしょうか?
つまり、今
char st[/url]="123+456*-";
こんな文字列が入っているとします。
st[0]を調査、数値なので、次へ
st[1]を調査、数値なので、次へ
st[2]を調査、数値なので、次へ
st[3]を調査、記号なので[2]までを一つの文字列として、その文字列を数値に変換。どこかへ保存。
st[3]は演算子としてどこかに保存。
(st[4]はカッコか数値のはず。)
st[4]を調査、数値なので、次へ
st[5]を調査、数値なので、次へ
st[6]を調査、数値なので、次へ
st[7]を調査、記号なので、[6]までを一つの文字列として、その文字列を数値に変換。どこかへ保存。
st[7]は演算子としてどこかに保存。
(st[8]はカッコか数値のはず。)
st[8]を調査、カッコでも数値でもないのでエラー終了。
こんな感じでどうでしょう?
例えば
argv[1][0]には今「1」が入っていますよね?
argv[1][0+1]には「+」が入っています。
この数字と文字を分けたいということなんですよね?
現在調査している要素が文字なら、そこで調査を一時停止して、そこまでを一つの文字列とし、
atoiなどを用いて文字を数値に変換します。
調査を開始して、次は文字のはずですから、1文字とってきて演算子として記憶する、次はカッコか数値のはずですからそれ以外ならエラー、などではどうでしょうか?
つまり、今
char st[/url]="123+456*-";
こんな文字列が入っているとします。
st[0]を調査、数値なので、次へ
st[1]を調査、数値なので、次へ
st[2]を調査、数値なので、次へ
st[3]を調査、記号なので[2]までを一つの文字列として、その文字列を数値に変換。どこかへ保存。
st[3]は演算子としてどこかに保存。
(st[4]はカッコか数値のはず。)
st[4]を調査、数値なので、次へ
st[5]を調査、数値なので、次へ
st[6]を調査、数値なので、次へ
st[7]を調査、記号なので、[6]までを一つの文字列として、その文字列を数値に変換。どこかへ保存。
st[7]は演算子としてどこかに保存。
(st[8]はカッコか数値のはず。)
st[8]を調査、カッコでも数値でもないのでエラー終了。
こんな感じでどうでしょう?
Re:無題
# @とんぷぅ~さんへ
>例えば1+1として(スペース無し)の場合
>argv[1]に1+1が入っているので、その文字列を解析して
argv[2]以降に一切「式」が入っていないことが保証できるのであれば、argv[1]を解析してください。
>数値なら '1'と'+'と'1'という具合に解析をして計算させれば良いのでしょうか?
基本的にはそうです。
ただ、括弧付きを扱うのであれば計算の順番を正しく判定する必要があります。
>isdigit関数などを使用して数値か判別をすれば良いのでしょうか?
数値かどうかなら yes。
# 管理人さんへ
>?st[8]を調査、カッコでも数値でもないのでエラー終了。
式が "123+456*-"ならエラーになりますが、"123+456*-5"ならエラーにはならないですよね?
>例えば1+1として(スペース無し)の場合
>argv[1]に1+1が入っているので、その文字列を解析して
argv[2]以降に一切「式」が入っていないことが保証できるのであれば、argv[1]を解析してください。
>数値なら '1'と'+'と'1'という具合に解析をして計算させれば良いのでしょうか?
基本的にはそうです。
ただ、括弧付きを扱うのであれば計算の順番を正しく判定する必要があります。
>isdigit関数などを使用して数値か判別をすれば良いのでしょうか?
数値かどうかなら yes。
# 管理人さんへ
>?st[8]を調査、カッコでも数値でもないのでエラー終了。
式が "123+456*-"ならエラーになりますが、"123+456*-5"ならエラーにはならないですよね?
Re:無題
管理人さん。Justyさん。お世話になっております。
>argv[1][0+1]には「+」が入っています
この[0+1]というのはどういうことなのでしょうか?
>この数字と文字を分けたいということなんですよね?
はい。数字であるならatoiなどで、数値に変換して計算
可能な状態にするようにしたいです。
>argv[2]以降に一切「式」が入っていないことが保証できるのであれば、argv[1]を解析してください。
今回は引数が最大でも4つになる( 1 + 1 = 2 )ので、スペースを入れない場合argv[1]のみになります。
(考え方が間違っていたらすみません)
>括弧付きを扱うのであれば計算の順番を正しく判定する必要があります。
今のところまず、括弧や桁数を意識しないで、スペース有りor無しで普通に
四則演算が出来るコードを書いてみようと思います。
ちなみに2007/05/22(火) 22:07でのコードを元に作成しているのですが、
コードを根本的に変えていかなければならないのでしょうか?
ちなみに解析で文字列を読み込む際に、コマンドライン引数から読み込む
ことは可能なのでしょうか?getcharなどを読み込みに使うと入力待ちに
なってしまう為、よろしくないです。
長々となってしまい申し訳ありません。よろしくお願いいたします。
>argv[1][0+1]には「+」が入っています
この[0+1]というのはどういうことなのでしょうか?
>この数字と文字を分けたいということなんですよね?
はい。数字であるならatoiなどで、数値に変換して計算
可能な状態にするようにしたいです。
>argv[2]以降に一切「式」が入っていないことが保証できるのであれば、argv[1]を解析してください。
今回は引数が最大でも4つになる( 1 + 1 = 2 )ので、スペースを入れない場合argv[1]のみになります。
(考え方が間違っていたらすみません)
>括弧付きを扱うのであれば計算の順番を正しく判定する必要があります。
今のところまず、括弧や桁数を意識しないで、スペース有りor無しで普通に
四則演算が出来るコードを書いてみようと思います。
ちなみに2007/05/22(火) 22:07でのコードを元に作成しているのですが、
コードを根本的に変えていかなければならないのでしょうか?
ちなみに解析で文字列を読み込む際に、コマンドライン引数から読み込む
ことは可能なのでしょうか?getcharなどを読み込みに使うと入力待ちに
なってしまう為、よろしくないです。
長々となってしまい申し訳ありません。よろしくお願いいたします。
Re:無題
キーボードからの入力を必要としないならgetcharは必要ないでしょう。
もうすでに配列に文字列がはいっているのですから、配列要素を一つずつ調べたら同じ事です。
コマンドラインから可能かという質問は前にもお答えしましたよね?
複数にわかれた文字列を一つにするプログラムのサンプルもお書きしたと思います。
括弧なしの計算なら簡単です。
私の書いたスタックに合うように文字列をおいてやればいいだけです。
しかし括弧つきに応用が出来ませんから、もし括弧を実現すべきなのなら1からほかの考え方で作ったほうがよさそうです。
すみませんが、私には括弧つき計算でいい方法が思いつきません。
もうすでに配列に文字列がはいっているのですから、配列要素を一つずつ調べたら同じ事です。
コマンドラインから可能かという質問は前にもお答えしましたよね?
複数にわかれた文字列を一つにするプログラムのサンプルもお書きしたと思います。
括弧なしの計算なら簡単です。
私の書いたスタックに合うように文字列をおいてやればいいだけです。
しかし括弧つきに応用が出来ませんから、もし括弧を実現すべきなのなら1からほかの考え方で作ったほうがよさそうです。
すみませんが、私には括弧つき計算でいい方法が思いつきません。
Re:無題
# 管理人さん
>私は数式でマイナスを書けるとき必ず括弧を書きますけど、省略できるんです
一応省略しても「式」的には正しく読みとれそうですが。
たしかに言われてみれば "3*(-5)"では省略はしない方がいいのかもしれませんね。
でも "-5*3"の時は省略しますね。
う~む。この場合も括弧つけた方がいいでしょうか。"(-5)*3"みたいに
あとは()の前に付く場合ですね。 "4 * -(1 + 5)"とか。
>どこまで実現するべきかは仕様によりますね
ですね。
# @とんぷぅ~さん
>括弧や桁数を意識しないで、スペース有りor無しで普通に
>四則演算が出来るコードを書いてみようと思います
つまり括弧はなし、桁数はlong longの範囲で、スペースの有無はどちらでも、ということですね。
>コードを根本的に変えていかなければならないのでしょうか
最終的なコードは大幅に異なるものになりそうです。
が、上記の条件(括弧なしとか)であれば延長線上でいけそうな気がします。
>コマンドライン引数から読み込む ことは可能なのでしょうか?
今までどこから読み込んでいたのでしょうか?
>私は数式でマイナスを書けるとき必ず括弧を書きますけど、省略できるんです
一応省略しても「式」的には正しく読みとれそうですが。
たしかに言われてみれば "3*(-5)"では省略はしない方がいいのかもしれませんね。
でも "-5*3"の時は省略しますね。
う~む。この場合も括弧つけた方がいいでしょうか。"(-5)*3"みたいに
あとは()の前に付く場合ですね。 "4 * -(1 + 5)"とか。
>どこまで実現するべきかは仕様によりますね
ですね。
# @とんぷぅ~さん
>括弧や桁数を意識しないで、スペース有りor無しで普通に
>四則演算が出来るコードを書いてみようと思います
つまり括弧はなし、桁数はlong longの範囲で、スペースの有無はどちらでも、ということですね。
>コードを根本的に変えていかなければならないのでしょうか
最終的なコードは大幅に異なるものになりそうです。
が、上記の条件(括弧なしとか)であれば延長線上でいけそうな気がします。
>コマンドライン引数から読み込む ことは可能なのでしょうか?
今までどこから読み込んでいたのでしょうか?
Re:無題
管理人さん。Justyさん。レスありがとうございます。
>もうすでに配列に文字列がはいっているのですから、配列要素を一つずつ調べたら
はい。その通りなのですが、その「調べる」ということが理解出来ておりません。
何が分かっていないからなのでしょうか?
>私の書いたスタックに合うように文字列をおいてやればいいだけ
スタックについてのサンプルありがとうございました。しかし今回
どうしても、自分でコーディングしたソースを元に作りたいのです。
(スペース有りor無しだけについて)
>コマンドライン引数から読み込む ことは可能なのでしょうか?
すみません。コピペでミスをしてしまいました。意味不明なことを
言ってすみませんでした。
>つまり括弧はなし、桁数はlong longの範囲で、スペースの有無はどちらでも、ということですね。
はい。そういうことになります。
>どこまで実現するべきかは仕様によりますね
明記するのを忘れておりました。すみません。
今回は 1 + 2 - 3などの3項演算?はしないので、括弧による優先順位は関係ありません。
括弧をつける基準としては入力された数値が負数の場合は括弧で括るということだけで大丈夫です。
>数値かどうかなら yes
isdigitを使ってargv[1]に入っている文字列を解析しようと
思ったのですが、中々上手くいきません。。
こんなに有用な意見を頂いているのにやりたいことがパッと出てこない為、
皆様に大変迷惑を掛けてしまってすみません。
>もうすでに配列に文字列がはいっているのですから、配列要素を一つずつ調べたら
はい。その通りなのですが、その「調べる」ということが理解出来ておりません。
何が分かっていないからなのでしょうか?
>私の書いたスタックに合うように文字列をおいてやればいいだけ
スタックについてのサンプルありがとうございました。しかし今回
どうしても、自分でコーディングしたソースを元に作りたいのです。
(スペース有りor無しだけについて)
>コマンドライン引数から読み込む ことは可能なのでしょうか?
すみません。コピペでミスをしてしまいました。意味不明なことを
言ってすみませんでした。
>つまり括弧はなし、桁数はlong longの範囲で、スペースの有無はどちらでも、ということですね。
はい。そういうことになります。
>どこまで実現するべきかは仕様によりますね
明記するのを忘れておりました。すみません。
今回は 1 + 2 - 3などの3項演算?はしないので、括弧による優先順位は関係ありません。
括弧をつける基準としては入力された数値が負数の場合は括弧で括るということだけで大丈夫です。
>数値かどうかなら yes
isdigitを使ってargv[1]に入っている文字列を解析しようと
思ったのですが、中々上手くいきません。。
こんなに有用な意見を頂いているのにやりたいことがパッと出てこない為、
皆様に大変迷惑を掛けてしまってすみません。
Re:無題
すみません、ちょっと忙しくてお返事がちまちまになりそうです。
>しかし今回どうしても、自分でコーディングしたソースを元に作りたいのです。
人のプログラムを理解するのは大変ですし、自分で書いたほうが力になるので出来ることならそちらがいいと思います。
アルゴリズムはどのように考えています?
スタック使うのでしょうか?
> 1 + 2 - 3などの3項演算?はしないので
という意味がよくわからなかったのですが、今単純に「1+2」とか「3*2」とか3つ以上の数値は入力しないということなのでしょうか?(そんな簡単な事じゃないですよね^^;
>こんなに有用な意見を頂いているのにやりたいことがパッと出てこない為、皆様に大変迷惑を掛けてしまってすみません。
具体的なアドバイスが出来ていないので、わからなくても仕方ないと思いますし、遠慮なく情報交換しましょう。
結構最初の仕様を実現するのは難しいように思います。
>しかし今回どうしても、自分でコーディングしたソースを元に作りたいのです。
人のプログラムを理解するのは大変ですし、自分で書いたほうが力になるので出来ることならそちらがいいと思います。
アルゴリズムはどのように考えています?
スタック使うのでしょうか?
> 1 + 2 - 3などの3項演算?はしないので
という意味がよくわからなかったのですが、今単純に「1+2」とか「3*2」とか3つ以上の数値は入力しないということなのでしょうか?(そんな簡単な事じゃないですよね^^;
>こんなに有用な意見を頂いているのにやりたいことがパッと出てこない為、皆様に大変迷惑を掛けてしまってすみません。
具体的なアドバイスが出来ていないので、わからなくても仕方ないと思いますし、遠慮なく情報交換しましょう。
結構最初の仕様を実現するのは難しいように思います。
Re:無題
管理人さん。Justyさん。レスありがとうございます。
"管理人さん"
>今単純に「1+2」とか「3*2」とか3つ以上の数値は入力しないということなのでしょうか?
はいそうです。こんなことで質問して申し訳ありません。
ちょっと課題が難しいのでまずここからやってみてっていう感じになりました。
>結構最初の仕様を実現するのは難しいように思います。
そうですね~。最終的には最初の仕様になると思います。
"Justyさん"
>スペース有りor無しでも動くように、文字列の結合から着手してみてはどうですか?
こちらは管理人さんから頂いたサンプルを使用しているのですが、単純に
sprintf ( str, "%s", argv[1] )等でも良いのでしょうか?はたまたstrcat等を
使用するのか?その辺が疑問です。
>isdigitとargvでは型が違うので、上手くいかずに困っています。argvに入っている
文字列を1文字ずつ確認するには違う関数を使うのでしょうか?もしくはargvに入っている
文字列を切り出してから、1文字ずつ解析を行うのでしょうか?トークンあたりを調べて
みたのですが、あまり理解出来ませんでした。
長々失礼しました。
"管理人さん"
>今単純に「1+2」とか「3*2」とか3つ以上の数値は入力しないということなのでしょうか?
はいそうです。こんなことで質問して申し訳ありません。
ちょっと課題が難しいのでまずここからやってみてっていう感じになりました。
>結構最初の仕様を実現するのは難しいように思います。
そうですね~。最終的には最初の仕様になると思います。
"Justyさん"
>スペース有りor無しでも動くように、文字列の結合から着手してみてはどうですか?
こちらは管理人さんから頂いたサンプルを使用しているのですが、単純に
sprintf ( str, "%s", argv[1] )等でも良いのでしょうか?はたまたstrcat等を
使用するのか?その辺が疑問です。
>isdigitとargvでは型が違うので、上手くいかずに困っています。argvに入っている
文字列を1文字ずつ確認するには違う関数を使うのでしょうか?もしくはargvに入っている
文字列を切り出してから、1文字ずつ解析を行うのでしょうか?トークンあたりを調べて
みたのですが、あまり理解出来ませんでした。
長々失礼しました。
Re:無題
とんぷ~さんの回答を拝見するに、ちょっとトークンなどのライブラリ関数を用いずに、
文字列と配列、アドレスや文字コードなどの勉強もかねて、配列1つ1つを操作するプログラムを書いた方がいいように思います。
ライブラリ関数を用いるより自分で配列の内容を確認しながら作っていった方が仕組みがよくわかりますしね。
ちょっと戻って1から基本を見つめなおしましょう。
文字列というものは配列要素[0]から'\0'が入っている配列要素までをひとまとまりとするとかその辺の事をしっかりおさらいしてください。
きっと基本があやふやだと応用を効かせようとしたとき無理が来てわからなくなってしまうと思いますので。
では
「1+1」
が文字列として存在するとき
「1」「+」「1」にわけて2次元配列に格納する事から始めましょう。
単純に四則演算だけならすごく簡単ですから。
文字列と配列、アドレスや文字コードなどの勉強もかねて、配列1つ1つを操作するプログラムを書いた方がいいように思います。
ライブラリ関数を用いるより自分で配列の内容を確認しながら作っていった方が仕組みがよくわかりますしね。
ちょっと戻って1から基本を見つめなおしましょう。
文字列というものは配列要素[0]から'\0'が入っている配列要素までをひとまとまりとするとかその辺の事をしっかりおさらいしてください。
きっと基本があやふやだと応用を効かせようとしたとき無理が来てわからなくなってしまうと思いますので。
では
「1+1」
が文字列として存在するとき
「1」「+」「1」にわけて2次元配列に格納する事から始めましょう。
単純に四則演算だけならすごく簡単ですから。
Re:無題
サンプルを書きました。
入力はスペース無しで2つの値の四則計算のみという条件です。
入力はスペース無しで2つの値の四則計算のみという条件です。
#include <stdio.h> #include <string.h> #include <stdlib.h> void main(void){ int i=0,x[3]; char st[/url]="1+1",c; while(st!='\0'){ if( !(st>='0' && st<='9') ){ c=st; st='\0'; x[0]=atoi(st); x[1]=atoi(&st[i+1]); break; } i++; } printf("%d %c %d = ",x[0],c,x[1]); switch(c){ case '+': x[2]=x[0]+x[1]; break; case '-': x[2]=x[0]-x[1]; break; case '*': x[2]=x[0]*x[1]; break; case '/': x[2]=x[0]/x[1]; break; } printf("%d",x[2]); } 実行結果 1 + 1 = 2
Re:無題
st |-[0]---[1]---[2]---[3]--| | 1 | + | 1 | \0 | |------------------------| stの中身は上のような配置になっています。 while(st!='\0'){ で終端記号を見つけるまで順に配列の中身を調査していきます。 まず[0]です。 if( !(st>='0' && st<='9') ){ という意味は今調査している配列要素の中身が文字コード「0」から「9」までの間ではなかったら と言う意味です。数字か数字じゃないかという事ですね。 今回はスペースなし、記号は四則演算子しか入らないという条件の元これで可能です。 今[0]は「1」ですから条件にマッチせず、i++により[1]に調査対象が移動します。 [1]は「+」ですからif文の条件にマッチします。 c=st; これでcに演算子を格納します。 st='\0'; これにより、演算子までを一つの文字列として区切ります。 ただ今以下のようになっています。 st |-[0]---[1]---[2]---[3]--| | 1 | \0 | 1 | \0 | |------------------------| stと書くと[0]のアドレスの事です。&st[0]は配列の先頭アドレスで、文字列は[0]から始まり[1]で終わる文字列です。 一方文字列というのは示したアドレスから進んで終端記号が見つかるまでのひとまとまりですから、 [2]のアドレスを示せば、[2]から[3]までの文字列が示せる事になります。 ですから x[0]=atoi(st); x[1]=atoi(&st[i+1]); で、それぞれ2つの値が格納できる事がわかりますか?stと書いてありますが、 x[0]=atoi(&st[0]); と x[0]=atoi(st); は同じ意味です。 break; で処理を抜けます。 後は条件によって計算し、表示しているだけです。 おわかりになるでしょうか。 変にライブラリ関数を使うより配列の扱い方を勉強しながら順々に作ってみてはいかがでしょうか。 仕組みを理解しながら作っていった方が応用が効く様に思います。 また、サンプルの文字列はいろいろ変更してみて確認してください。 例) char st[/url]="4358-358"; 実行結果 4358 - 358 = 4000
Re:無題
>単純にsprintf ( str, "%s", argv[1] )等でも良いのでしょうか?
>はたまたstrcat等を 使用するのか?その辺が疑問です。
後者の方が判りやすいとは思いますが、どちらでもOKです。
>isdigitとargvでは型が違うので、上手くいかずに困っています。
>argvに入っている文字列を1文字ずつ確認するには違う関数を使うのでしょうか?
その関数で合ってますよ。
一応 isdigit(c)という形にまとめましたが、cは p[n]なので、isdigit(p[n])としても
isdigit(argv[1][n])としても正しく動くはずです。
>はたまたstrcat等を 使用するのか?その辺が疑問です。
後者の方が判りやすいとは思いますが、どちらでもOKです。
>isdigitとargvでは型が違うので、上手くいかずに困っています。
>argvに入っている文字列を1文字ずつ確認するには違う関数を使うのでしょうか?
その関数で合ってますよ。
[color=#d0d0ff" face="monospace]#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[/url])
{
if(argc >= 2)
{
size_t n, length;
const char *p = argv[1];
length = strlen(p);
for(n=0; n<length; ++n)
{
char c = p[n];
printf("%d文字目は [%c] ... ", n+1, c);
if(isdigit(c))
printf("%s\n", "数字");
else
printf("%s\n", "数字以外");
}
}
return 0;
}[/color]
argv[1]の中を1文字1文字解析して、数字かそれ以外かを判定しています。一応 isdigit(c)という形にまとめましたが、cは p[n]なので、isdigit(p[n])としても
isdigit(argv[1][n])としても正しく動くはずです。
Re:無題
管理人さん。Justyさん。レスありがとうございました。
ネットにトラブルがあり、レスが大変遅れて申し訳ありません。
"管理人さん"
>ちょっと戻って1から基本を見つめなおしましょう。
そうですね。今まで行き当たりバッタリで課題を行っていたので、
苦手と思う部分や、面倒と思う所を省いていました。今ままで配列にアクセス
するコードを書いた機会があまり無く、配列とループのセットが苦手なことが分かりました。
得に添え字が変数に置き換えられた多次元配列とループなどが、ソースを見てもパッと理解
することが出来ません。
ちなみに配列名は配列の先頭要素のアドレスを指すという部分なのですが
st[0]なら0のアドレスを指すということは分かります。ではargv[1][0]ならば
argv[1][0]のアドレスを指すのでしょうか?それともargv[0][0]?
すみません。テンパってきました。ただ管理人さんの説明のおかげで上記サンプル
はなんとか理解できました。
"Justyさん"
>const char *p = argv[1];
この1行はどういった意味なのでしょうか?
それと、よく見かけるsize_t型についてなんですが、一体
どのような場合に使われるんでしょうか?
ちなみに今現在の仕様なら、文字列を連結せずに
出来るような気がするのですが無理ですか?
(スペース有りなら今までのソースを元にして、無しなら
argv[1]に入っている文字列を文字に分けて解析して数値ならば)
という具合です。おかしい部分があったら言って下さい。
ネットにトラブルがあり、レスが大変遅れて申し訳ありません。
"管理人さん"
>ちょっと戻って1から基本を見つめなおしましょう。
そうですね。今まで行き当たりバッタリで課題を行っていたので、
苦手と思う部分や、面倒と思う所を省いていました。今ままで配列にアクセス
するコードを書いた機会があまり無く、配列とループのセットが苦手なことが分かりました。
得に添え字が変数に置き換えられた多次元配列とループなどが、ソースを見てもパッと理解
することが出来ません。
ちなみに配列名は配列の先頭要素のアドレスを指すという部分なのですが
st[0]なら0のアドレスを指すということは分かります。ではargv[1][0]ならば
argv[1][0]のアドレスを指すのでしょうか?それともargv[0][0]?
すみません。テンパってきました。ただ管理人さんの説明のおかげで上記サンプル
はなんとか理解できました。
"Justyさん"
>const char *p = argv[1];
この1行はどういった意味なのでしょうか?
それと、よく見かけるsize_t型についてなんですが、一体
どのような場合に使われるんでしょうか?
ちなみに今現在の仕様なら、文字列を連結せずに
出来るような気がするのですが無理ですか?
(スペース有りなら今までのソースを元にして、無しなら
argv[1]に入っている文字列を文字に分けて解析して数値ならば)
という具合です。おかしい部分があったら言って下さい。
Re:無題
>st[0]なら0のアドレスを指すということは分かります。
いえ、違います。st[0]のアドレスは&st[0]で示せます。st[0]と書くと[0]自身のデータを示します。
char st[10];
などで宣言した配列を「st」と書くと&st[0]の意味になります。すなわちst配列の先頭アドレスです。
以下を見てください。
上の1次元配列において、stと示すと[0]のアドレスを指します。
下の2次元配列において、
st[0]とさすと、st[0][0]~st[0][3]までの1次元配列と考えられる配列の先頭アドレスすなわち&st[0][0]を指します。
st[1]とさすと、st[1][0]~st[1][3]までの1次元配列と考えられる配列の先頭アドレスすなわち&st[1][0]を指します。
以下のように宣言すると、以下のように確保されます。
よくわからなければなんでもいいからとにかく疑問に思う表示の仕方やデータの入れ方をなんでもいいからつっこんでガンガンコンパイルしてみてください。
コンパイルした数だけ理解が深まるでしょう。
いえ、違います。st[0]のアドレスは&st[0]で示せます。st[0]と書くと[0]自身のデータを示します。
char st[10];
などで宣言した配列を「st」と書くと&st[0]の意味になります。すなわちst配列の先頭アドレスです。
以下を見てください。
st[4] st [0] [1] [2] [3] st[3][4]; st[0]-> [0][0] [0][1] [0][2] [0][3] st[1]-> [1][0] [1][1] [1][2] [1][3] st[2]-> [2][0] [2][1] [2][2] [2][3]
上の1次元配列において、stと示すと[0]のアドレスを指します。
下の2次元配列において、
st[0]とさすと、st[0][0]~st[0][3]までの1次元配列と考えられる配列の先頭アドレスすなわち&st[0][0]を指します。
st[1]とさすと、st[1][0]~st[1][3]までの1次元配列と考えられる配列の先頭アドレスすなわち&st[1][0]を指します。
以下のように宣言すると、以下のように確保されます。
char st[4]="123"; |-[0]---[1]---[2]---[3]--| | 1 | 2 | 3 | \0 | |------------------------| printf("%s",st); と書くと「123」が表示されるのは、stが&st[0]をさしているからです。 つまりstの部分はそこから右をまとまりとしたいアドレスを書けばいいわけですから、 printf("%s",&st[2]); こう書いてもいいわけです。 こうすると「3」が表示されます。 では応用で、2次元配列で考えて見ます。 2次元配列であろうと、3次元であろうと、配列は連続したアドレスに用意されます。 [0][0]の次のアドレスは[0][1]です。 char st[3][4];において [0][3]の次のアドレスは[1][0]です。今 st[0][0]='a'; st[0][1]='b'; st[0][2]='c'; st[0][3]='d'; st[1][0]='e'; st[1][1]='\0'; で格納すると以下のように入ります。 |-[0][0]---[0][1]---[0][2]---[0][3]--| | a | b | c | d | |-[1][0]---[1][1]---[1][2]---[1][3]--| | e | \0 | - | - | |-[2][0]---[2][1]---[2][2]---[2][3]--| | - | - | - | - | |------------------------------------| printfで示すアドレス先は特にどこでもいいのですから printf("%s",&st[0][1]); このように書けば「bcde」と表示されるはずです。 また、st[1]は[1]行目の1次元配列とみなせる配列の先頭アドレスですから、 printf("%s",st[1]); こうかけば「e」が出力されます。 #include <stdio.h> void main(){ char st[3][4]; st[0][0]='a'; st[0][1]='b'; st[0][2]='c'; st[0][3]='d'; st[1][0]='e'; st[1][1]='\0'; printf(" st[0] => %s\n",st[0]); printf("&st[0][1] => %s\n",&st[0][1]); printf(" st[1] => %s\n",st[1]); } 実行結果 st[0] => abcde &st[0][1] => bcde st[1] => e
よくわからなければなんでもいいからとにかく疑問に思う表示の仕方やデータの入れ方をなんでもいいからつっこんでガンガンコンパイルしてみてください。
コンパイルした数だけ理解が深まるでしょう。
Re:無題
>>const char *p = argv[1];
>この1行はどういった意味なのでしょうか?
argvの宣言は char *argv[/url]ですよね?
これは char **argvと扱い的には同じになります。
つまりポインタのポインタです。
で、argv[1]としたとき、これ自体の型は char *となり、普通の charポインタとなります。
でこのまま argv[1]として使い続けてもいいのですが、一端 argv[1]のポインタ値を
別の変数に入れた方が扱いやすいので、pという変数を用意して代入しています。
どう扱いやすくなるかというと 例えば argv[1]じゃなくて、argv[2]の解析を
しようとか考えたとき、ソースのあっちこっちに argv[1]が散乱していたら
書き換えるのが面倒ですよね?
そんなとき pに代入してあれば代入式の argv[1]を argv[2]に代えるだけで済みます。
又、別の変数に入れる、ということはその代入元の方の変数に別の名前を付けるという意味も生まれます。
サンプルでは pとしたので意味もへったくれもないですが、例えば
argv[0]・・・「1つ目の引数」という意味から app_name・・・「アプリケーション名」に
argv[1]・・・「2つ目の引数」という意味から exression_string・・・「式の文字列」になり
見ただけで意味が分かりやすくなるという効果があります。
>それと、よく見かけるsize_t型についてなんですが、
>一体どのような場合に使われるんでしょうか?
size_tはよく要素の数を表すのに使われます。
例えば文字列の長さを調べる標準関数 strlen()ですが、戻り値に文字列の長さが返って来ます。
しかし、戻り値の型は intではありません。size_tなのです。
実際 size_tが何なのかは環境によって違いますが、大抵は unsigned intか unsigned longのようです。
特に何もないのに積極的に size_tを使うことはありませんが、標準関数で size_t型が
指定されている場合はsize_t型を使った方がいいでしょう。
# sizeof()とかの結果の値も size_t型です。
>ちなみに今現在の仕様なら、文字列を連結せずに 出来るような
>気がするのですが無理ですか?
スペースがあった場合となかった場合で、ソース(解析・計算部分)を分けると言うことですか?
無理ではないと思いますが・・・。
スペースはあってもなくても受け付けるということは
もちろん、理論的には連結しなくてもできますが、ちょっとだけ面倒になります。
>この1行はどういった意味なのでしょうか?
argvの宣言は char *argv[/url]ですよね?
これは char **argvと扱い的には同じになります。
つまりポインタのポインタです。
で、argv[1]としたとき、これ自体の型は char *となり、普通の charポインタとなります。
でこのまま argv[1]として使い続けてもいいのですが、一端 argv[1]のポインタ値を
別の変数に入れた方が扱いやすいので、pという変数を用意して代入しています。
どう扱いやすくなるかというと 例えば argv[1]じゃなくて、argv[2]の解析を
しようとか考えたとき、ソースのあっちこっちに argv[1]が散乱していたら
書き換えるのが面倒ですよね?
そんなとき pに代入してあれば代入式の argv[1]を argv[2]に代えるだけで済みます。
又、別の変数に入れる、ということはその代入元の方の変数に別の名前を付けるという意味も生まれます。
サンプルでは pとしたので意味もへったくれもないですが、例えば
[color=#d0d0ff" face="monospace] const char *app_name = argv[0]
const char *exression_string = argv[1];
[/color]
としていたら、引数の名前の意味がargv[0]・・・「1つ目の引数」という意味から app_name・・・「アプリケーション名」に
argv[1]・・・「2つ目の引数」という意味から exression_string・・・「式の文字列」になり
見ただけで意味が分かりやすくなるという効果があります。
>それと、よく見かけるsize_t型についてなんですが、
>一体どのような場合に使われるんでしょうか?
size_tはよく要素の数を表すのに使われます。
例えば文字列の長さを調べる標準関数 strlen()ですが、戻り値に文字列の長さが返って来ます。
しかし、戻り値の型は intではありません。size_tなのです。
実際 size_tが何なのかは環境によって違いますが、大抵は unsigned intか unsigned longのようです。
特に何もないのに積極的に size_tを使うことはありませんが、標準関数で size_t型が
指定されている場合はsize_t型を使った方がいいでしょう。
# sizeof()とかの結果の値も size_t型です。
>ちなみに今現在の仕様なら、文字列を連結せずに 出来るような
>気がするのですが無理ですか?
スペースがあった場合となかった場合で、ソース(解析・計算部分)を分けると言うことですか?
無理ではないと思いますが・・・。
スペースはあってもなくても受け付けるということは
[color=#d0d0ff" face="monospace]calc.exe 1 + 3
calc.exe 1 +3
calc.exe 1+3
calc.exe " 1 + 3"[/color]
このどれもを受け付けなければなりません。もちろん、理論的には連結しなくてもできますが、ちょっとだけ面倒になります。
Re:無題
Justyさん。レスありがとうございます。
>これは char **argvと扱い的には同じになります。
>つまりポインタのポインタです。
ポインタのポインタ。。。言葉を聞くと一瞬泣きそうになります(笑)
>もちろん、理論的には連結しなくてもできますが、ちょっとだけ面倒になります。
ですよね。回答ありがとうございました。
>例えばargv[1]じゃなくて、argv[2]の解析をしようとか考えたとき、
>ソースのあっちこっちに argv[1]が散乱していたら
>書き換えるのが面倒ですよね?
確かにあっちこっちに散乱してる場合は面倒ですね。
ちなみに、流れ的にはargv[1]~argv[3]までを連結し、その上で
argv[/url]に入っている文字列を1文字ずつ解析し、数値なら式に沿って演算させる。
というふうな感じにすればいいんですよね?(こちらが質問者なのにすみません)
>これは char **argvと扱い的には同じになります。
>つまりポインタのポインタです。
ポインタのポインタ。。。言葉を聞くと一瞬泣きそうになります(笑)
>もちろん、理論的には連結しなくてもできますが、ちょっとだけ面倒になります。
ですよね。回答ありがとうございました。
>例えばargv[1]じゃなくて、argv[2]の解析をしようとか考えたとき、
>ソースのあっちこっちに argv[1]が散乱していたら
>書き換えるのが面倒ですよね?
確かにあっちこっちに散乱してる場合は面倒ですね。
ちなみに、流れ的にはargv[1]~argv[3]までを連結し、その上で
argv[/url]に入っている文字列を1文字ずつ解析し、数値なら式に沿って演算させる。
というふうな感じにすればいいんですよね?(こちらが質問者なのにすみません)
Re:無題
>ポインタのポインタ。。。言葉を聞くと一瞬泣きそうになります(笑)
苦手意識をお持ちだという事が伝わってきますが、全然難しいものではないですよ。
例えば、ポインタとは目印だと思ってください。
データには目印がついていて、その目印をみればデータが取り出せると。
char **st;
で受け取ればポインタのポインタという事になりますが、
言い換えれば
目印が入った連続した箱の集まり、その集まりにさらに目印をつけたものの箱の集まり、ということです。
ポインタというのは言ってみれば配列です。
char a[/url]="1234";
とかいても
char *a="1234";
と書いてもいいことご存知でしょか。
上記両方ともaとかけばaのアドレスの事を示します。
2重ポインタということは、これらの配列の先頭アドレスを一つずつ格納した配列の集まりと言う事だと言い換えられます。
2重ポインタと2次元配列は同じではなく、意味は違うのですが、同じ意味も示す事が出来ます。
う~ん、、言ってて余計にわからなくさせてしまったかな・・・。
苦手意識をお持ちだという事が伝わってきますが、全然難しいものではないですよ。
例えば、ポインタとは目印だと思ってください。
データには目印がついていて、その目印をみればデータが取り出せると。
char **st;
で受け取ればポインタのポインタという事になりますが、
言い換えれば
目印が入った連続した箱の集まり、その集まりにさらに目印をつけたものの箱の集まり、ということです。
ポインタというのは言ってみれば配列です。
char a[/url]="1234";
とかいても
char *a="1234";
と書いてもいいことご存知でしょか。
上記両方ともaとかけばaのアドレスの事を示します。
2重ポインタということは、これらの配列の先頭アドレスを一つずつ格納した配列の集まりと言う事だと言い換えられます。
2重ポインタと2次元配列は同じではなく、意味は違うのですが、同じ意味も示す事が出来ます。
う~ん、、言ってて余計にわからなくさせてしまったかな・・・。
Re:無題
ちょっと意欲低下してらっしゃるようなので気分転換のコメントでも^^;
@とんぷぅ~さんはきっと現在「やらされているプログラミング」であったり、「しなければならないからやっているプログラミング」であるのではないでしょうか。そのために
なかなか思い通りに行かない・・(_ _|||)ズ~ン
見たいな心境になってしまっているのではと思いますけど、プログラムを趣味で楽しいと思ってやっているとプログラムの見方が全然違ってきますよ。
昔ポインタが嫌いでした、構造体が嫌いでした、文字列処理が嫌いでした、自作関数がわかりませんでした。
しかしゲームをちょびちょび作っていく中でそこを嫌っていたらそれ以上の処理が出来ない事に気が付きました。
もっとよいゲームを作りたい、もっとコードを賢く書きたい、もっと効率よいコードが書いてみたい。
そんな思いで色々な単元を勉強していきました。
ちょっと勉強してはゲームを実装し、ちょっと勉強してはゲームを実装しました。
私は参考書をひたすら読んで勉強した覚えなど一度もありません。(だから基礎がなってないんだといわれたらそれまでデスガ^^;)
必要な時に調べては、コーディングするという繰り返しでした。
(そうするといつも知ってる知識内でしかプログラムコードをかかなくなってしまっていたので、意図的に他のアルゴリズムを勉強したりしたことはありましたが)
私はゲームをプログラムで作る事が楽しかったので、難しいな嫌だなと思う単元も、苦に思うことなく勉強できました。
というか趣味だったので、勉強という感じがありませんでした。
それに、きっと読むばっかりの勉強ではなく、それを勉強したらすぐにそれを使ってコーディングしたのが良かったのだと思います。
数学の教科書を1冊最初から最後まで読み通してわかった気になって、いざ教科書をひらかずに練習問題やろうとしたらさっぱりできなかったというのと同じように、
プログラムも演習によって身に付いていくものです。
また、「おもしろい!」と思えばそれに勝るものはありません。
プログラムのおもしろさを先に見つけ、プログラムの面白さを実感しながら、新しい単元を演習によって身につける道が最短コースだと思います。
((といってもシゴトとかで必要なのでしたらのんびりゲームなんて作ってる暇ないですかね^^;
もしどうしてもいやになったら、今勉強している範囲を利用して小さなゲームを作ってみたりアプリを作ってみたりして自分で学習意欲を出させる事も大事かと思います。
もし時間が出来たら色んな方向からプログラムをみつめてみてください☆
・・と偉そうな事を言ってみてもまだ私はプログラムのプの字もわかってないわけですが^^;
@とんぷぅ~さんはきっと現在「やらされているプログラミング」であったり、「しなければならないからやっているプログラミング」であるのではないでしょうか。そのために
なかなか思い通りに行かない・・(_ _|||)ズ~ン
見たいな心境になってしまっているのではと思いますけど、プログラムを趣味で楽しいと思ってやっているとプログラムの見方が全然違ってきますよ。
昔ポインタが嫌いでした、構造体が嫌いでした、文字列処理が嫌いでした、自作関数がわかりませんでした。
しかしゲームをちょびちょび作っていく中でそこを嫌っていたらそれ以上の処理が出来ない事に気が付きました。
もっとよいゲームを作りたい、もっとコードを賢く書きたい、もっと効率よいコードが書いてみたい。
そんな思いで色々な単元を勉強していきました。
ちょっと勉強してはゲームを実装し、ちょっと勉強してはゲームを実装しました。
私は参考書をひたすら読んで勉強した覚えなど一度もありません。(だから基礎がなってないんだといわれたらそれまでデスガ^^;)
必要な時に調べては、コーディングするという繰り返しでした。
(そうするといつも知ってる知識内でしかプログラムコードをかかなくなってしまっていたので、意図的に他のアルゴリズムを勉強したりしたことはありましたが)
私はゲームをプログラムで作る事が楽しかったので、難しいな嫌だなと思う単元も、苦に思うことなく勉強できました。
というか趣味だったので、勉強という感じがありませんでした。
それに、きっと読むばっかりの勉強ではなく、それを勉強したらすぐにそれを使ってコーディングしたのが良かったのだと思います。
数学の教科書を1冊最初から最後まで読み通してわかった気になって、いざ教科書をひらかずに練習問題やろうとしたらさっぱりできなかったというのと同じように、
プログラムも演習によって身に付いていくものです。
また、「おもしろい!」と思えばそれに勝るものはありません。
プログラムのおもしろさを先に見つけ、プログラムの面白さを実感しながら、新しい単元を演習によって身につける道が最短コースだと思います。
((といってもシゴトとかで必要なのでしたらのんびりゲームなんて作ってる暇ないですかね^^;
もしどうしてもいやになったら、今勉強している範囲を利用して小さなゲームを作ってみたりアプリを作ってみたりして自分で学習意欲を出させる事も大事かと思います。
もし時間が出来たら色んな方向からプログラムをみつめてみてください☆
・・と偉そうな事を言ってみてもまだ私はプログラムのプの字もわかってないわけですが^^;
Re:無題
TT414さん初めまして。
>どんな整数を入力しても計算結果が正しく表示されるようにする。
言い方が悪かったです。"どんな"というのは今まで扱ってきた値と比べて
かなり大きい値を扱うということで、今回ならば最終的に40桁まで扱える
ようにしたいがための表現が"どんな"という言葉で過大になってしまいました。
続けて質問失礼します。引数にスペース無しの場合でのコードを書いて
いたのですが、計算結果がおかしくなります。例・引数を1+1と入力すると
49 + 49 = 98などという結果が出ます。何処を直せばよいでしょうか?
恐らくコードが意味不明な部分があると思いますが、よろしくお願いします。
>どんな整数を入力しても計算結果が正しく表示されるようにする。
言い方が悪かったです。"どんな"というのは今まで扱ってきた値と比べて
かなり大きい値を扱うということで、今回ならば最終的に40桁まで扱える
ようにしたいがための表現が"どんな"という言葉で過大になってしまいました。
続けて質問失礼します。引数にスペース無しの場合でのコードを書いて
いたのですが、計算結果がおかしくなります。例・引数を1+1と入力すると
49 + 49 = 98などという結果が出ます。何処を直せばよいでしょうか?
#pragma warning ( disable : 4996 ) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> // パラメータエラー void usage ( void ) { printf ( "<< 引数を正しく入力して下さい。\n" ); printf ( "<< 1+1 or 1 + 1 の形式で入力して下さい。\n" ); exit ( 0 ); } int main ( int argc, char *argv[/url] ) { int result; int i = 0; char op; // パラメータのチェック if ( argc != 2 && argc != 4 ) { usage (); } // コマンドライン引数にスペースを与えない場合 if ( argc == 2 ) { while ( argv[1] != '\0' ) { if ( argv[1] == '+' ) { op = ( argv[1][1] ); if ( isdigit ( argv[1] ) ) { if ( argv[1] >= '0' && argv[1] <= '9' ) { } } } i++; } } switch ( op ) { case '+': result = argv[1][0] + argv[1][2]; break; } printf ( "%d %c %d = %d\n", argv[1][0], op, argv[1][2], result ); }
恐らくコードが意味不明な部分があると思いますが、よろしくお願いします。
Re:無題
それは「文字コード」+「文字コード」をしているからです。
受け取ったものは「文字」であり、「数値」ではありません。
「1」という文字は文字コード1ではなく、「1」の文字コードはアスキーコードによると49です。
過去に文字コードについて何度か解説しています。よければちょっと探してみてください。
数値をシングルコーテーションで囲むとそれは文字コードを意味します。
例えば
1
とかけば数値1のことですが、
'1'と書けば「1」の文字コードを意味します。
printf("%d",1);
printf("%d",'1');
両者で違う数値が出ることを確認してください。
atoiで文字を数値に変換しなければならないのはこのためです。
私の書いたサンプルの中で「1+1」の各「1」をatoiで数値に変換していますよね?
また、文字の比較をするとき「'0'以上'9'以下」という書き方をコードの中でしています。
「0以上9以下」ではないのです。
ちょっと解説が手短ですが、文字と、数値、数値を表す文字コードについて調べてみてください。
数値と文字の数字は意味が違うということです。
http://e-words.jp/p/r-ascii.html
文字コードについてはこちらに書かれている表に対応します。
また、1文字の場合、わざわざatoiしなくてもいいです。
例えばいま「9」の文字を数値の「9」として取り出したいときの話です。
「0123456789」と文字コードが並んでいるので、
「9の文字コード」-「0の文字コード」
をすれば「数値の9」が取り出せます。
例えば、
0の文字コードが49だとします。9の文字コードが58ですね。
58-49=9
つまり、引き算すれば数値が取り出せます。
二桁以上になると微妙に計算がややこしくなるのですが1文字の場合単にひけばいいですよ。
受け取ったものは「文字」であり、「数値」ではありません。
「1」という文字は文字コード1ではなく、「1」の文字コードはアスキーコードによると49です。
過去に文字コードについて何度か解説しています。よければちょっと探してみてください。
数値をシングルコーテーションで囲むとそれは文字コードを意味します。
例えば
1
とかけば数値1のことですが、
'1'と書けば「1」の文字コードを意味します。
printf("%d",1);
printf("%d",'1');
両者で違う数値が出ることを確認してください。
atoiで文字を数値に変換しなければならないのはこのためです。
私の書いたサンプルの中で「1+1」の各「1」をatoiで数値に変換していますよね?
また、文字の比較をするとき「'0'以上'9'以下」という書き方をコードの中でしています。
「0以上9以下」ではないのです。
ちょっと解説が手短ですが、文字と、数値、数値を表す文字コードについて調べてみてください。
数値と文字の数字は意味が違うということです。
http://e-words.jp/p/r-ascii.html
文字コードについてはこちらに書かれている表に対応します。
また、1文字の場合、わざわざatoiしなくてもいいです。
例えばいま「9」の文字を数値の「9」として取り出したいときの話です。
「0123456789」と文字コードが並んでいるので、
「9の文字コード」-「0の文字コード」
をすれば「数値の9」が取り出せます。
例えば、
0の文字コードが49だとします。9の文字コードが58ですね。
58-49=9
つまり、引き算すれば数値が取り出せます。
二桁以上になると微妙に計算がややこしくなるのですが1文字の場合単にひけばいいですよ。
Re:無題
>渡すべき変数の形と現在渡している変数の形がちゃんとあっていますか?
const char *stringと書いてあり型が違うので出来ないと思います。ただ
argv[1]は文字列に対するポインターの配列なのに
argv[1][n]はどうして同じではないのでしょうか?
これが分からないのは配列が分かっていなんですかね?
>文字列を解析して数値に変換すべきものは数値に変換し、
>中の演算子は別途格納するサンプルは既に示しました。
はい。参考にさせていただいて、演算子は変数char opに格納するようにしました。
ただ、演算子は一つなのでいいのですが、数字を見つけたときに、それが上書き
されてしまうんじゃないのか心配です。じゃあ格納場所を多くすればいいのか?
とも考えたんですが、実際どう組み込めばいいのか分かりませんでした。
今の所ソースはこんな感じです。お忙しい中何度もすみません。
const char *stringと書いてあり型が違うので出来ないと思います。ただ
argv[1]は文字列に対するポインターの配列なのに
argv[1][n]はどうして同じではないのでしょうか?
これが分からないのは配列が分かっていなんですかね?
>文字列を解析して数値に変換すべきものは数値に変換し、
>中の演算子は別途格納するサンプルは既に示しました。
はい。参考にさせていただいて、演算子は変数char opに格納するようにしました。
ただ、演算子は一つなのでいいのですが、数字を見つけたときに、それが上書き
されてしまうんじゃないのか心配です。じゃあ格納場所を多くすればいいのか?
とも考えたんですが、実際どう組み込めばいいのか分かりませんでした。
#pragma warning ( disable : 4996 ) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> // パラメータエラー void usage ( void ) { printf ( "<< 引数を正しく入力して下さい。\n" ); printf ( "<< 1+1 or 1 + 1 の形式で入力して下さい。\n" ); exit ( 0 ); } int main ( int argc, char *argv[/url] ) { int result; int i = 0; char op; // パラメータのチェック if ( argc != 2 && argc != 4 ) { usage (); } // コマンドライン引数にスペースを与えない場合 if ( argc == 2 ) { while ( argv[1] != '\0' ) { if ( argv[1] == '+' ) { op = ( argv[1][1] ); } else if ( argv[1] == '-' ) { op = ( argv[1][1] ); } else if ( argv[1] == '*' ) { op = ( argv[1][1] ); } else if ( argv[1] == '/' ) { op = ( argv[1][1] ); } if ( isdigit ( argv[1] ) ) { if ( argv[1] >= '0' && argv[1] <= '9' ) { } } i++; } } switch ( op ) { case '+': result = argv[1][0] + argv[1][2]; break; case '-': result = argv[1][0] - argv[1][2]; break; case '*': result = argv[1][0] * argv[1][2]; break; case '/': result = argv[1][0] / argv[1][2]; break; default: exit ( 0 ); } printf ( "%d %c %d = %d\n", argv[1][0], op, argv[1][2], result ); }
今の所ソースはこんな感じです。お忙しい中何度もすみません。
Re:無題
>argv[1]は文字列に対するポインターの配列なのに >argv[1][n]はどうして同じではないのでしょうか? え~と、 どうして同じではないのでしょうかということは、 argv[1][n]もアドレスが入っているとお思いでしょうか? argv[1]は確かに[1][0]~[1][n]が示す配列のアドレスはいっています。 しかしargv[1][0]などは特定のデータそのものを示します。 今とんぷ~さんは char st[10]="123"; という配列において、 なぜstと言う記述とst[1]という記述は同じではないのかとおっしゃっているのと同じです。 stというとst[0]~st[9]までのデータの集まりの先頭のアドレスを示しますよね。 st[1]というと、stが示すアドレスの1つ先にあるアドレスの中身、データ自身を示します。 int st[10]={1,2,3,}; printf("%d\n", st); printf("%d\n",&st[0]); printf("%d\n",&st[1]); printf("%d\n",&st[2]); printf("%d\n",&st[3]); printf("%d\n", st[0]); printf("%d\n", st[1]); printf("%d\n", st[2]); printf("%d\n", st[3]); 実行結果 1245004 1245004 1245008 1245012 1245016 1 2 3 0 それと同じように、**argvにおいて、 argv[1]はargv[1][0]からargv[1][n]までのひとまとまりの1つの配列の先頭アドレスを示します。 一方で argv[1][1]やargv[1][n]はその中の配列の特定のデータ自身を示します。 argv[1][n]はアドレスが入っているわけではありません。 疑問に思うデータの中身を色々な形で表示させてみてください。 意味が解ると思います。
Re:無題
コマンドラインから指定できる形に変更しました。
このプログラムは黄色い部分はサンプルと全く同じです。
コマンドラインから受け取った文字列をstにまとめる関数addを加えただけです。
これは途中にスペースがあろうと全部引数をstにadd関数でまとめてくれますからサンプルをそのまま利用することが出来ます。
「218 + 328」
「78* 219」
「9 /2」
など、計算可能です。
このプログラムは黄色い部分はサンプルと全く同じです。
コマンドラインから受け取った文字列をstにまとめる関数addを加えただけです。
これは途中にスペースがあろうと全部引数をstにadd関数でまとめてくれますからサンプルをそのまま利用することが出来ます。
「218 + 328」
「78* 219」
「9 /2」
など、計算可能です。
#include <stdio.h> #include <string.h> #include <stdlib.h> void add(int argc, char *argv[/url],char st[128]){ int i=0,j=0,s=0; while( ++i < argc ){ s=0; while(argv!='\0'){ st[j]=argv; s++; j++; } } st[j]='\0'; } int main(int argc, char *argv[/url]){ int i=0,x[3]; char st[128],c; add(argc,argv,st); while(st!='\0'){ if( !(st>='0' && st<='9') ){ c=st; st='\0'; x[0]=atoi(st); x[1]=atoi(&st[i+1]); break; } i++; } printf("%d %c %d = ",x[0],c,x[1]); switch(c){ case '+': x[2]=x[0]+x[1]; break; case '-': x[2]=x[0]-x[1]; break; case '*': x[2]=x[0]*x[1]; break; case '/': x[2]=x[0]/x[1]; break; } printf("%d",x[2]); }
Re:無題
それであってますよ^^
タグは見えなくなるので書いてもわかりませんよw
ですからカッコを半角でかかずに<pre>と書いたんですよ。
ウェブで使うタグの表示は普通こんな記号で書くのですが
http://www.tohoho-web.com/html/char.htm
ここの掲示板の使用でこの書き方は出来ないんですよね。
私は全員の記事編集できるので、編集画面を見ることが出来るのですが、そこでどのようにタグを使っているかわかるので私にはわかりますよ。
まぁそれでなくてもプレタグで囲むとスペースのあきかたやフォントが微妙にかわるのでわかりますけどね。
普段半角スペースは2回以上かくと1つにまとめられてしまいますが、
プレタグを使うとそのまま表示されます。タブインデントもね。
ですから、配列の事を説明するときに図を書きましたけど、あれもスペースをそのまま表示したいので、プレタグ使いました。
タグは見えなくなるので書いてもわかりませんよw
ですからカッコを半角でかかずに<pre>と書いたんですよ。
ウェブで使うタグの表示は普通こんな記号で書くのですが
http://www.tohoho-web.com/html/char.htm
ここの掲示板の使用でこの書き方は出来ないんですよね。
私は全員の記事編集できるので、編集画面を見ることが出来るのですが、そこでどのようにタグを使っているかわかるので私にはわかりますよ。
まぁそれでなくてもプレタグで囲むとスペースのあきかたやフォントが微妙にかわるのでわかりますけどね。
普段半角スペースは2回以上かくと1つにまとめられてしまいますが、
プレタグを使うとそのまま表示されます。タブインデントもね。
ですから、配列の事を説明するときに図を書きましたけど、あれもスペースをそのまま表示したいので、プレタグ使いました。
Re:無題
管理人さん。レスありがとうございます。
>それであってますよ^^
安心しましたww
ちょっと作成してみたんですが減算が上手くいきません。
strtol関数の部分にあるprintf ( "error : Please input the integer\n" );
のメッセージが出て終了してしまいます。何がおかしいのでしょうか?
>それであってますよ^^
安心しましたww
ちょっと作成してみたんですが減算が上手くいきません。
strtol関数の部分にあるprintf ( "error : Please input the integer\n" );
のメッセージが出て終了してしまいます。何がおかしいのでしょうか?
#pragma warning ( disable : 4996 )
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
// パラメータエラー
void usage ( void )
{
printf ( "<< 引数を正しく入力して下さい。\n" );
exit ( 0 );
}
// コマンドライン引数をst[128]にまとめる関数
void sto ( int argc, char *argv[/url], char st[128] )
{
int i = 0, j = 0, s = 0;
while ( ++i < argc ) {
s = 0;
while ( argv != '\0' ) {
st[j] = ( argv );
s++;
j++;
}
}
st[j]='\0';
}
// main関数
int main ( int argc, char *argv[/url] )
{
long long i = 0;
long long mod;
long long lop;
long long rop;
long long result;
char op; // 演算子
char st[128]; // コマンドライン引数を格納
char *check;
// パラメータのチェック
if ( argc <= 1 || argc >= 5 ) {
usage ();
}
// 関数呼び出し
sto ( argc, argv, st );
while ( st != '\0' ) {
if ( ! ( st >= '0' && st <= '9' ) && ( ! ( st == '-' ) ) ) {
op = st;
st = '\0';
lop = atoi (st);
rop = atoi (&st[i+1]);
break;
}
i++;
}
lop = strtol ( st, &check, 10 );
if ( errno != ERANGE ) {
if ( *check != '\0' ) {
printf ( "error : Please input the integer\n" );
exit ( 0 );
}
} else {
printf ( "error : The range of the int type is exceeded\n" );
exit ( 0 );
}
rop = strtol ( &st[i+1], &check, 10 );
if ( errno != ERANGE ) {
if ( *check != '\0' ) {
printf ( "error : Please input the integer\n" );
exit ( 0 );
}
} else {
printf ( "error : The range of the int type is exceeded\n" );
exit ( 0 );
}
// 演算子に沿って計算
switch ( op ) {
case '+':
result = lop + rop;
break;
case '-':
result = lop - rop;
break;
case '*':
result = lop * rop;
break;
case '/':
if ( lop == 0 ) {
printf ( "error : 0 division is a prohibition\n" );
exit ( -1 );
}
// 除算のオーバーフローを考慮
if ( ( lop == INT_MIN ) && ( rop == -1 ) ) {
printf ( "error : The overflow learns by experience\n" );
exit ( 0 );
}
result = lop / rop;
mod = lop % rop;
// 割り算の結果として余りが出なかった場合
if ( mod == 0 ) {
printf ( "%lld %c %lld = %lld", lop, op, rop, result );
exit ( 0 );
// 割り算の結果として余りが出た場合
} else if ( mod != 0 ) {
printf ( "%lld %c %lld = %lld 余り %lld", lop, op, rop, result, mod );
exit ( 0 );
}
break;
default:
printf ( "error : Please input either of operator '+', '-', '*', '/'\n" );
exit ( 0 );
}
// 加、減、乗算のオーバーフローを考慮
if ( ( result > INT_MAX ) || ( result < INT_MIN ) ) {
printf ( "error : The overflow learns by experience\n" );
exit ( 0 );
}
printf ( "%lld %c %lld = %lld", lop, op, rop, result );
}
Re:無題
後、long long型はstrtoll関数ではないでしょうか?
http://www.linux.or.jp/JM/html/LDP_man- ... tol.3.html
後、余りを出していますが、実数型で計算しないのでしょうか?
long double型など。
ただlong double型は処理系によっては無い可能性があるので、使わないほうがいいという考えもありますが。
http://www.linux.or.jp/JM/html/LDP_man- ... tol.3.html
後、余りを出していますが、実数型で計算しないのでしょうか?
long double型など。
ただlong double型は処理系によっては無い可能性があるので、使わないほうがいいという考えもありますが。
Re:無題
管理人さん。いつもお世話になっております。
>マイナスではなければと書いてありますけど、
先頭文字が'-'だった場合に、引き算と判定されてしまうので、
つけてみたんですが減算は上手くいきませんでした。
管理人さんの方でも試したのですが、今度は加算などでも
符号が違う場合などの計算が出来なくなってしまいました。
>後、long long型はstrtoll関数ではないでしょうか?
strtoll関数を使ったら以下のようなメッセージが出てコンパイル出来ませんでした。
1>c:\ct\src\projects\calc\calc\calc.c(69) : warning C4013: 関数 'strtoll' は定義されていません。int 型の値を返す外部関数と見なします。
1>リンクしています...
1>calc.obj : error LNK2019: 未解決の外部シンボル _strtoll が関数 _main で参照されました。
1>C:\CT\SRC\projects\calc\Debug\calc.exe : fatal error LNK1120: 外部参照 1 が未解決です。
>マイナスではなければと書いてありますけど、
先頭文字が'-'だった場合に、引き算と判定されてしまうので、
つけてみたんですが減算は上手くいきませんでした。
管理人さんの方でも試したのですが、今度は加算などでも
符号が違う場合などの計算が出来なくなってしまいました。
>後、long long型はstrtoll関数ではないでしょうか?
strtoll関数を使ったら以下のようなメッセージが出てコンパイル出来ませんでした。
1>c:\ct\src\projects\calc\calc\calc.c(69) : warning C4013: 関数 'strtoll' は定義されていません。int 型の値を返す外部関数と見なします。
1>リンクしています...
1>calc.obj : error LNK2019: 未解決の外部シンボル _strtoll が関数 _main で参照されました。
1>C:\CT\SRC\projects\calc\Debug\calc.exe : fatal error LNK1120: 外部参照 1 が未解決です。
Re:無題
マイナスの件は今回は2つしか値を取り込まないので単純に
if ( ! ( st >= '0' && st <= '9' ) && i!=0 ) {
で回避できると思います。
最初にマイナスが来たときは許すと言うことは、判定を0以外の時、とすればいいのですから。
strtollの件ですが。。Visual Studio2005でもコンパイル通りません。
C99で追加された関数だと言うことはわかるのですが、VS2005の環境でもコンパイル出来ないとなると・・。
[strtoll() は C99 と POSIX.1-2001 に準拠している]と書いてあるので、
コンパイラがそれに準拠していないということではないでしょうか。
GCCはC99に準拠しているようですが、VS2005はC99に準拠していないということでしょうか。
if ( ! ( st >= '0' && st <= '9' ) && i!=0 ) {
で回避できると思います。
最初にマイナスが来たときは許すと言うことは、判定を0以外の時、とすればいいのですから。
strtollの件ですが。。Visual Studio2005でもコンパイル通りません。
C99で追加された関数だと言うことはわかるのですが、VS2005の環境でもコンパイル出来ないとなると・・。
[strtoll() は C99 と POSIX.1-2001 に準拠している]と書いてあるので、
コンパイラがそれに準拠していないということではないでしょうか。
GCCはC99に準拠しているようですが、VS2005はC99に準拠していないということでしょうか。
Re:無題
> 違うエラーメッセージが出て困っています
違うメッセージとはどういうことでしょう?
st[i+1]が数値でなければならないところで、"/"であれば「数値を入力してほしい」というエラーで
合っていませんか?
> if ( strlen ( &st[i+1] ) >= 2 )
これをどこに入れたのか、何を意味しているのかよくわからないです・・・。
> 1+-1
ついに単項演算を条件に加えましたか。
これを受け付けるようにする、ということは
1+++++3とか 1-----4、1+-+-+-++---4も受け付けるのでしょうか?
(C言語的には ++/--演算子と混同しないように書けばOKだったりします)
# ところで@とんぷ~さんに質問があります。
・ 最終仕様
最終仕様の「括弧を含む演算」というのは "2 * (4 + 4)"のような複数の加減乗除を
扱う、ということでしょうか?
・ オーバーフローチェック
今は内部の型が有限なのでチェックしているのだと思いますが、
最終的には(環境的な限界を抜きにして)無限桁になるので
今の段階でも不要なのではないでしょうか?
・ lop / rop
whileループの中で代入して、その後 strtolでも代入しています。
何故2回代入しているのでしょう?
違うメッセージとはどういうことでしょう?
st[i+1]が数値でなければならないところで、"/"であれば「数値を入力してほしい」というエラーで
合っていませんか?
> if ( strlen ( &st[i+1] ) >= 2 )
これをどこに入れたのか、何を意味しているのかよくわからないです・・・。
> 1+-1
ついに単項演算を条件に加えましたか。
これを受け付けるようにする、ということは
1+++++3とか 1-----4、1+-+-+-++---4も受け付けるのでしょうか?
(C言語的には ++/--演算子と混同しないように書けばOKだったりします)
[color=#d0d0ff" face="monospace]
int val1 = 1 + + + + + 3;
int val2 = 1- - - - -4;
int val3 = 1+-+-+-+-+-+-+-+-4;
printf("%d, %d, %d\n", val1, val2, val3);[/color]
# ところで@とんぷ~さんに質問があります。
・ 最終仕様
最終仕様の「括弧を含む演算」というのは "2 * (4 + 4)"のような複数の加減乗除を
扱う、ということでしょうか?
・ オーバーフローチェック
今は内部の型が有限なのでチェックしているのだと思いますが、
最終的には(環境的な限界を抜きにして)無限桁になるので
今の段階でも不要なのではないでしょうか?
・ lop / rop
whileループの中で代入して、その後 strtolでも代入しています。
何故2回代入しているのでしょう?
Re:無題
Justyさん。レスありがとうございました。
>違うメッセージとはどういうことでしょう?
>st[i+1]が数値でなければならないところで、"/"であれば「数値を入力してほしい」
すみません。合ってました(笑)
>if ( strlen ( &st[i+1] ) >= 2 )
>これをどこに入れたのか、何を意味しているのかよくわからないです・・・。
すみません。これは1++1などでも計算できてしまうので
それを弾きたかったんですが、見当違いですみませんでした。
ちなみに"C言語的には ++/--演算子と混同しないように書けばOKだったりします"
とJustyさんがおっしゃられていますが、それなら1++1などが計算できてもいいのでしょうか?
>最終仕様の「括弧を含む演算」というのは "2 * (4 + 4)"のような複数の加減乗除を
>扱う、ということでしょうか?
はい。恐らくなんですが、そうなると思います。
>今は内部の型が有限なのでチェックしているのだと思いますが、
>最終的には(環境的な限界を抜きにして)無限桁になるので
>今の段階でも不要なのではないでしょうか?
現段階ではまずスペース有り、無しで計算出来、負数を括弧で括る条件
で一回見せないといけないのでこうしました。
>whileループの中で代入して、その後 strtolでも代入しています。
>何故2回代入しているのでしょう?
whileループの中の何処の部分でしょうか?ちょっと分かりませんでした。
長々と失礼しました。
>違うメッセージとはどういうことでしょう?
>st[i+1]が数値でなければならないところで、"/"であれば「数値を入力してほしい」
すみません。合ってました(笑)
>if ( strlen ( &st[i+1] ) >= 2 )
>これをどこに入れたのか、何を意味しているのかよくわからないです・・・。
すみません。これは1++1などでも計算できてしまうので
それを弾きたかったんですが、見当違いですみませんでした。
ちなみに"C言語的には ++/--演算子と混同しないように書けばOKだったりします"
とJustyさんがおっしゃられていますが、それなら1++1などが計算できてもいいのでしょうか?
>最終仕様の「括弧を含む演算」というのは "2 * (4 + 4)"のような複数の加減乗除を
>扱う、ということでしょうか?
はい。恐らくなんですが、そうなると思います。
>今は内部の型が有限なのでチェックしているのだと思いますが、
>最終的には(環境的な限界を抜きにして)無限桁になるので
>今の段階でも不要なのではないでしょうか?
現段階ではまずスペース有り、無しで計算出来、負数を括弧で括る条件
で一回見せないといけないのでこうしました。
>whileループの中で代入して、その後 strtolでも代入しています。
>何故2回代入しているのでしょう?
whileループの中の何処の部分でしょうか?ちょっと分かりませんでした。
長々と失礼しました。
Re:無題
>それなら1++1などが計算できてもいいのでしょうか
個人的には出来てもいいかと思いますが、上司の方に確認してみたほうがいいでしょう。
C言語がOKだからといって必ずしも "1 + + 1"を受け付ける必要はないかもしれませんが、
"1 + (+1)"は数学的にもOKなので受け付ける必要があるのではないかと思います。
一応前に作った calc_testはどちらも出来るようになっています。
>はい。恐らくなんですが、そうなると思います
なるほど。
となると、もうそろそろ今の解析方法とかだと厳しくなりそうですね。
>現段階ではまずスペース有り、無しで計算出来、負数を括弧で括る条件
>で一回見せないといけないのでこうしました
なるほどそういうことでしたか。
失礼しました。
>whileループの中の何処の部分でしょうか
わかりにくくてすみません。説明不足でした。
えーと、whileループの中で
どちらかの代入が不要かと思います。
個人的には出来てもいいかと思いますが、上司の方に確認してみたほうがいいでしょう。
C言語がOKだからといって必ずしも "1 + + 1"を受け付ける必要はないかもしれませんが、
"1 + (+1)"は数学的にもOKなので受け付ける必要があるのではないかと思います。
一応前に作った calc_testはどちらも出来るようになっています。
>はい。恐らくなんですが、そうなると思います
なるほど。
となると、もうそろそろ今の解析方法とかだと厳しくなりそうですね。
>現段階ではまずスペース有り、無しで計算出来、負数を括弧で括る条件
>で一回見せないといけないのでこうしました
なるほどそういうことでしたか。
失礼しました。
>whileループの中の何処の部分でしょうか
わかりにくくてすみません。説明不足でした。
えーと、whileループの中で
[color=#d0d0ff" face="monospace] lop = atoi (st);
rop = atoi (&st[i+1]);[/color]
で lop/ropに代入し、それらを一度も使うことなく、[color=#d0d0ff" face="monospace]lop = strtol ( st, &check, 10 );
rop = strtol ( &st[i+1], &check, 10 );[/color]
と lop/ropに代入しているのでちょっと気になったのです。どちらかの代入が不要かと思います。