質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

5回答

8682閲覧

C言語の構造体配列の末尾に新規の配列を追加する方法

humuhimi

総合スコア49

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2019/08/04 02:45

編集2019/08/04 07:41

現在、課題でsample.txtを構造体に入れたのちに新規でデータを入れることを実現したいとしているのですがうまく行きません。
今試している方法としては
0. define MAXCNT 100で配列の最大数を100に指定します。
0. そして、既存のデータ55件(sample.txt)をまずは構造体に読み込みます。
0. さらに、追加で既存の配列+1(ここでは56番目などに)新規にデータを入れ込む方法です。
これがうまくいかないのでうまくいく方法があれば教えてほしいです。

また、他に

  • 読み込んだ名前データの表示が文字化けする(深�)みたいなバグもありますのでよければこちらもついでに教えてほしいです。

C言語できる方どなたかご教授いただきたいです。
よろしくお願いします。

sample.txt

1深津 旭弘 29 183 78 2深津 英臣 27 180 70 3藤井 直伸 25 183 78 4関田 誠大 23 177 70 5米山 裕太 32 185 85 6鈴木 悠二 35 190 80 7清水 邦広 30 193 94 8高松 卓矢 29 186 82 9栗山 雅史 28 190 85 10柳田 将洋 24 186 79 11山田 脩造 24 193 78 12高野 直哉 24 190 77 13小川 猛 22 193 90 14久原 翼 22 189 79 15石川 祐希 21 192 84 16鈴木 祐貴 20 201 85 17新井 雄大 19 188 86 18富松 崇彰 32 192 85 19李  博 26 194 83 20傳田 亮太 25 191 84 21出耒田 敬 25 200 92 22山内 晶大 23 204 72 23高橋健太郎 22 202 100 24大竹 壱青 21 201 100 25小野寺太志 21 201 98 26古賀太一郎 27 170 70 27浅野 博亮 26 178 69 28鶴田 大樹 25 177 76 29井手 智 25 174 74 30冨永こよみ 28 176 67 31佐藤 美弥 27 174 61 32田中 美咲 25 173 61 33宮下 遥 22 177 61 34石井 里沙 27 179 65 35新鍋 理沙 26 173 64 36長岡 望悠 25 179 64 37石井 優希 26 180 68 38野本 梨佳 25 180 73 39内瀬戸真実 25 171 70 40堀川 真理 25 183 70 41高橋 沙織 24 177 67 42鍋谷友理枝 23 176 57 43井上愛里沙 22 178 66 44田中 瑞稀 21 170 73 45古賀紗理那 21 180 66 46黒後 愛 19 180 69 47荒木絵里香 32 186 78 48松本亜弥華 28 188 71 49岩坂 名奈 26 187 76 50奥村 麻依 26 177 66 51島村 春世 25 182 77 52大野 果奈 25 180 70 53井上 琴絵 27 162 53 54佐藤あり紗 27 166 53 55小幡 真子 24 164 55

main.c

1/* 2- case2で年齢(age)27を表示するときだけ7になってしまうバグがあります。 3- 日本語を読み込んだ際に文字化けするバグがあります。 4char型-string型によるバグだと思う 5*/ 6 7#include <stdio.h> 8#define MAXCNT 100// sample.txtの行の最大許容数 9// 構造体定義の宣言 10// 参考:【B4】おまけ課題 4~10行目 11// 関数のプロトタイプ宣言 12int is_loaded(); 13// 参考:【B4】おまけ課題 12~14行目 14typedef struct Body 15{ char name; 16 // char name[10]; もしかしたらこっちの方がいいかも 17 int age; 18 int height; 19 int weight; 20}Body; 21 22int main(void) 23{ 24// 変数の宣言 25// 参考:【B4】おまけ課題 18~20行目 26 int i,j=0,max_num,flag=0;//初期値など 27 int tmp_age=0,tmp_height=0,tmp_weight=0;//平均の準備用 28 float avg_age,avg_height,avg_weight;//平均 29 char new_name; 30 int new_age,new_height,new_weight; 31 char fname[] = "sample.txt";//読み込むためのファイル名 32 Body Data[MAXCNT]; 33 FILE* fp; 34 35int menu; 36while(1){ 37printf("\n=== 操作メニュー ===\n"); 38printf("1:ファイル読み込み\n"); 39printf("2:全データ表示\n"); 40printf("3:新データ入力\n"); 41printf("4:ファイル書き出し\n"); 42printf("1~4以外:終了\n\n"); 43printf("操作No の入力:"); 44scanf("%d",&menu); printf("\n"); 45switch(menu){ 46case 1: 47// ファイルを開き 構造体配列に読み込む 48// 参考:【B4】おまけ課題 22~33行目 49fp=fopen(fname,"r"); 50if(fp == NULL){ 51 printf("ファイルを開けませんでした\n"); 52 return -1;//異常終了 53} else 54{ 55 printf("%s ファイルを開きました\n",fname); 56 // fread(fname,sizeof(char),10,fp); 57 printf("%s ファイルを読み込みました\n",fname); 58 for(i=0;i<MAXCNT;i++) { 59 if(fscanf(fp,"%s%d%d%d\n", 60 &Data[i].name, 61 &Data[i].age, 62 &Data[i].height, 63 &Data[i].weight) == EOF) break; 64 } 65 66 Data[56].name = '*'; 67 Data[56].age = 27; 68 Data[56].height = 130; 69 Data[56].weight = 61; 70 // Data[57].name = '*'; 71 // Data[57].age = 23; 72 // Data[57].height = 170; 73 // Data[57].weight = 40; 74 // printf("%d",Data[56].age); 75 76 77 fclose(fp); 78 printf("ファイルポインタを閉じました\n"); 79 flag=1;//case 2に映るためのフラグを持たせる 80 printf("サイズの確認:%d",i); 81} 82break;// case1 終了 83 84case 2: 85// 構造体配列の内容を1件1行として画面に表示 86// データ件数と、それぞれの項目についての全件の平均値を表示 87// 参考:【B4】おまけ課題 35~37行目 88// if(!is_loaded(flag))//テキスト読み込まれてるか 89// {break;} 90if (flag!=1){ 91 printf("\nファイル読み込みを先に実行してください\n"); 92 break; 93} 94else 95 { 96printf("データを表示する\n行数\t名前\t年齢\t身長\t体重\n"); 97while(1) { 98 printf("%d:\t%s\t%d\t%d\t%d\n", 99 j+1, 100 &Data[j].name, 101 Data[j].age, 102 Data[j].height, 103 Data[j].weight); 104 // 年齢、身長、体重の合計 105 tmp_age += Data[j].age; 106 tmp_height += Data[j].height; 107 tmp_weight += Data[j].weight; 108 if(j==i) break;//iはデータの読み込み件数(デフォルト55件) 109 j++; 110} 111printf("\n全データを出力しました\n"); 112// 年齢、体重、身長の平均 113avg_age = tmp_age/MAXCNT; 114avg_height = tmp_height/MAXCNT; 115avg_weight = tmp_weight/MAXCNT; 116printf("\n合計件数:%d\n",MAXCNT); 117printf("平均を表示\n"); 118printf("平均年齢:%f\t平均身長:%f\t平均体重:%f\n",avg_age,avg_height,avg_weight); 119break; 120} 121case 3: 122// 構造体配列に新データを追加する 123// 参考:【B4】おまけ課題 39~48行目 124if (flag!=1){ 125 printf("\nファイル読み込みを先に実行してください\n"); 126break; 127} 128else{ 129 int new_row = i+1; 130 printf("新しく追加するデータを入力してください\n"); 131 printf("それぞれ追加するデータを|名前,年齢,身長,体重|の形式で入力してください\n"); 132 // scanf("%c,%d,%d,%d",&new_name,&new_age,&new_height,&new_weight); 133 scanf("%c,%d,%d,%d",&Data[56].name,&Data[56].age,&Data[56].height,&Data[56].weight); 134 // scanf("\n年齢:%d",&Data[56].age); 135 // scanf("身長:%d",&Data[56].height); 136 // scanf("体重:%d",&Data[56].weight); 137 // Body Data[new_row] = {new_name,new_age,new_height,new_weight};//直近の行数+1配列目にデータを入れる 138} 139case 4: 140// 構造体配列の内容をファイルに書き出す 141// 参考:【B4】おまけ課題 50~59行目 142break; 143default: 144// プログラムを終了 145return 0; 146} 147} 148return 0; 149} 150// 関 数 の 定義 151// FIXME 152int is_loaded(int flag) 153{ 154 if (flag!=1){ 155 printf("\nファイル読み込みを先に実行してください\n"); 156 return -1; 157}else{ 158 // ファイル読み込みチェック完了 159 return 0; 160} 161} 162// 参考:【B4】おまけ課題 64行目以降 163//【B1】ステップ1 27~44行目 、【B2】ステップ2 52~63行目 164コード

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2019/08/04 04:54

「3.3さらに、追加で既存の配列+1(ここでは56番目などに)新規にデータを入れ込む方法です。 これがうまくいかないのでうまくいく方法があれば教えてほしいです。」とはどういうことでしょうか? どんなコードを試してどんな結果(エラーなど)になったのでしょうか?
humuhimi

2019/08/04 07:48

Body構造体のDataを定義してから ```c printf("%s ファイルを開きました\n",fname); // fread(fname,sizeof(char),10,fp); printf("%s ファイルを読み込みました\n",fname); for(i=0;i<MAXCNT;i++) { if(fscanf(fp,"%s%d%d%d\n", &Data[i].name, &Data[i].age, &Data[i].height, &Data[i].weight) == EOF) break; ``` でsample.txtを読み込んだのですが、下記のcase3 にて新しいデータを追加したいです。 scanf("%c,%d,%d,%d",&Data[56].name,&Data[56].age,&Data[56].height,&Data[56].weight);
humuhimi

2019/08/04 07:48

読みにくっ!すみません。。。
guest

回答5

0

mainの中でなんもかんもやらせてる時点で、僕なら窓から投げ捨てる。
少なくともメニュー項目ごとに関数に分割し適切に呼び分けろ。

投稿2019/08/04 03:48

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

humuhimi

2019/08/04 07:50

そうですね。期限ギリギリなんでスパゲティーコードでいいやという甘い考えでやってました。 リファクタリングします! ありがとうございます
guest

0

ベストアンサー

全部、見た訳ではありませんが、

typedef struct Body
{ char name;

となっていて、

if(fscanf(fp,"%s%d%d%d\n",
&Data[i].name,

はダメです。name は一文字分しか、無いのに複数の文字が読み込まれています。

// char name[10]; もしかしたらこっちの方がいいかも

ではなく、そうする必要があります。 ただ、10はサイズが小さいので、名前に十分なサイズの確保を。(お試しだっら、100くらい指定するが、それと末尾の '\0' 分を忘れないように)

質問文には、56番目とありますが、

Data[56].name = '*';

C言語は、番号は0から始まるので、 55じゃないでしょうか?
上記にも書きましたが、 nameは、1文字分なので、文字列にはなりません。

まず、この辺の確認から、お願いします。

投稿2019/08/04 03:06

pepperleaf

総合スコア6383

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

humuhimi

2019/08/04 07:56

まさに配列番号は55でした。不注意でした ちゃんと55番にしたら構造体内に入ったので出口が見えてきました!ありがとうございます 助かりました!
humuhimi

2019/08/04 08:16

全ておっしゃる通りでした。 char nameの配列数を増やしてインデックスを55に直したら全部うまく行きました。 本当に助かりました。ベストアンサーありがとうございます
BeatStar

2019/08/06 03:46

(横から失礼します...) あ、そっちか! なるほど。
guest

0

たぶん、オプショナルな問題は表示するときの問題だと思います。
WindowsならWindowsのOS側で...っていう方法もあるようですが、

C言語側では日本語のような文字を使う場合は char ではなくて wchar_t を使います。

二バイトで一つ分と見なすようです。

もし

char str[] = "あいうえお";

とあったら、

wchar_t str[] = L"あいうえお";

となる。

wchar_t に関しては調べたら普通に出てきます。
("追記1" を参照)

あとはいわゆる『ダメ文字』って呼ばれる文字を使っているからかも。

[質問に関して]

※ 私自身が思考停止してしまっています...

まず、何がわからないのでしょうか。

今試している方法としては

1define MAXCNT 100で配列の最大数を100に指定します。
2そして、既存のデータ55件(sample.txt)をまずは構造体に読み込みます。
3さらに、追加で既存の配列+1(ここでは56番目などに)新規にデータを入れ込む方法です。
これがうまくいかないのでうまくいく方法があれば教えてほしいです。

とありますが、これ、全部じゃないですよね?

3がわからないのでしょうか?

もし3がわからないにしても、何がわからないのかが不明瞭です。

追加する方法自体がわからないのか、『ストックされている範囲がわからない』のか。

後者は、56番目まで使われているのなら、次の場所である 57番目にセットしたい...
みたいな感じだけど、その56番目まで使われている っていうことをどうやって調べるのか。

ってことでしょうか?

それなら、

方法1: 単純にforで『空の場所を探す』。 例: 0~56番目まで使われているなら、0~56までは何かしらのデータが入っている. しかし57番目に差し掛かると、『何も入っていない状態』であるため、 現在位置である57番目を-1した (= 前回の場所 ) 要素番号までが使われているとみなす.
方法2: 変数を一つ用意して、その変数に『何番目まで使われているか』をストックしておく. 例: 何番目まで使われているかを示す変数を posとしておく. posの初期値は-1 ( 何も入っていないため ). 0番目にセットしたら pos をインクリメント ( pos++ ) して、0にしておく. (0番目までは使っている) 1番目に追加したら posをまたインクリメントして pos = 1 としておく. ... (別にposを『位置』ではなく、『個数』としてもいい。その場合は初期値は0としておく。 使う場合は pos-1 のようにするが)

とかが思いつきますね。


[追記1]

どこの記事だったか、忘れましたが、wchar_tはもしかすると他のOSかコンパイラによっては使えない可能性があります。(うろ覚え)

一応の方法として上記のやつは残しておきます。

投稿2019/08/04 03:26

編集2019/08/06 03:45
BeatStar

総合スコア4958

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

humuhimi

2019/08/04 03:31

丁寧な回答ありがとうございます。 とりあえず今は構造体配列に直接新規のデータを追加したいです。 55件名まではデータを読み込んでいる。 scanfで新たに名前、年齢、身長、体重を追加してそれをファイルに書き込むのではなく、main.cの構造体配列に追加するということをしたいです! 今外出中なのであとでしっかり見ておきます! ありがとうございます
humuhimi

2019/08/04 08:15

wchar_t型は初めて聞きました!調べたところうまく行きそうです。 今回は結局は僕が指定している配列の番号が間違っていたのが原因でした。 他のやり方として string.hのstrcpy(Data[55].name,"名前");とする方法でもできました。 下の方法1と方法2についてですが、僕は方法2を使ってます。 別の変数を用意するというより、データを読み込む際行数とループ用の変数iが対応しており、EOFでループを抜けるようにしました! 長文の回答ありがとうございます。 知識が広がり、助かりました
BeatStar

2019/08/06 03:46 編集

>> 今回は結局は僕が指定している配列の番号が間違っていたのが原因でした。 あ、そっちかぁ...
guest

0

C言語ではあらかじめ確保した配列を拡張させるような事はできません。
配列で宣言せずに、mallocで領域確保するようにすれば、reallocってので確保領域の再割り当てができますね

投稿2019/08/04 03:04

編集2019/08/04 03:05
y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

humuhimi

2019/08/04 07:56

malloc,reallocは初めて聞いたので調べてみます! ありがとうございます!
guest

0

scanf("%c,%d,%d,%d",&Data[56].name,&Data[56].age,&Data[56].height,&Data[56].weight);

の「"%c,%d,%d,%d」を「"%c %d %d %d」(,でなく半角空白1文字)に変えてみてください。

投稿2019/08/04 09:20

meg_

総合スコア10579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問