• 締切済み

文字の探索について

文字列中の英大文字,英小文字の出現回数をカウントし、その回数を出力するプログラムを作りたいのですが、どうもうまく動いてくれません。 ABC123Abcのときの出力結果は 'A' = 2 'B' = 1 'C' = 1 'D' = 0 'E' = 0 中略 'X' = 0 'Y' = 0 'Z' = 0 'a' = 0 'b' = 1 'c' = 1 中略 'y' = 0 'z' = 0 のように出したいです。 私が考えた方法では まず文字列を配列str[100]に読み込み for文で、'\0'が来るまで配列の中身の文字を一つずつ判定('A'が見つかると、変数Aの値をを1つ増やす)していき、 全ての文字の判定後、 printf("'A' = %d\n", A); printf("'B' = %d\n", B); 中略 printf("'z' = %d\n", z); という風に表示しようとしたのですが、うまく表示されず、プログラム自体もとても長くなってしまい、これが正解とはいえない状態です。 こんな方法よりもっといい方法があれば教えていただきたいです。 あと、判定方法もお願いします・・・。

みんなの回答

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.9

いんちきそのものは「結果を出力したい文字の一覧」を持てば逃げられますね>#8. ちなみに c を unsigned char にすればより安全.

回答No.8

C言語のいろいろな特性があり、こんなプログラムにすることもできます。 #include <cstdio> int main() { int count[256] = {0}; // 256 個というのは、普通の処理系では、char が収まる範囲 char *input = "ABC123Abc"; for (int i = 0; input[i] != '\0'; i++) { char c = input[i]; // 1文字切り出して count[c]++; // その文字に相当するカウンタ(配列で準備)を+1 } for (char c = 'A'; c <= 'Z'; c++) { // char なら普通にループのインデックスにもできる std::printf(" '%c' = %d\n", c, count[c]); } for (char c = 'a'; c <= 'z'; c++) { std::printf(" '%c' = %d\n", c, count[c]); } return 0; } 気分はわかりやすいと思います。 これは、C言語では、char 型は実は整数型でもあるという性質を使っています。 ただし、このコードは文字コードが連続していると言うことを前提にしていたりして、ちょっとインチキではありますが。

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.7

>'A'が見つかると、変数A(●)の値をを1つ増やす ・(略) >判定方法もお願いします・・・(◆) ★初めに、参考URLにアスキーコード表を示します。 文字 A ~ Z は、アスキーコードで 0x41 ~ 0x5A に連続して対応します。 文字 a ~ z は、アスキーコードで 0x61 ~ 0x7A に連続して対応します。 文字 0 ~ 9 は、アスキーコードで 0x30 ~ 0x39 に連続して対応します。 ☆これらの出現回数を格納する配列(●)を用意し、初期化します。  int iCntBig[26] = { 0 }; // A ~ Z用  int iCntSml[26] = { 0 }; // a ~ z用  int iCntDig[10] = { 0 }; // 0 ~ 9用 ☆対象となる文字列長(文字列読込み後)  int iLen = strlen( cMojiRetsu ); ★出現を判定し、その回数をカウント(◆)  for( i = 0; i < iLen; i++ ){   if( isupper( cMojiRetsu[i] ) ) iCntBig[ cMojiRetsu[i] - 0x41 ]++;   if( islower( cMojiRetsu[i] ) ) iCntSml[ cMojiRetsu[i] - 0x61 ]++;   if( isdigit( cMojiRetsu[i] ) ) iCntDig[ cMojiRetsu[i] - 0x30 ]++;  } ★出現回数を表示  for( i26 = 0; i26 < 26; i26++ ){   printf( "'%c'=%3d\n", ( i26 + 0x41 ), iCntBig[i26] );  }  for( i26 = 0; i26 < 26; i26++ ){   printf( "'%c'=%3d\n", ( i26 + 0x61 ), iCntSml[i26] );  }  for( i10 = 0; i10 < 10; i10++ ){   printf( "'%c'=%3d\n", ( i10 + 0x30 ), iCntDig[i10] );  } 注:表現上、全角空白を用いています。 ★プログラムは10人いれば10種の・・、年寄りが作ると・・↑です。

参考URL:
http://e-words.jp/p/r-ascii.html
  • melkattz
  • ベストアンサー率0% (0/0)
回答No.6

strchr関数を使うのはどうでしょう? #include <stdio.h> int moji_cnt(char *,char); int main(){ char tbl[]={ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' }; char str[256]="ABC123Abc"; int i; for(i=0;i<52;++i){ fprintf(stdout,"%c=%d\n",tbl[i],moji_cnt(str,tbl[i])); } return 0; } /* 引数1で渡された文字列の中に引数2で渡された文字の 文字数をカウントする */ int moji_cnt(char *str,char moji){ int moji_cnt=0; while(1){ if((str=strchr(str,moji))!=NULL) { ++moji_cnt; ++str; }else{ break; } } return moji_cnt; }

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.5

★配列を使っていないでしょ。 >プログラム自体もとても長くなってしまい…  ↑  これはA~Zのカウンタに配列を利用すればもっと短くなる気がします。  今はAカウンタ、Bカウンタ、…Zカウンタ、aカウンタ、…zカウンタとしているのかな。  この方法だとプログラムが複雑になると思うため例え正しく動作しても私なら不正解とします。 >うまく表示されず、これが正解とはいえない状態です。  ↑  動作がおかしいのですか?  考え方としてはあっているように思います。  問題は配列を使っていないため複雑になりすぎているだけでは? ・ASCIIコードのように文字コードが連続している場合には配列と文字判定関数を  組み合わせることでシンプルかつ、分かりやすくなります。 >あと、判定方法もお願いします・・・。  ↑  判定方法は ctype.h ヘッダにある  ・isupper()関数で英大文字を判別  ・islower()関数で英小文字を判別  できます。  これを踏まえてサンプルを載せます。  提示したサンプルが理解できたかどうかを補足に書いて下さい。  待っています。 サンプル: #include <ctype.h> #include <stdio.h> // メイン関数 int main( void ) {  char str[ 100 ] = "ABC123Abc"; ←対象の文字列  int count[ 256 ] = { 0 }; ←これが出現回数のカウンタ  int i, c;    // '\0'が来るまで配列の中身の文字を一つずつ判定  for ( i = 0 ; str[i] != '\0' ; i++ ){   if ( isupper(str[i]) ) count[ str[i] ] += 1; ←英大文字の判別とカウント   if ( islower(str[i]) ) count[ str[i] ] += 1; ←英小文字の判別とカウント   if ( isdigit(str[i]) ) count[ str[i] ] += 1; ←数字文字の判別とカウント(おまけ)  }  // 出現回数の結果表示  for ( c = 'A' ; c <= 'Z' ; c++ ) printf( "'%c' = %d回\n", c, count[c] ); ←英大文字の出現回数  for ( c = 'a' ; c <= 'z' ; c++ ) printf( "'%c' = %d回\n", c, count[c] ); ←英小文字の出現回数  for ( c = '0' ; c <= '9' ; c++ ) printf( "'%c' = %d回\n", c, count[c] ); ←数字文字の出現回数(おまけ)  return 0; } おまけとして『数字文字の出現回数』も付けています。 1バイト・コードのすべての出現回数をカウントできる count[] 配列を用意しています。 もちろん必要な分だけの配列でも良いですが 256 個しかないので処理を簡単にするために int count[ 256 ] = { 0 }; としています。 また、宣言と同時に初期化しています。これで count[] 配列のすべてがゼロにセットされます。 それでは頑張って下さい。

  • kokorone
  • ベストアンサー率38% (417/1093)
回答No.4

<うまく表示されず 正常な結果が得られない理由はどこにあるのか、まずは明確にすべきです。そのためには、どのような結果になるのか例示してほしかったですね。 プログラムを改良するのは2の次です。 私の作成したサンプルです。 ポイント:2次元配列、if文未使用 即興で作成したので、エラーになるかも。。 char in_chr[100]; char out_chr[2][26]; int out_cnt[2][26]; int cnt1: int cnt2: int cnt3: int chk_chr; int idx1: int idx2: for(cnt1=0;cnt1<2;cnt1 ++){ for(cnt2=0;cnt2<26;cnt2 ++){ /* 'A'-'Z','a'-'z' をout_chr[][]に設定 */ out_chr[cnt1][cnt2] = 0x41+cnt2+(0x20 * cnt1); /* out_cnt[][]に0を設定 */ out_cnt[cnt1][cnt2] =0; } } for(cnt3=0;cnt3 < 100;cnt++,){ chk_chr = in_chr[cnt3]; idx1 = chk_chr / 0x61; idx2 = chk_chr - (0x20*idx1 + 0x41); out_cnt[idx1][idx2] ++ } for(cnt1=0;cnt1<2;cnt1 ++){ for(cnt2=0;cnt2<26;cnt2 ++){ printf("'%c'=%d\n",out_chr[cnt1][cnt2],out_chr[cnt1][cnt2]); } }

  • f_attck
  • ベストアンサー率33% (40/118)
回答No.3

私は、今のままの方が可読性が高くて好きですけどん。 プログラム全体が大きいのは問題ないとして、関数が大きく なったのなら、改善するべきと思います。 #それぞれ機能分割するべきです。 可読性は下がりますがやるんならforで\0まで検索するのは同じで、 カウントに関して変更します。 大文字用の配列と小文字用の配列を作ります。 それで、0x41-0x5aまでが大文字で0x61-0x7aまでが小文字なので ifで判断して配列に代入する。 大文字の場合 (big_char[str[n]-0x40-1])++; 小文字の場合は (big_char[str[n]-0x60-1])++; でどうでしょう? 全体としては for(i=0;i<100;i++) {  if ((str[i] > 0x40) && (str[i] < 0x5b))  {   (big_char[str[n]-0x40-1])++;  }  else if ((str[i] > 0x60) && (str[i] < 0x7b))  {   (big_char[str[n]-0x60-1])++;  }  else  {   // input error  } } 結果出力に関しても同じように添え字に0x40+1もしくは0x60+1を 足してループさせれば、大文字と小文字分のprintf2個で終わりかな コンパイルとか実行とかしてないんで、間違ってたらごめんなさいね

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.2

サンプルコードです。 #include <stdio.h> #include <string.h> #include <ctype.h> int main(void) {   char str[] = "ABC123Abc";   int count[52] = { 0 }, i;      for (i = 0; i < strlen(str); i++) {     if (isupper(str[i]))       count[str[i] - 'A']++;     if (islower(str[i]))       count[str[i] - 'a' + 26]++;   }      for (i = 0; i < 26; i++)     printf("'%c' = %d\n", 'A' + i, count[i]);   for (i = 0; i < 26; i++)     printf("'%c' = %d\n", 'a' + i, count[i + 26]);   return 0; } (注)インデントのため、全角空白を使っています。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「整数 (0~9) の配列に対して, 各整数がその中にどれだけあるかを数える」プログラムを書いてみてください.

関連するQ&A

  • 別次元配列への文字コピー

    別次元配列への文字コピー(not文字列)をする際特別な制約ってありますか? 2次元配列から1次元配列への文字コピー 1次元配列から2次元配列への文字コピー などなど for(i=0,n=0;n<TEISU1;n++){ for(m=0;m<TEISU2;m++,i++){ strcpy(&ABC[m][n],&DEF[i]); printf(" i%d n%d m%d %c %x\n",i,n,m,ABC[m][n],DEF[m][n]); // ★★★★★↑この時点では正しく出ているが } } /**/printf("%s\n",ABC); // ★★★★★↑この時点では出力内容がおかしくなっている 原因がさっぱりわかりません。 原因はどういった事が考えられますか?

  • 引数に二重配列のある関数について

    void calc(int *a,int b,int c){ a[0]=b+c; a[1]=b-c; } void main(void){ int x[2]; int y=2,z=5; calc(x,y,z); printf("x[0]=%d,x[1]=%d\n",x[0],x[1]); } 上のように引数が普通の配列の関数ならできるのですが, 引数が下のような多重配列になるとエラーが出てしまいできません。 void keisan(int **a,int b,int c){ a[0][0]=b+c; a[0][1]=b-c; a[1][0]=b*c; a[1][1]=b/c; } void main(void){ int x[2][2]; keisan(x,6,2); printf("x[0][0]=%d,x[0][1]=%d\n",x[0][0],x[0][1]); printf("x[1][0]=%d,x[1][1]=%d\n",x[1][0],x[1][1]); } 引数に多重配列を使った場合の関数の作り方について教えてください. お願いいたします.

  • strtokでの空文字への置き換え

    大したことじゃないと言えばそうかもしれませんが、ちょっと氣になるんで質問させてください。 C言語でstrtokという函數ありますよね。 第1引數の文字列を、第2引數の文字列を構成する文字で區切る。 第2引數の文字を見つけたら、それを空文字('¥0')に置き換える。 字句の最初の文字へのポインタを返す。 このようなものだと理解しています。 次のプログラムを實行してみました。 #include <stdio.h> #include <string.h> int main(void) { char string[]="XYZ1231ABC"; int i; printf("%s\n", string); putchar('\n'); printf("%s\n", strtok(string, "1A")); printf("%s\n", strtok(NULL, "1A")); printf("%s\n", strtok(NULL, "1A")); printf("%s\n", strtok(NULL, "1A")); putchar('\n'); for(i=0; i<=10; i++) printf("string[%d]=%c\n", i, string[i]); return 0; } 結果 XYZ1231ABC XYZ 23 BC (null) string[0]=X string[1]=Y string[2]=Z string[3]= string[4]=2 string[5]=3 string[6]= string[7]=A string[8]=B string[9]=C string[10]= 私が思うには、string[7]は空文字に置き換わってしまうはずだと思うんですが、 結果は'A'のままです。 ここが '¥0'に置き換わるかどうかは しょり系によって異なるのでしょうか。

  • 覆面算 C(2)

    このプログラミングの何が違うんでしょうか? どなたか教えてください。 #include <stdio.h> int main(void){ int D,A,Y,R,E,M,Z,U,I; for(D=1; D<10; D++){ for(A=0; A<10; A++){ if(A!=D){ for(Y=0; Y<10; Y++){ if(Y!=D && Y!=R && Y!=E && Y!=A && Y!=M){ for(I=1; I<10; I++){ if(I!=D && I!=A && I!=Y){ for(Z=0; Z<10; Z++){ if(Z!=D && Z!=A && Z!=Y && Z!=R && Z!=E && Z!=M && Z!=U && Z!=I){ if((D*100+A*10+Y)+D*10000+R*1000+E*100+A*10+M == I*10000+Z*1000+U*100+M*10+I){ printf("%d%d%d\n",D,A,Y); printf("%d%d%d\n",D,R,E,A,M); printf("-------\n"); printf("%d%d%d\n",I,Z,U,M,I); printf("-------\n"); break; } } } } } } } } } } return 0; }

  • 配列とポインタについて

    #include <stdio.h> int main() { char x[3]; char *y; x[0]='a'; x[1]='b'; x[2]='\0'; y="abc"; printf("xの値は%s\n",x); printf("yの値は%s\n",y); } 通常の配列宣言では、このままだと文字列をまとめて 代入できないのに対して、ポインタ変数ならまとめて代入することができるのは何故ですか?そういう仕組みだと言われてしまえば、それまでなんですが・・・

  • 文字列を表すための配列とポインタ

    文字列を表すための配列とポインタ  配列とポインタは同様に扱えるもの、と思って、次のプログラムを作りました。処理系は、Visual Studio 2010 コマンドプロンプトです。 #include <stdio.h> void main(void) { char a[256]; char *b; printf("文字列を入力してください。\n"); printf("例「abcde」\n\n"); printf("配列型文字列を使います。\n"); scanf("%s", a); printf("文字列は%sです。\n\n", a); printf("ポインタ型文字列を使います。\n"); scanf("%s", b); printf("文字列は%sです。\n", b); }  すると、まずコンパイル時に、 「warning C4700: 初期化されていないローカル変数'b'が使用されます」 と表示されました。そして、実行すると、「配列型文字列」の方は問題ないのですが、「ポインタ型文字列」の方の実行後に、 「x.exeは動作を停止しました。 問題が発生したため、プログラムが正しく動作しなくなりま した。プログラムは閉じられ、解決策がある場合は Windowsから通知されます。」 と表示され、エラーとして終了してしまいます。 「char *b;」 と宣言するところが問題のようですが、なぜなのかが分かりません。どなたか、解説をお願いします。

  • C言語で文字列ではなく、文字の

    C言語で整数型の時は例えば int d[3][5]; などとおいて二次元配列を作り、文字列のときは char a[3][4]="abc,bcd,cde";(←ちょっとこの宣言も合っている自信はないが) という様に置きますよね。こういうのを文字でも利用して、 1 2 3 4 5....... A s t u v w x y.... B i u i k i k u.... C j j j j o o o.... :.................. :................. :................ という様な表を文字の2次元配列を使って printf("%c",c[i][I]); のように表したいのですが、int d[i][I]のように 文字を二次元配列を作ることは出来るんでしょうか? どなたか知っている方がいたら教えてください。

  • 配列のソート(昇順)

    最大で30個の整数データを入力し、それを大きい順に並べ替えるプログラムを1次元配列と繰り返し・if文を使って作成しなさい。 という問題で #include<stdio.h> main() { int a[30],x,y,z; printf("Seisu wo 30 ko Nyuryoku \n"); for(x=0;x<=29;x++) scanf("%d",&a[x]); printf("before sort...\n"); for(x=0;x<=29;x++) printf("%d ",a[x]); for(x=0;x<=28;x++) for(y=0;y<=28-x;y++) if(a[y]<a[y+1]) { z=a[y];a[y]=a[y+1];a[y+1]=z; } printf("\n after sort...\n"); for(x=0;x<=29;x++) printf("%d ",a[x]); } ここまで出来たのですが最大で30個ということなので(例)「10個の整数を入力して Z を入力したら終了」 としたいのですがどこをどのようにすればいいですか?

  • 関数に配列を渡して値を変える

    関数に配列を渡して値を書き換えたいのですが、文字配列である char b[10]="abc"; の書き換えが綺麗にできません。 どのように書いたら綺麗にできますか? void hen(int *a, char *b,char **c){ *a=7; b[0]='d'; b[1]='e'; b[2]='f'; //こういう書き方なら渡せるけれどb[10]="def"; 見たいな書き方で一行で値を渡す方法はないものかな? *c="jkl"; } void main (void){ int a=5; char b[10]="abc"; char *c="ghi"; hen(&a,b,&c); printf("%d %s %s\n",a,b,c); }

  • 学校の課題で2次方程式のプログラムを作ってみたのですが、足りない部分ががあるらしいのでお教えてください

    キーボードからある整数の値を入力して、2次方程式を解くというプログラムを作ったのですが、解の方程式のところでどこかが足りないらしいのですが教えてください。 #include<math.h> #include<stdio.h> int quadraticEquation(double a, double b, double c){ int x,y,l,k,j; double z; x=b*b; y=4*a*c; z=x-y; if(z>=0){ l=sqrt((double)z); } else printf("ERROR!!\n"); k=(-b)+l; j=k/2*a; return j; } int main(void){ int n1,n2,n3; printf("input three integer!\n"); printf("intger1:"); scanf("%d",&n1); printf("intger2:"); scanf("%d",&n2); printf("intger3:"); scanf("%d",&n3); printf("kotaeha %d %d desu\n",quadraticEquation(n1, n2, n3),quadraticEquation(n1, n2, n3)); return 0; } が自分が作ったプログラムです。 後、解が2つある場合の出力方法がこれであっているかどうかも教えてください。 よろしくお願いします。

専門家に質問してみよう