• 締切済み

C言語の問題が解けません

C言語の問題ができなくて困っています。 これが問題文です。 与えられた表の縦・横の値の平均/合計をそれぞれの行・列ごとに求め出力するプログラムを作成しなさい。ただし、縦・横のデータ数は10個未満とし、それぞれの数字は整数とする。また、出力は右詰め6桁で出力することとし、平均における小数点以下は1桁まで表示する。平均行/列および合計行/列がぶつかる個所は、表全体の平均と合計を計算した結果を表示する。 補足として入力された行列数が10未満であることは、プログラム内でチェックすること。 例:20,3→再入力となる(行が9未満でない)  :2,-5→再入力となる(行が負の値) 実行結果例はこんな感じらしいです。 行数(最大9),列数(最大9)をカンマ区切りで入力(行,列):4,4 データをカンマ区切りで行ごとに入力[4行 4列] 52,96,15,20 86,22,35,45 45,78,54,36 16,86,74,55  52 96 15 20 45.8 183  86 22 35 45 47.0 188  45 78 54 36 53.3 213  16 86 74 55 57.8 231 49.8  70.5 44.5 39.0 50.9 - 199 282 178 156 - 815 自分はここまで自力でやったのですがここからが試行錯誤してもできません。このあとどのようにプログラムを書いていけばいいのですか? よろしくお願いします。 #include <stdio.h> int main(){ int gyou,retu,Loop1=0,Loop2=0; int kazu[8][8]; printf("行数(最大9行)、列数(最大9列)をカンマで区切って入力 (行,列):"); scanf("%d,%d",&gyou,&retu); if((gyou<=9)&&(retu<=9)){ printf("データをカンマ区切りで行ごとに入力 [%d行,%d列]\n",gyou,retu); for(Loop2=0;Loop2<gyou;Loop2++){ for(Loop1=0;Loop1<retu;Loop1++){ scanf("%d\n",&kazu[gyou--][retu--]);

みんなの回答

  • tig33
  • ベストアンサー率50% (6/12)
回答No.9

記述ミスがありました。 IsOKChar()関数の中の   rt = FALSE+ は   rt = FALSE; の間違いです。

  • tig33
  • ベストアンサー率50% (6/12)
回答No.8

tig3です。 質問を良く読み返してみると、 データをカンマ区切りで行ごとに入力[4行 4列] とありますね。 正確な入力を作成するのはかなり骨が折れますよ。 #define INMAX (1024) #define TRUE (1)    ←これは、定義してあるコンパイラなら不要 #define FALSE (0)    ←これは、定義してあるコンパイラなら不要 #define STREND ('\n') #define SEPARATER (',') #define DIGMAX (6) char inbuf[INMAX];  /* 入力文字列を格納する領域です。 とりあえず最大1024文字とします*/ /* 1文字が許容される文字かを検証する */ int IsOkChar( int c ) {   static char OKchar[] = "0123456789,";   char *cp;   int rt;      rt = FALSE+   for( *cp=OKchar; *cp != STREND; cp++ ) {     if( c == *cp ) {       rt = TRUE;       break;     }   }      return( rt ); } /* 1行が許容される文字だけで校正されているかを検証する */ int IsOkString( char *text ) {   int ct;   char *cp;   int rt;      cp = text;   rt = TRUE;   for(ct=0; *cp != STREND ; ct++, cp++) {     if( IsOkString(*cp) == FALSE ) {       rt = FALSE;       break;     }   }   return( rt ); } /* 与えられた文字列から数値を抽出して配列に格納する */ /* 文字列に指令列数以上の数字列があった場合は、先頭から指定数だけが処理される */ /* 文字列に指定列数未満しかなかった場合は、不足したところは0が入る */ int SetArrayCol(char *text, int kazu[][], int row, int colCount) {   int col, ct, rt;   char *cp, *wp;   char wkbuf[8]; /* 命題は6桁以内の数字なので8文字文用意する*/      rt = TRUE;   cp = text;   for( col=0; col < colCount; col++) {     wp = wkbuf;     *wp = STREND;     ct = 0;     while( (*cp != STREND) && (*cp != SEPARATER) ) {       *wp++ = *cp++;       ct++;       if( ct > DIGMAX ) {         return( FALSE );       }     }     *wp = STREND;     kazu[row][col] = atoi(wkbuf);   }      return( rt ); } /*文字列を入力する部分*/ /* 注意  入力文字列が1024文字を超えることが想定される場合は、  gets()関数ではなく、fgets()関数で入力文字数の最大を制御  しなければいけません */   int CheckOK;  printf("データをカンマ区切りで行ごとに入力 [%d行,%d列]\n",gyou,retu);  for(Loop2=0;Loop2<gyou;Loop2++){    do {      gets(inbuf);      if( strlen(inbuf)==0 ) {        printf("処理を中断します。\n");        return(0); /* または、exit(0); */      }            CheckOK = FALSE;      if( IsOkString(inbuf) == TRUE ) {        CheckOK = SetArrayCol(inbuf, loop2, retu);      }      if( !CheakOK ) {        printf("データの指定に誤りがあります。再度入力してください\n");      }    } while( !CheckOK );  } こんな具合かと思います。プログラムのコンパイルと実行のデバグはしていませんので、自力で完成させてください。  

  • tig33
  • ベストアンサー率50% (6/12)
回答No.7

ANo.2のtig3です。 #include文については、ANo.6でmasklkih様が丁寧に答えていただいていますので、もう既にご理解なさったかと思いますが、簡単に、 #include文は、マクロの定義ですが、とりあえずの理解としては、数字(数値)を別名で定義する用途に多く用いられる、と覚えても差し支えないでしょう。(C言語ではです。C++では、そういった定義はconstを使うように推奨されています。) 今回の問題では、9x9のデータを扱う命題ですが、これが、15x15とか別の命題になったときに、合計値と平均値を格納する領域がずれてきます。プログラム中にこれをそのまま、合計値や平均値の要素を示す番号を記述していると、命題が変更になる毎にプログラム全体を眺めて、変更しなければいけなくなります。 そうすると、一部だけ変更をするのを忘れてしまったりすると、これがバグになります。 #define AVEIDX (9) これは、プログラム中に現れるAVEEDXは、9と置き換えてくださいとコンパイラに教えることになります。 今回のプログラムでも、しっかりとするなら、 #define DATA_COUNT (9) #define DATA_END_INDEX (DATA_COUNT-1) #define AVEIDX (DATA_END_IDX+1) #define SUMIDX (AVEIDX+1) のように定義すると完璧(?)だと思います。(要素数が変わったら、DATA_COUNTの数字を変更するだけで済みます。) mixiでは、半角の空白が詰めて(プロポーショナルフォントのため)表示されるので、文字列と「(」がくっついて、関数みたいに見えますが、空白が入っているのを注意してください。 データの入力方法がわから無いと言うことですが、ご自分で質問の中に既に記述されて得いるので、回答からは省いたのですが、入力を、カンマ区切りで一行ずつ行いたいと言うことでしょうか? それなら、scanf関数を使って、 1x1の場合は、scanf("%d",&kazu[0][row]); 2x2の場合は、scanf("%d,%d",&kazu[0][row],&kazu[1][row]);   ・   ・   ・ 9x9の場合は、scanf("%d,%d,%d,%d,%d,%d,%d,%d,%d,"             ,&kazu[0][row]             ,&kazu[1][row]             ,&kazu[2][row]             ,&kazu[3][row]             ,&kazu[4][row]             ,&kazu[5][row]             ,&kazu[6][row]             ,&kazu[7][row]             ,&kazu[8][row] ); ということになりますが、これでは、最適化したプログラムとは言えませんね。 これを最適化するのは、かなりテクニックを必要とします。(scanf()関数を使って、数値を1個づつ入力するとそのたびにENTERキーを押さなければ行けませんから、カンマで区切って入力することはできません。) 基本的には、gets()関数を使って一行入力を行い、カンマ区切りの文字列に分けてから整数に変換して各配列要素に取り込まなければなりません。 この場合、要素数の一致、不一致の検証もしなければいけない(不一致の場合は再入力が必要、また、途中の中断・中止も考慮すると、本格的なプログラミングになります)ので、けっこうプログラムは大変になります。 どうしても、こうしたいというのであれば、お教えしますが、とりあえずは、ご自分のかかれたプログラムでデーターを入力してみてはいかがですか?

  • maslkjh
  • ベストアンサー率45% (10/22)
回答No.6

No.2様のプログラムで #define AVEIDX (9) #define SUMIDX (10) が教科書に載っておらずこれをなしでプログラムしたいとのことですが、これはC言語を使うのなら常識的に知っておいてほしい構文ですし、わざわざ使わないで書くようにするのはナンセンスです。#define文なしで、という指定があるわけでもないでしょう?(尤もそんな指定があったとしてもバカげていますが) この場合#define文を使うことで「マジックナンバー」(←)を減らすという効果と、仕様変更に強いプログラムを作るという効果が得られます。マジックナンバーというのはプログラミングをする上でなるべく避けた方がよいとされているものです。マジックナンバーでgoogle等で検索してみるといろいろ出てきますw 私がこれからCを書く上で参考になると思うページを紹介します。↓ http://www.kojima-cci.or.jp/fuji/mybooks/cdiag/

回答No.5

#include <stdio.h> int check(int m, int n) { if(m <= 0 || 9 < m || n <= 0 || 9 < n){ puts("Again!!"); return 1; } return 0; } void input(int a[][10], int m, int n) { int i, j; for(i = 0; i < m; i ++){ for(j = 0; j < n; j ++){ scanf(" %d, ", &a[i][j]); a[i][n] += a[i][j]; a[m][j] += a[i][j]; } } for(i = 0; i < n; i ++) a[m][n] += a[m][i]; } double average(int sum, int n) { int r = sum % n; r = (r * 100 / n + 5) / 10; return sum / n + (double)r / 10; } void show(int a[][10], int m, int n) { int i, j; fputs(" ", stdout); for(i = 0; i < n; i ++) printf(" [][%d]", i); puts(" Ave Sum"); for(i = 0; i < m; i ++){ printf(" [%d][]", i); for(j = 0; j < n; j ++) printf("%6d", a[i][j]); printf("%6.1f%6d\n", average(a[i][n], n), a[i][n]); } fputs(" Ave ", stdout); for(i = 0; i < n; i ++) printf("%6.1f", average(a[m][i], m)); printf("%6.1f\n", average(a[m][n], m * n)); fputs(" Sum ", stdout); for(i = 0; i < n; i ++) printf("%6d", a[m][i]); printf(" %6d\n", a[m][n]); } int main(void) { int a[10][10] = {0}, m, n; do{ scanf("%d, %d", &m, &n); }while(check(m, n)); input(a, m, n); show(a, m, n); return 0; }

  • tig33
  • ベストアンサー率50% (6/12)
回答No.4

ANO.3に、列の合計の表示が抜けていました。。。 でも、意図するところは推して知るべし、、ですね!

  • tig33
  • ベストアンサー率50% (6/12)
回答No.3

まず、データと、平均値、合計を格納する領域(メモリー)が必要ですね。 ANo.2の方が指摘しているように、データは、行、列、ともに最大9個(10未満)ですから、平均値と、合計を入れる場所を確保するためには、 int kazu[9+2][9+2]; が、必要です。要素の数(11)は、要素を示す(0-10)とちがうことに注意してください。 で、平均値と、合計を入れる場所(要素を示す順番)を示す #define AVEIDX (9) #define SUMIDX (10) ANo.1の方が、指摘しているのは、ちょっと考え違いだと思います。 質問者は、この続きをどうプログラミングしていいのか分からないことを言いたいだけだと思います。 考え方は、 (1) 行の合計と平均値を計算して、指定の場所へ格納する。 (2) 列の合計と平均値を計算して、指定の場所へ格納する。 (3) 全体の合計と平均値を計算して、指定の場所へ格納する。 (4) 結果を表示する。 と、(1)~(4)を順番に処理することを考えればできると思います。 (1)は、 int row, col, sum, ave;  for(row=0; row<gyou; row++) {    sum = 0;    for(col=0; col<retu; col++) {      sum += kazu[row][col];    }    kazu[row][SUMIDX] = sum;    kasu[row][AVEIDX] = (sum*10)/retu; /*整数なので10倍しておく*/  }   (2)は、行と列を交換すればできますね。  結果を入れるところは、      kazu[SUMIDX][col] と kazu[AVEIDX][col] ですね (3)は、全体の合計をデータ数から計算できます。  結果を格納するところは、  考えてください。 (4)は、ちょっと工夫が必要です。 (a) 1行の表示(データ+列の平均値と合計)  for(row=0; row<gyou; row++) {    for(col=0; col<retu; col++) {      printf("%6d ", kazu[col]);    }    printf( "%4d.%1d ", kazu[row][AVEIDX]/10, kazu[AVEIDX]%10 );    printf( "%6d\n", kazu[row][SUMIDX] );  }   (b) 列の平均値の表示  for(col=0; col<retu; col++) {    for(row=0; row<gyou; row++) {      printf( "%4d.%1d ", kazu[row][AVEIDX]/10, kazu[row][AVEIDX]%10 );    }  } (c) 全体の平均値の表示  printf( "%4d.%1d\n", kazu[AVEIDX][AVEIDX]/10, kazu[AVEIDX][AVEIDX]%10 ); (d) 全体の合計の表示  printf( "%6d\n", kazu[SUMIDX][SUMIDX]/10, kazu[SUMIDX][SUMIDX]%10 ); これで、できあがり~~

hiroshi192
質問者

お礼

回答ありがとうございます。 合計と平均値の計算方法はわかったのですが、 52,96,15,20 86,22,35,45 45,78,54,36 16,86,74,55 これの入力方法がわかりません。 どうやればこうやって入力できるのでしょうか。 教えていただけないでしょうか? あと勝手ながら #define AVEIDX (9) #define SUMIDX (10) が教科書に載っていません。 これを使わないでこのプログラムは作れないのでしょうか? よろしくお願いします。

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

最大9行9列(データの最大個数は81)ですよね?だとすると、 > int kazu[8][8]; この定義はまずいです。64個までしか入りません。

hiroshi192
質問者

お礼

回答ありがとうございます。 要素の数(11)は、要素を示す(0-10)を勘違いして理解していたようです。 定義しなおしました。ありがとうございました。

  • maslkjh
  • ベストアンサー率45% (10/22)
回答No.1

この問題は結構プログラムに時間掛かると思いますが、とりあえずコードを見て思ったことを書くと。 このプログラムはこのままの状態ではかっこの数が対応してないのでコンパイル出来ないことは分かっていると思いますが、未知のプログラムを書くときはなるべく常にコードがコンパイル出来る状態を保つ様な感じで、ちょっとずつコードを継ぎ足して書いていくと上手くいくかも知れません。(もちろん厳密な意味でその様なことは無理でしょうが。) あと、 if((gyou<=9)&&(retu<=9)){ ←ここの中括弧は意図しているものですか?必要でしょうか?

hiroshi192
質問者

お礼

回答ありがとうございます。このプログラムを作成するのにすでに5時間も奮闘しています・・・・ if((gyou<=9)&&(retu<=9)){←if文のときは必要だと思ったんですが。