• ベストアンサー

期待する文字列

フリーウェアのBorland c++compiler 5.5で 動的メモリーを確保して、期待する文字列(実数文字)が入力されるまで 繰り返すというプログラムを作っています。 以下のプログラムだけだと正常に動作しますが、その関数をループさせて 期待する文字列までループさせると数字のみなら実効可能ですが、 数字以外の文字が混じって15文字以上になると「不正な処理~~~」と強制終了させられます。 以下が そのプログラムの考え方です。 1 関数 A() 動的メモリーの確保   2へ 2 関数 B() 文字の読み込み(必要に応じてメモリー拡張) 3へ 3 関数 C() '.'個数チェック 2=エラー表示            1=小数点の書き換え(数字) 4へ            0=             4へ 4 関数 D() 関数isdigitで各メモリーをチェック 無限ループを使って int i=1; while(i) { 関数 A() }iのアドレス(ポインタ)を4まで引数にして iの値を0に書き換えループから脱出させています c言語を勉強して2週間の初心者です。どこがいけないのか 分かりません。 どなたか教えてください。          

質問者が選んだベストアンサー

  • ベストアンサー
  • leaz024
  • ベストアンサー率75% (398/526)
回答No.6

 ソース全部読みました。  まぁ2週間という初心者にしては上出来でしょう。←元プログラミング講師の経験より  一言いうなら、これっぽっちの要件なのに、問題を大きくし過ぎです。  もっと問題を整理してから取り組んで下さい。  とりあえずこのプログラムが直ったら、再設計して1から作り直してみましょう。  さて問題のバグですが、原因はやはり、reallocのサイズが拡張されていないことです。  関数expand_memory内の変数sizeがauto変数として宣言されているので、これをstatic宣言すれば直るでしょう。 (intの前にstatic を付けるだけです。)  では、なぜ「数字以外が混じって~」だとダメになるのかというと、これは2度目のmalloc(NULLのrealloc)が正常に行えないからです。  数字以外が含まれていると再度入力させるためにNULLでrealloc(malloc)しようとしますが、それまでの動作でmallocが必要としている次のメモリブロックのヘッダまで壊されてしまっているため、mallocが不正な処理を引き起こすのです。 (同じ理由で、15文字以上の小数点を2個以上含む数字列を入力した場合でも、不正な処理が出るはずです。)  ※それまで何度も実行されているはずのreallocは、同じメモリブロックのヘッダを参照するのでこの問題は起きませんが、たまたま他のエラーが出ていないだけであることを、よく意識してください。  下記に参考になりそうなページを挙げておきます。

参考URL:
http://www.catnet.ne.jp/kouno/c_faq/c7.html#19
nagaruru
質問者

お礼

詳しい説明とURLまで教えていただき、本当にありがとうございます。 みなさんが言うように勉強して作り直したいと思います。 いろいろお時間を頂き感謝しております。

その他の回答 (5)

noname#30727
noname#30727
回答No.5

関数名の動詞・名詞の並び順を統一されると良いのではと思います。 reallocするのでしたら、誰かがサイズを保持していなければうまくいきません。 例えば、 char *input(int *option) {  char *str = NULL;  int index = 0;  int alloc_size = 0;  for (;;)  {   if (index >= alloc_size)   {    alloc_size += 5;    str = realloc(str, alloc_size);   }   index++;  } } でも、エラーでリトライさせるのならば、誰かがfreeしてあげないとよろしくないので、基本的な構造を再考する必要がありそうです。 malloc/realloc/freeは使い方が比較的むずかしいので、固定サイズの配列で、入力文字数制限をするというのも1つのやり方だと思います。 引数に構造体へのポインタを使ってみるとか、戻り値をエラーコードにしてみるとかも試してみてはどうでしょう。

nagaruru
質問者

お礼

励ましのお言葉とアドバイスありがとうございました。 いろいろ試してみたいと思います。

  • KojiS
  • ベストアンサー率46% (145/312)
回答No.4

何となく設計せずにいきなり書いたコードに見えます。 まずアルゴリズムを考えて、設計をしましょう。 あと、これワーニングは出ていませんか? ワーニングが出ていると思うのですが、そのワーニングの原因を調べましょう。もし出ていないなら、ワーニングレベルが低いと思われるので、ワーニングレベルは常に最高にしておきましょう。 これは「数字のみなら実行可能」と書かれていますが、正常に動作しているでしょうか?見たところ正常に動作しないと思われます。 例えば、 char *expand_memory(char *buff, int *rem) ですが、バッファサイズが変わりません。ですので、意図する動作がつかめません。 getchar()の使い方を間違っていませんか? また、全体的にエラーチェックがほとんどありません。 その他もいろいろあるのですが、コーディングスタイルには触れません。が、言わせてもらうと、呼び出された関数の内部でエラー表示はやめた方が良いと思います。標準関数のように、エラーを返して呼出元でエラー表示しましょう。また、必要のない「ポインタの引きずり回し」はやめた方が良いでしょう。データの流れがわかりにくくなります。 もう一度全体をきちんと設計し直した方がよいかと思います。

nagaruru
質問者

お礼

そうですね、設計も何もなく処理の順序をただ書いただけだと 思いました。 ポインタも、ループを脱出するためのもので そこまでの関数には関係ないのに引きずってるなとは思っていました。 kojiSさんのご指摘参考になりました。ありがとうございます。

  • KojiS
  • ベストアンサー率46% (145/312)
回答No.3

> 考え方がおかしかったのでしょうか? > 関数の使い方は合ってると思うんですが。 > 関数の使い方が間違っている、正確にはどのように動いているかを把握しきれていない、という感じです。 とりあえず、実際にどのようにコーディングしているかを、要所を抜粋して書き込んでくだされば、何かアドバイスできるかもしれません。

nagaruru
質問者

補足

心強いお言葉ありがとうございます。 ソースファイル貼りつけましたので、ご面倒かけますがアドバイスお願いいたします。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> char *true_num(void); /* 期待数値入力関数宣言 */ char *input(int *); /* 数値入力関数宣言 */ char *expand_memory(char *, int*); /* バッファ拡張関数宣言 */ char *decimal(char *, int *); /* 小数点チェック関数宣言 */ char *num_check(char *, int*); /* 数字チェック関数宣言 */ int main() { printf("data\n"); printf("data\n%s\n",true_num() ); // 動作確認のため return 0; } /* 期待数値入力関数 */ char *true_num(void) { int *p_option, option = 1; char *number; p_option = &option; while(option) //期待する文字列が入力されるまでループ { number = input(p_option); } return number; } /* 数値入力関数 f(バッファ拡張関数) */ char *input(int *option) { char *str = NULL, *ent = "(enter)", // 改行のみのときenter表示のため *number; // realloc第1引き数にNULL指定でmallocとして機能 int index = 0, remainder = 0; // メモリーの残り変数 for(;;) { if(remainder == 0) str = expand_memory(str, &remainder); *(str + index) = getchar(); if( *str == '\n') { str = ent; // 改行のみ入力時、文字列エンター表示 break; } if( *(str + index) == '\n') // 文字列の終わりの書き込み { *(str + index) = '\0'; break; } index++; remainder--; } return decimal(str,option); } /* バッファ拡張関数 */ char *expand_memory(char *buff, int *rem) { const int SIZE = 5; int size = 0; size += SIZE; *rem = SIZE; buff= realloc(buff, size); return buff; } /* 小数点チェック関数 */ char *decimal(char *data,int *option) { int flag=0, posit; // 確認フラグ char *pflag, // '.'の位置 *number; pflag = data; while(flag < 2) // '.'の個数検索 { pflag = strchr(pflag + flag, '.'); if(pflag == NULL) break; else flag++; } switch(flag) { case 2: // 小数点2個以上 printf("set error!\a\n"); break; case 1: posit = strchr(data,'.') - data; // 小数点1個を含む文字列 *(data + posit) = '0'; // 小数点の書き換え isdigitでエラーになるため number = num_check(data,option); *(data + posit) = '.'; // チェック後データの復元 break; case 0: // 小数点を含まない文字列 number = num_check(data,option); break; } return number; } /* 数字チェック関数 */ char *num_check(char *data,int *option) { int len, flag, posit, *end; len = strlen(data); for(posit=0; posit < len; posit++) // 各配列の値を1~0か参照 { flag = isdigit( *(data + posit) ); if(flag == NULL) { printf("set error!\a\n"); break; } } if(flag != NULL) { end = option; // ここまでデーターが流れてくると文字列の実数になる *end = 0; // ループ脱出のための書き換え } return data; }

noname#30727
noname#30727
回答No.2

うーん、確かに抽象的すぎて・・・ 始めて2週間ということだから、間違いだらけで当然です。 そんなことは気にせずに、該当する部分のソース全部載せましょう。 1つの関数の大きさとか、関数のネストのさせ方、戻り値の使い方など、色々な意見を聞けるのではないかと思います。

  • KojiS
  • ベストアンサー率46% (145/312)
回答No.1

貴方の書かれた考え方だと、実際にどのように書かれているか全くわかりません。 ただし、この考え方の通りですと、グローバル変数を使って、alloc関連の関数を使って、なんだかんだとしているようですが、正常に動作する方がおかしいと思われます。(例え数字のみでも) C言語を勉強していると言うことですが、参考書は何をお使いですか? これが正常に動作しない原因がわからないということは、一度参考書(もしくはヘルプファイルでしょうか)の貴方が使った関数の部分を読み直した方が良いかと思われます。

nagaruru
質問者

補足

アドバイスありがとうございます。 考え方がおかしかったのでしょうか? 関数の使い方は合ってると思うんですが。

関連するQ&A

  • 整数を文字列として認識したい

    整数を文字列として認識したいんですが、可能なのでしょうか? 例えば、i=12470というint型の整数があるとして、1万の位の数1や、十の位の数7だけを取り出したいんです。 しかし、この際、1万の位の数1をi/10000、十の位の数7を(i%100)/10などというようにしては取り出したくないんです。 ややこしい質問ですが、よろしくお願いします。 というのも、整数を文字列として認識する目的は、int型として送られてきたデータが本当に整数なのかをチェックするためだからです。 初心者なので合っているか分かりませんが、整数を文字列として認識できれば、isdigit関数を使うことで、データが本当に整数なのかをチェックすることができるのかなあと考えているんですが・・・ もし、私の考えが間違っていたり、他に良い方法があったら是非教えて欲しいと思います。

  • ”123456”といった整数を文字列に変換、その後、文字列を1文字ごとに整数に変換 

    忙しい中失礼します。 http://oshiete1.goo.ne.jp/qa3424254.htmlでも質問させて頂いたものですが、 今、回答してくださった方の意見を参考に以下の過程をこなそうとしています。 1.整数入力 →scanf関数を使用し、"123456"と入力します。 2.整数を文字列に変換 → printf("Write the SIN: \n");   scanf("%d", &fnum);   printf("%c\n",fnum); で、"123456"と数値を入力しても”123456”という値が返されず、@となってしまいます。 どうすれば入力した数値が文字列として返ってくるのでしょうか? どんな文・関数を使用すれば数字を文字列として使用することが可能になるのでしょうか? 今のところ習っている文はif else, swith case, while for,do whileで、 getcharやstr?(string)という関数は習っていません。なので、どうプログラムを書けばいいのか??さっぱりなのです。 でもgetcharやstr?(string)という関数を使用するしか方法はないものなのでしょうか?  また、それから 3.文字列を1文字ごとに整数に変換  にする場合、どんな文・関数を使用すれば、1文字”ごと”に整数に変換できるのでしょうか? ごめんなさい、分からないのです。プログラム文、ヒントもしくは参考になるページ等があれば教えて下さい。 よろしくお願いします。 <使用環境:フリーソフト(Borland?)C ANSI C>

  • 文字列の中から1~5桁の数字を抜き出したい

    ある命令プログラムを作っているのですが、文字列の中に命令語を書いてその後に続く数字を抜き出したいのですがうまくいきません ソースを見ていただきたいのですが @ke の命令語の後で1~5桁の数字を記載しているのですが 数字の部分を文字から数字に変えたいのです。 その後 @ke 数字 を正式な命令文として扱いたいのですがソースを見ていただけるとわかると思いますが問題があります。 ・文字をatoiで数字に変換できない(キャスト演算子を変えてもだめだった) ・ソースのプログラムの書き方ではやたらと長々しくなってしまう。 どのようにしたら問題が解決できますか? ----以下ソース---- #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> int main(){ char kei[100]="abc@ke 4567def@ke 789"; int i=0; int g=NULL; while(i<15){ if(kei[i]=='@'){ i++; if(strnicmp(&kei[i],"ke ",3)==0){ i+=3; //後に続く数字を抜き出して処理したい if(isdigit(kei[i])){ if(isdigit(kei[i+1])){ if(isdigit(kei[i+2])){ //・・・・以下全部で5桁分の数字を判定していく けど正直こんなややこしい方法をとらなくてもスマートにできるはず } else{ g=(atoi(kei[i])) * 10 +atoi(kei[i]); //型名が違うからatoiに入らないといわれる } } else{ g=atoi(kei[i]); //型名が違うからatoiに入らないといわれる } } else{ printf("\n命令の仕方が間違っています\n"); } } } else{ printf("%c",kei[i]); i++; } } return 0; }

  • ヘッダーファイル"jctype"について

    昨夜はお世話になりました。 今日はCのヘッダファイル"jctype"についてです。 例の文字列検索プログラム作成中に、 "iskanji"関数という存在に気づきました。 関数名から日本語環境用と思われますが、 jctypeがBorland C++ Compiler には存在しないようですので、 どなたかその関数を利用する方法を教えてください。 宜しくお願いします。

  • 文字列を数字型に変換したい

    いつもお世話になっております。 eclipseというツールでC言語のプログラムを触っているのですが、 文字列の数字を数値型に変換して掛け算をしたいのですが、 型変換の関数はありますでしょうか??

  • 大文字の文字列→小文字の文字列

    C言語初心者です。 ある演習問題をやっていて詰まっています。 自分で入力した大文字の文字列を小文字にするプログラムを作るという問題なのですが、↓の条件があり、こんがらがってしまいました。 ・入力した文字列に小文字が含まれていたら、エラーと表示して再び入力を促し、0を入力するとプログラム終了という流れにする。 ・ポインタ変数を使う。 ・continue文を使う。 ・標準ライブラリ関数は使わない。 です。 ・continue文というのがよくわからない。 ・宣言した関数でどの処理をすればいいのかわからない。 ・大文字を小文字にするというプログラムがわからない。 (アスキーコードをどう使うのか) でつまっています。 どなたかアドバイス・解説・模範解答・指摘などしていただけないでしょうか。 よろしくお願い致します。

  • 16表記の文字列を数字に直したい(C/C++標準関数)

    16表記の文字列を数字に直したい(C/C++標準関数) 例えば、"FF”な255 or -127という風に16表記の文字列を数字に直すC/C++の標準関数はありますか? なければ、どのようなやり方で行っていますか? VxWorksのprogramを開発しようとしているのですが、どんな標準関数が使えるのか、 直接契約していないので分かりません。 組み込み製品の説明書にはC/C++の仕様の説明書がないですね。 VxWorksでsupport されている標準関数はどんなものがあるかもご存知の方教えてください。 シリアル通信のプログラムで伝聞がASCIIで書かれていて、数値は10進だったり、16進だったりします。

  • 文字列がNULLか空文字列かの判定

    Visual C++で、Cのプログラムを作成しているものです。(OS:WinNT 4.0) 文字列の扱いについて、質問します。 関数 int func(char *str) があると仮定します。 パラメータとして、strは以下のような状態あるとします。 (strは関数が呼ばれる前にcalloc()で領域確保済み)  シンボル名 値  str      0x00000001 "" 上記の状態で、strがNULLか空文字列("")であることを条件式にしたいのですが、str == NULL は偽となり、strcmp(str, "") を使用すると異常終了します。 どうしたらよいのでしょうか。アドバイスをお願いします。

  • 文字列の比較

    現在Cでプログラムをつくっているのですが いきずまってしまいました。 1.テキストファイルを読み込む 2.書き込みファイルを開く 3.読み込んだデータを一行読み込んで   その行の特定の文字列があれば、   特定の文字列のみ取り出し、   書き込みファイルに書く。    4.次以降の行も同じ処理をする。    5.読み込み、書き込みファイルを閉じる。 と、こんな感じのプログラムなのですが、 3の特定の文字列をどのように取り出せばいいのかわかりません。 取り出したいのが数字ならば、if文でできるのですが 文字列の場合は、どうなんでしょうか。 例えば、「MOJIRETU11」という取り出したいとき 数字と同じようにIF文を使用することは、できるのでしょうか。

  • char*型の文字列を表示させたい。

    char*型の文字列を表示させたい。 char*型の文字列をウィンドウに表示させるプログラムを作っているのですが、 調べても分からなかったので、質問させていただきます。 コンパイラはBorland C++で、プラットフォームはウィンドウズです。 Textoutのようにウィンドウに出力させたいのですが、うまくいきません。 うまく行かないと言うのは、C言語でのプログラムの書き方が分からないと言う事です。 ある文字列をファイルから読み込んで、ウィンドウに表示させると言うプログラムを作っています。 http://wisdom.sakura.ne.jp/system/winapi/win32/win15.html このような感じにしたいのですが…。宜しくお願い致します。 ちなみにこの質問をさせていただいたものです。 http://oshiete1.goo.ne.jp/qa3342727.html

専門家に質問してみよう