• ベストアンサー

(MFC)コンボボックスの値を数値比較

VC++2005のMFCにてアプリケーションを作成しています。 コンボボックス(Ctrl変数:m_xcStMonth)に入力された値の、 正常値入力チェックとして、「1」から「12」までの数値ならtrue、 それ以外の数値及び文字列ならfalseを返す機能を実装したいのですが、 下記プログラムだと、「2」を入力しても、比較関数(1)(2)の戻り値として、 (1)RetMonth1には正常値「1」を返すのですが、 (2)RetMonth2にも誤り値「1」を返してしまいます。 原因として、「2」と「12」を比較した際に、 それぞれ一文字目の「2」と「1」を比較してしまうので、 誤り値を返してしまうようです。 下記が問題のソースコードです。 案1が比較関数にstrcpy_s()を使用した場合、 案2が比較関数CString::Compare()を使用した場合です。 両方において、RetMonth2に誤った戻り値を返しています。 もし何か良い改善策、より効率の良い実装方法などご存知の方おられましたら、 お手数ですが、ご教授お願い致します。 【案1】 CString StMinMonth; CString StMaxMonth; StMinMonth.Format( "%d", 1 ); StMaxMonth.Format( "%d", 12 ); CString StMonth; m_xcStMonth.GetWindowText( StMonth ); // コンボボックスの値を取得 char CmpMonth [ MAX_WORD_SIZE + 1 ] = ""; char CmpMinMonth[ MAX_WORD_SIZE + 1 ] = ""; char CmpMaxMonth[ MAX_WORD_SIZE + 1 ] = ""; strcpy_s( CmpMonth, MAX_WORD_SIZE + 1, StMonth ); strcpy_s( CmpMinMonth, MAX_WORD_SIZE + 1, StMinMonth ); strcpy_s( CmpMaxMonth, MAX_WORD_SIZE + 1, StMaxMonth ); int RetMonth1 = strcmp( CmpMonth, CmpMinMonth ); //(1) int RetMonth2 = strcmp( CmpMonth, CmpMaxMonth ); //(2) if( ( RetMonth1 < 0 ) || ( RetMonth2 > 0 ) ) { return false; } return true; 【案2】 CString StMinMonth; CString StMaxMonth; StMinMonth.Format( "%d", 1 ); StMaxMonth.Format( "%d", 12 ); CString StMonth; m_xcStMonth.GetWindowText( StMonth ); // コンボボックスの値を取得 int RetMonth1 = StMonth.Compare( StMinMonth ); //(1) int RetMonth2 = StMonth.Compare( StMaxMonth ); //(2) if( ( RetMonth1 < 0 ) || ( RetMonth2 > 0 ) ) { return false; } return true;

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

  • ベストアンサー
回答No.1

単純に数値に変換して比較するのではだめなのでしょうか? CString StMonth; m_xcStMonth.GetWindowText(StMonth); TCHAR* pchEnd; int nMonth = _tcstol(StMonth, &pchEnd, 10); if (*pchEnd != _T('\0')) { // 数値以外の入力がある } else {   if (nMonth < 1 || 12 < nMonth) {   // 月として正しくない   }   else {   // 正常   } }

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

  • BLK314
  • ベストアンサー率55% (84/152)
回答No.4

>正常値入力チェックとして、「1」から「12」までの数値ならtrue、 >それ以外の数値及び文字列ならfalseを返す機能を実装したい 関数を実装します static bool IsValidMonth(LPCTSTR Text) { int m; int n = sscanf_s(Text, "%d", &m); if (n <= 0) return false; // Textは数次に変換できない return m >= 1 && m <= 12;  } 上記を呼び出す部分は CString s; m_xcStMonth.GetWindowText(s); if (!IsValidMonth(s)) { // エラー処理 } else { // 正常処理 } で如何でしょうか?

zigen8513
質問者

お礼

沢山の親身なご回答ありがとうございます。 全て実装確認し、こちらの想定する結果に最も近いご回答に、 恐れ入りながら、良回答をつけさせて頂きます。 申し訳ありませんが、こちらにてまとめてのお礼とさせて頂きます。 ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • chie65535
  • ベストアンサー率43% (8539/19415)
回答No.3

文字列のまま比較したいなら。 CString StMonth; CString StMinMonth = "01"; CString StMaxMonth = "12"; m_xcStMonth.GetWindowText( StMonth ); // コンボボックスの値を取得 StMonth.Insert(0,"00"); StMonth = StMonth.Right(2); return ((StMinMonth >= StMonth) && (StMaxMonth <= StMonth)); または CString StMonth; CString StMinMonth = "01"; CString StMaxMonth = "12"; m_xcStMonth.GetWindowText( StMonth ); // コンボボックスの値を取得 StMonth.Insert(0,"00"); StMonth = StMonth.Right(2); int RetMonth1 = StMonth.Compare( StMinMonth ); int RetMonth2 = StMonth.Compare( StMaxMonth ); return ((RetMonth1 >= 0) && (RetMonth2 <= 0));

全文を見る
すると、全ての回答が全文表示されます。
  • chie65535
  • ベストアンサー率43% (8539/19415)
回答No.2

CString StMonth; m_xcStMonth.GetWindowText( StMonth ); // コンボボックスの値を取得 int i = ::_ttoi(StMonth); return ((i >= 1) && (i <=12));

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • プログラミング ポインタを使った文字列比較

    プログラミング ポインタを使った文字列比較 2つの文字列str1, str2を入力し,それらが等しければ0,等しくなければ1を返す関数str_compareを作り、返り値によって以下のように表示するプログラムを作れ。ただし,関数strcmpを使ってはならない。 文字列の入出力はmain関数で行い,関数str_compareの仮引数にはポインタ変数を宣言し,ポインタと間接演算子*を用いた処理を行うこと。 % ./a.out input str1 = Worldcup input str2 = Worldcup same strings % ./a.out input str1 = World input str2 = cup different strings この問題に私は次のようにプログラミングしました。 #include <stdio.h> #define MAX 100 int str_compare(char *, char *); main() { char str1[MAX], str2[MAX]; printf("input str1 = %s", str1); scanf("%s", str1); printf("input str2 = %s", str2); scanf("%s", str2); str_compare(str1, str2); if (str_compare(str1, str2) == 0) printf("same strings\n"); else if (str_compare(str1, str2) == 1) printf("different strings\n"); } int str_compare(char *s1, char *s2) { int i; for (i = 0; s1[i] != '\0'; i++) { if (s1[i] != s2[i]) { break; } } if (s1[i] == s2[i]) { return 0; } else { return 1; } } これで実行したところ、「input str1 =」の右のスペースが文字化け?してしまいます。(半角カタカナや記号が出る)ただ、その後に文字列を入力すると、正しく機能します。 これは何が悪いなのでしょうか、どなたか教えてください。

  • reallocの断片化対策について

    初めにお断りしておきたい事があります。 出先で緊急な事でしたので、今即興で書いたソースになります。 Cコンパイル環境が有りませんでしたので、動作確認がとれておりません。 その為、ケアレスミス等有るかもしれませんがご容赦願います。 例として標準入力より文字列を取得する処理を記述しました。 以下の処理でreallocの際の断片化対策となるでしょうか。 (最終的に*strにセットされている領域が断片化されていない事) 実際の処理では1行辺り0~30000文字程の可変長の文字列を読み込む事を想定しております。 C(windows)のみ可でC++は不可になります。 その他、冗長な記述等指摘が有りましたらよろしくお願い致します。 #define MAX_BUF_SIZE 128 int getText(char **str) { char *buf[MAX_BUF_SIZE]; char *tmp = NULL; int tmpsize = 0; if ((tmp = (char*) malloc(1)) == NULL) { return FALSE; } *tmp = '\0'; while (fgets(buf, MAX_BUF_SIZE, stdin) != NULL) { tmpsize += MAX_BUF_SIZE; if ((tmp = realloc(tmp, tmpsize)) == NULL) { free(tmp); return FALSE; } strcat(tmp, buf); } if (*str != NULL) { free(*str); } if (*str = (char*) malloc(strlen(tmp) + 1) != NULL) { return FALSE; } strcpy(*str, tmp); free(tmp); return TRUE; }

  • 文字列を比較

    文字列を比較して 一つでも一致したらファイルに書き込まず抜ける 一つも一致しなかった場合一度書き込んで抜けるという操作を 下記のコードで実現したいんですけど、 "cPid[n] = cStoRegiAdd; for(j = 0;j < MAX;j++){ if(cPid[n] != cRegiTab[j]){ iflag = 1; } } if(iflag == 1){ fprintf(fh,"#define %s 0\n",cStoRegiAdd); }" の部分で何かおかしいとこはありますか?? もしあれば教えていただきたいんですけど?? #include<stdio.h> #include<string.h> #include<stdlib.h> #define MAX 1024 char *cRegiTab[MAX]; // 文字列登録表 int n = 0; int main() { rightsidehfunction(); leftsidehfunction(); } /* 左辺の値をとって.hファイルに書き込む関数 */ int leftsidehfunction() { FILE *ft; FILE *fh; char buf[MAX]; char buf1[MAX]; char *cPid[MAX]; char *cWorkRegiAdd; char *cStoRegiAdd; int istr = 0; int k; char *p; char *q; int s; int i; int j; int iflag = 0; ft = fopen("test.txt","r"); fh = fopen("test.h","a+"); if (fh == NULL || ft == NULL) { printf("ファイルを開けません。\n"); return 1; } /* ファイルを1行ずつ読み込む処理 */ while (fgets(buf, sizeof buf, ft) != NULL){ cWorkRegiAdd = strtok(buf, "="); for(k = 0;k < n;k++){ if(*cPid[k] != *cWorkRegiAdd)continue; if(strcmp(cPid[k],cWorkRegiAdd) == 0)break; } if(k < n) continue; cStoRegiAdd = malloc(strlen(cWorkRegiAdd) + 1); strcpy(cStoRegiAdd,cWorkRegiAdd); cPid[n] = cStoRegiAdd; for(j = 0;j < MAX;j++){ if(cPid[n] != cRegiTab[j]){ iflag = 1; } } if(iflag == 1){ fprintf(fh,"#define %s 0\n",cStoRegiAdd); } n++; } fclose(fh); fclose(ft); return 0; } /* 右辺の値をとって.hファイルに書き込む関数 */ int rightsidehfunction() { FILE *ft; // 入力ファイルポインタ FILE *fh; // 出力ファイルポインタ int c; //読み込み文字 char buf[MAX]; //バッファ領域 char buf1[MAX]; char cPid[MAX]; // 採取したPID char *cWorkRegiAdd; // 採取文字列作業域アドレス char *cStoRegiAdd; // 文字列格納域アドレス int iflag = 0; // 0/1; 右/左のクオート int ichs = 0; // chrの文字数 int istr = 0; // strの文字数 int k; // ntrの探索index int iOid; //OID char *p; ft = fopen("test.txt", "r"); fh = fopen("test.h", "w"); if (fh == NULL || ft == NULL) { printf("ファイルを開けません。\n"); return 1; } //ファイルを1文字ずつ読み込む while ((c = fgetc(ft)) != EOF) { switch (c) { case '"': iflag = 1 - iflag; /*右のクオート*/ if (iflag == 0) { cPid[ichs] = '\0'; cWorkRegiAdd = cPid; for(k = 0;k < istr;k++){ if(*cRegiTab[k] != *cWorkRegiAdd) continue; if(strcmp(cRegiTab[k],cWorkRegiAdd) == 0) break; } if(k == istr){ cStoRegiAdd = malloc(strlen(cWorkRegiAdd) + 1); strcpy(cStoRegiAdd,cWorkRegiAdd); cRegiTab[istr] = cStoRegiAdd; istr++; fprintf(fh, "#define %s 0\n", cStoRegiAdd); } ichs = 0; } break; case '\n': if (iflag == 1) { cPid[ichs] = '\0'; iflag = 0; } ichs = 0; break; default: if (iflag == 1) { cPid[ichs] = c; if (ichs < MAX - 1){ ichs++; } } break; } } /* ファイルの最後が改行じゃなかった場合 */ if (ichs>0) { cPid[ichs]='\0'; } fclose(ft); fclose(fh); return 0; }

  • テキストファイルの各行の文字列を、コンボBoxに表示させたい

    テキストファイルの各行の文字列を、コンボBoxに表示させたい 現在VC++ MFCの勉強をしております。(MFCに拘ってはおりません) 下のテキストファイル"D:\data.txt" (Shift_JIS)から (内容) 田中さん 斉藤さん 吉田さん CFile の Read で一行ずつ読み込んで、CStringArrayを使って コンボBox に Insert したいと思っています。 下記のコードについてですが。 BOOL CAddDialog::OnInitDialog() { CDialog::OnInitDialog(); // TODO: ここに初期化を追加してください TCHAR* pszFileName = L"d:\\data.txt"; CFileException fileException; CFile cFile; int ret; char buffLine[256] ; CStringArray cStrComboArr ; // リスト ret = cFile.Open( pszFileName , CFile::modeRead | CFile::shareDenyNone , &fileException ); if ( ret == false ) { AfxMessageBox( L"ファイルが読込めません。" ); return 1; } while ( (ret = cFile.Read( &buffLine , 256 )) != 0 ) { cStrComboArr.Add( buffLine ); /* ここでビルドエラー */ } cFile.Close(); // コンボboxに入れる CComboBoxEx* pCombo = (CComboBoxEx*) GetDlgItem( IDC_COMBOBOXEX1 ); COMBOBOXEXITEM cbi ; cbi.mask = CBEIF_TEXT; for ( int i = 0; i < cStrComboArr.GetCount(); i++ ) { cbi.iItem = i; cbi.pszText = (LPTSTR)(LPCTSTR) cStrComboArr.ElementAt(i) ; // 「'CString' から 'LPWSTR' に変換できません」から。 cbi.cchTextMax = 256; pCombo->InsertItem( &cbi ); } return TRUE; // return TRUE unless you set the focus to a control // 例外 : OCX プロパティ ページは必ず FALSE を返します。 } cStrComboArr.Add( buffLine ); の部分でエラー表示は、 「INT_PTR CStringArray::Add(LPCTSTR)' : 1 番目の引数を 'char [256]' から 'LPCTSTR' に変換できません。」です。 根本的にやり方が間違っているのか、もう少しのところなのか、 ズバッとご指摘いただけないでしょうか。 宜しくお願いします。 OS : Vista Home Premium VS 2008 pro

  • 文字列比較

    最長10文字の文字列を2件入力し、char型の配列にそれぞれ格納する。2つの文字列を比較し、文字列が同じだったら「equal」を表示し異なっていたら「Not equal」を表示するプログラムを作成せよという課題が出ました。 条件として、11文字以上の文字が入力されたら、先頭から10文字までを有効とし、11文字目以降を無視する。下記のプログラムで文字列1に11文字以上入力すると、うまく動きません。なぜ、うまくいかないかと、どうなおしたらよいかを教えてください。 #include<stdio.h> #include<string.h> #define max_length 10 void get_string (char *p_str, int size); int main() { char string1[max_length+2]; char string2[max_length+2]; printf("文字列1:"); get_string(string1,max_length+2); printf("文字列2:"); get_string(string2,max_length+2); if(!strncmp(string1,string2,max_length)) puts("equal"); else puts("Not equal"); } void get_string (char *p_str, int size) { fgets(p_str,size,stdin); }

  • テーブル配列の中身、出力値

    お世話になっております。 C言語勉強中のものです。 一定のひもをランダムに切断し、その長さを測ろうと思っています。 前回アドバイスを頂き、ソートを使って書いてみたのですが、詰まる部分があったのでご指導いただきたいと思いました。 #include <stdlib.h> #include <string.h> #include <stdio.h> #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))   int GetRandom(int min, int max);   int compare_int(const void* a, const void* b);   int compare_str(const void* a, const void* b); int main(void) {   int int_table[] = {GetRandom(0,10000)};   int i;   qsort( int_table, ARRAY_SIZE(int_table), sizeof(int), compare_int );   for( i = 0; i < ARRAY_SIZE(int_table); ++i ) {     printf("%d\n",int_table[i] ); }   return 0; } int compare_int(const void* a, const void* b) {   return ( *(int*)a - *(int*)b ); } int GetRandom(int min, int max) {     return min + (int)(rand()*(max-min+1.0)/(1.0+RAND_MAX)); } 【困っている箇所】 ・int int_table[]={} の中身に次のようなものを入れることで、ランダムに切ったひもを、ソートできると考えているのですが、その方法を色々ためしましたが上手くいきませんでした。このようなやり方で良いのか、その場合どのようにしたら良いか、また違うのかを教えていただきたいです。 for(i=0;i<10;i++) { printf("%d\n",GetRandom(0,10000)); } ・また最終的にソートしたものを比較させようと思っています。 「出力値を保存する方法」が分からないので教えて頂きたいです。 ----前回ご覧になってくださった方へ---- アドバイスありがとうございました。 まだ初心者ですが、色々ご教授下さるとうれしい限りです。

  • typeidと計算コスト

    今、以下のようなクラスの関数を作っているのですが、typeidはプログラム実行時に実行される関数という扱いなのでしょうか? それとも、コンパイル時に実行されるマクロ関数的な扱いのものなのでしょうか? もし、プログラム実行時に実行されるなら、コンパイル時にTTの種類によって内容をコンパイルする内容を変更すると言うことは不可能でしょうか? また、どうしても、プログラム実行時にしかできないのならと考え、 type_info ty=typeid(TT) と、代入してから判定してみようかとやってみたのですが、「error C2248: 'type_info::type_info' : private メンバ (クラス 'type_info' で宣言されている) にアクセスできません。」と表示され無理なようでした。 何か良い方法はないものでしょうか? template<class TT> class vector3{ public:   enum{NUM=3};   TT x[NUM];   int GetMemberList(char *str,const int bufsize,char *format=0); }; template<class TT> int vector3<TT>::GetMemberList(char *str,const int bufsize,char *format=0){   int i,j;   if(!format){     const int size=4;     type_info     format=new char[size];     if(typeid(TT)==typeid(int)){       strcpy_s(format,size,"%d");     }     else if(typeid(TT)==typeid(double)){       strcpy_s(format,size,"%lf");     }     else{       return(1);     }   }   j=sprintf_s(str,bufsize,format,x[0]);   for(i=1;i<NUM;i++){     j+=sprintf_s(str+j,bufsize-j,",");     j+=sprintf_s(str+j,bufsize-j,format,x[i]);   }   if(format)delete [] format;   return(0); }

  • findnext();について

    下のプログラムなのですが、 色々と調べていくとfindnext();でフリーズしてしまうことがわかりました。 しかし、なぜフリーズするのかわからないのです。 dir.hの書いてある通りに使っているつもりなのですが・・・ 助言お願いいたします。 仕事にいるので早急にお願いいたします。 ちなみにコンパイラはBC4.5++です。 /*****************************************************************/ test.c /*****************************************************************/ #include <stdio.h> #include <dir.h> #include <string.h> #define MAX 10 int main(){ struct ffblk *data; int i; char name[MAX]; char path[MAX]; strcpy(path,"c:\\*.*"); if(findfirst(path,data,0)==0){ while(1){ strcpy(name,data->ff_name); printf("%s",name); if(findnext(data)!=0)break; } } return 0; }

  • 構造体が戻り値の関数についてわかりません

    問題文:文字列を保存する構造体word_pairを下記の様に定義する。 typedef struct word_pair{ char longer_word[10]; char shorter_word[10]; char combined_word[20]; int longer_word_length; int shorter_word_length; }word_pair_t; この構造体を新たに作成し、データをセットして返す関数 word_pair_t create_word_pair(char *a, char *b); を作成せよ。create_word_pairは以下の仕様を満たす。 create_word_pairは2つの文字列a,bを比較し、長い文字列をlonger_wordに、短い文字列をshorter_wordに代入する。また、これらの長さが同じ場合には辞書的に後ろのものをlonger_wordに、前のものをshorter_wordに代入する。もし、a,bがまったく同じ文字列であれば、エラーメッセージを出力した上で、longer_wordに入力された文字列をshorter_wordに空の文字列を代入する。またcombined_wordにはlonger_word とshorter_wordをスペース区切りで結合したものを代入する。 標準入力から文字列を2つ読み取り、create_word_pairを用いて、新たにそれらのデータが代入された構造体を作成した後に、これらのメンバ変数を全て、標準出力に表示するプログラムを作成せよ。 という問題で、とりあえず自分で細かい条件は無視して文字列を標準入力してから構造体のメンバに文字を格納するところまでやろうとしたのですが、strcpyするのに型が違うとコンパイルエラーが出たのですが、型は一緒だと私は思っているため、なぜ違うのかわかりません。 また辞書的に後ろ前をif文でどのように表現すればいいのかと、文字列結合にstrcatを使うと思うのですが、結合の合間にスペースをいれる方法が分かりません。以下自分のコード。 #include<stdio.h> #include<string.h> #define max 50 typedef struct word_pair{ char longer_word[10]; char shorter_word[10]; char combined_word[20]; int longer_word_length; int shorter_word_length; }word_pair_t; word_pair_t create_word_pair(char *a, char *b); int main() { char a[max],b[max]; word_pair_t *str; printf("文字列を2つ入力してください。\n"); printf("1つ目:"); scanf("%s\n",a); printf("2つ目:"); scanf("%s\n",b); create_word_pair(a,b); printf("長い方の文字列%s\n",str->longer_word); printf("短い方の文字列%s\n",str->shorter_word); printf("連結した文字列%s\n",str->combined_word); printf("長い方の文字列の長さ%d\n",str->longer_word_length); printf("短い方の文字列の長さ%d\n",str->shorter_word_length); return 0; } word_pair_t create_word_pair(char *a, char *b) { int d, e; char c[max]; word_pair_t *str; d = strlen(a); e = strlen(b); if(d > e){ strcpy(str->longer_word, a); strcpy(str->shorter_word, b); c = strcat(a,b); strcpy(str->combine_word, c); strcpy(str->longer_word_length, d); strcpy(str->shorter_word_length, e); } if(d < e) { strcpy(str.longer_word, b); strcpy(str.shorter_word, a); c = strcat(a,b); strcpy(str.combine_word, c); strcpy(str.longer_word_length, e); strcpy(str.shorter_word_length, d); } }

  • qsortの引数について

    以下のプログラムがあります。 int compare( const char **name1, const char **name2 ) { return strcmp( *name1, *name2 ); } int main( void ) { char *names[] = { "rand", "calloc", "malloc" }; int num = sizeof names / sizeof names[0]; qsort( names, num, sizeof( names[0] ), (int (*)(const void *, const void * ))compare ); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~この部分 return 0; } 上の「~~~」の上の部分のqsort関数の第4引数のキャストの意味が 分かりません。なぜ関数の前に引数が書かれるのでしょうか? またintの後にある(*)は「int型のポインタ」と言う意味なのか、 compare関数のポインタなのかも分かりません。 ご回答よろしくおねがいします。