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

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

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

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

Q&A

6回答

2559閲覧

C言語の、fgetsや文字列関数についての質問

sakura.k

総合スコア50

C

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

0グッド

0クリップ

投稿2021/10/18 11:34

C言語の、fgetsや文字列関数についての質問です。

例えばファイルの中身が
88888888
333
7777777
1
4444
9999999
666666
55555
22
であった時、入力したとき次のように表示するコードを書く。
8888
333
7777
1
4444
9999
6666
5555
22

そのようなコードを書きたい場合、BUF_SIZE文字以上ある行を読み込もうとした場合、 BUF_SIZE文字目以上を表示せずに、 再び次の行頭から画面表示するようにすればいいと思うのですが、そのようなコードはどのように書けばいいのでしょうか。何度も考え、調べてみたのですが、読み込んだ行がBUF_SIZE文字目以上の場合、次の行を読み込むようにする方法がわかりません。すみませんが、ご教授願います。

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

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

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

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

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

BeatStar

2021/10/18 11:51

ご自分の質問を『第三者的視点で』フラットな状態で読んで下さい。 「どのようにやった」とかはっきりとわかりますか? プログラミングは「こう書けばいい」というものではありません。 決まった形というのがありません。 また、回答者は質問者と同じ環境にある…わけではありません。 よって、「どのようにやったか」さえ回答者にはわかりません。 また質問者さんの力量すらわかりません。 これでは回答のしようがないです。 質問は修正できるので修正してください。
sakura.k

2021/10/18 13:14

replitで、上のファイルを「const char *filename="saz.txt"」のように指定し、 そのファイルに対し、以下のようなコードを実行しました。しかしうまくいきませんでした。 #include<stdio.h> #include<stdlib.h> #include<string.h> #define BUF_SIZE 5 int main(void){ FILE *fp; const char *filename="saz.txt"; char buf[BUF_SIZE]; char *ch; int line=1; char *check_whole_line; char *str1; fp=fopen(filename, "r"); if(fp==NULL){ printf("Can't Open File %s\n", filename); exit(1); } while(1){ ch=fgets(buf, BUF_SIZE, fp);//ファイルを一行ずつ読み込み if(ch==NULL){ break; } check_whole_line=strchr(buf, '\n');//読み込んだ文字列の中に\nがあるかどうか判定 if(check_whole_line==NULL){//読み込んだ文字列の中に\nがなかったら、、、 printf("%s", buf); while(1){ ch=fgets(buf, BUF_SIZE, fp); if(strlen(buf)>BUF_SIZE){ strncpy(str1, buf, BUF_SIZE); printf("%s", str1); } if(ch==NULL){ break; } } exit(1); } else{ printf("%s", buf); } } fclose(fp); return 0; }
BeatStar

2021/10/18 13:21

そういうのは本文に書きましょう。 質問は修正できるので修正してください。 他のユーザ(回答者も含む)はこの修正依頼とかまでは読まない事が多いです。 (読む人もいるけど、普通は目につく質問本文のみだし) なので編集してください。 それと『うまくいかない』っていうのは本当にやめてください。 そういうのは『主観によるもの』です。 「テストを受けました。ですがうまくいきませんでした」みたいなものです。 そもそも回答者はそのテストを受けてもいないし、うまくいかないっていうのも主観的なものです。解き方そのものがわからなかったのか、計算ミスしていたのか、意図を取り間違っていたのか、記述する欄をミスったのか、わかりません。 プログラミング以前の問題です。 プログラミングっていうのは『機械とのコミュニケーション』です。人間とのコミュニケーションすら満足に取れない人が「曖昧な要求が認識できないような機械」とコミュニケーションなんて取れないはずです。 まずは『質問本文に』、「自分なりのコード」や「どのようにうまくいかないのか」は書きましょう。
ppaul

2021/10/18 19:23

fgetcを使えば悩まなくても良いのに、なぜfgetsを使うのでしょう?
guest

回答6

0

  • 全ての行について同じことをする話なので,「1行分の処理」という関数でも作ってやれば見通しが良いように思う.
  • 「各行で何文字目まで表示したいか?」 と, 「fgets()で何文字ずつ読み込むか(≒バッファのサイズ)」 というのは全く独立した話である.

(もちろん,両者の値を同一としても良いが,そのことに変に捉われる必要は無い)

上記を踏まえた例を示す.
(このコード例だと,入力に空行(改行しかない行)があった場合,そこで終了してしまうが.)

C

1//各行で何文字目まで表示するか 2#define MAX_OUTPUT_PER_LINE 4 3//fgets()で使うバッファのサイズ 4#define BUFF_SIZE 3 5 6//1行分の処理. 7//その行の先頭側 MAX_OUTPUT_PER_LINE 文字までを出力する(改行処理はしない). 8//戻り値は出力した文字数. 9int Proc_1Line( FILE *fp ) 10{ 11 char buff[BUFF_SIZE]; 12 int nOutput = 0; 13 while( fgets(buff, BUFF_SIZE, fp ) ) //てきとーなサイズずつ読み込んで… 14 { 15 //読み込んだ結果を先頭から見ていって… 16 for( int i=0; i+1<BUFF_SIZE; ++i ) 17 { 18 //改行が見つかったらこの行の処理は終了 19 if( buff[i] == '\n' )return nOutput; 20 //MAX_OUTPUT_PER_LINE文字目までは出力する 21 if( nOutput<MAX_OUTPUT_PER_LINE ) 22 { 23 putchar( buff[i] ); 24 ++nOutput; 25 } 26 } 27 } 28 return nOutput; 29} 30 31int main() 32{ 33 FILE* fp = fopen("data.txt", "r"); 34 if( fp==NULL )return 0; 35 while( Proc_1Line(fp) ){ printf("\n"); } 36 fclose(fp); 37 return 0; 38}

投稿2021/10/19 05:08

fana

総合スコア11996

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

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

0

メモリがほとんど無い環境の実行でも無い限り、十分大きなバッファーサイズでfgetsしてから、先頭の最大4文字を取り出すのがよいでしょう。

投稿2021/10/18 18:22

otn

総合スコア85901

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

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

0

fgets の代わりに fgetc を使って 1文字ずつ入力すればよいのではありませんか?
・出力した文字数を憶えておいて、4文字を超えたら出力しない。
・改行文字が来たらそれを出力し、出力文字数をゼロにリセットする。

C

1#include <stdio.h> // fopen, fclose, fgetc, putchar 2 3int main(void) 4{ 5 FILE *fp = fopen("saz.txt", "r"); 6 if (fp == NULL) return 1; 7 8 int c, k = 0; 9 while ((c = fgetc(fp)) != EOF) { 10 if (c == '\n') { 11 putchar(c); 12 k = 0; 13 } 14 else if (k < 4) { 15 putchar(c); 16 k++; 17 } 18 } 19 fclose(fp); 20}

投稿2021/10/19 18:15

kazuma-s

総合スコア8224

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

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

0

こんなんでよろしいか?

C

1#include <stdio.h> 2#include <string.h> 3#define BUF_SIZE 4 4 5int main() { 6 7 char buff[BUF_SIZE+1]; 8 FILE* fp = fopen("data.txt","r"); 9 10 while ( fgets(buff, BUF_SIZE+1, fp) ) { 11 char* ln = strchr(buff, '\n'); 12 // 読み込まれた文字列が改行を含んでいたら'\0'に置換し、 13 // そうでなかったら改行まで読み飛ばす 14 if ( ln != NULL ) { 15 *ln = '\0'; 16 } else { 17 while ( fgetc(fp) != '\n' ) ; 18 } 19 printf("[%s] ", buff); 20 } 21 fclose(fp); 22 return 0; 23}

投稿2021/10/18 15:25

episteme

総合スコア16612

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

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

fana

2021/10/19 04:39

> while ( fgetc(fp) != '\n' ) ; fgetc(fp) が EOF を返してくる場合(:入力の最終行が改行で終わっていない場合)に無限ループしそうに見えまする.
episteme

2021/10/19 07:04

あ...ご指摘のとおり。
guest

0

一つ。「基礎からやりましょう」。

入門書(サイトでもいいけど)に載っているものを一通りやりましょう。
これらは基礎です。
基礎をすっ飛ばして応用をやるのは危険です。

プログラミング程度ではよほどの事が無いかぎり、生命に危険が及ぶことはありませんが、
それでも危険です。

それに回答者からしても無駄な時間になります。

だって、足し算すらわからない人に微積分を教えるようなものですよ?

「y = x^3 + x^2 + x + 3を微分すると~」と説明しても、『微分って何?』、
微分を説明すると『二次関数って何?』、二次関数を説明すると、『そもそも足し算ってなに?』とか聞いてくるのですよ? あまりにも面倒。

仕事でも面倒だと思うのに、ここで回答しているのは『無報酬でやっているだけ』です。

無報酬で、常に受け身な人に何度も説明するぐらいならやる気のある人に説明した方がいい。

時間の無駄だと感じる。

『これぐらい教えればいいだろ』と思いますか?

教えるとしても、その基礎部分だけで数年、長ければウン十年という月日をかけてやっとできるようになるものを『御託は良いからとっとと教えろ』と言われるのです。すげぇ腹立つわ。

なので基礎をやりましょう。

二つ。『プログラミングは現実世界のシミュレーションである』。

プログラミングは「こう書けばいい」というものではありません。
現実世界のシミュレーションです。

たとえば、手作業でやるとか数学の問題に対する途中式とかのような感じでやると考えてみるのです。

今回の場合、

[依頼] 黒板に 88888888 333 7777777 1 4444 9999999 666666 55555 22 のように書かれている場合、あなたはノートに 8888 333 7777 1 4444 9999 6666 5555 22 のように書く処理をする係です。上記の処理をやってください。お願いします。

的な依頼かなんかだと考えてみてください。

この場合、とりあえず、『規則性』を見付けます。

一行目は "88888888" が "8888" となっています。個数は4。なぜでしょうね?

大抵、こういう場合は『個数で切られている』か『一個前のデータから考える』、『フィボナッチ数列のように、前項と前々項の和…のような感じ』とかのように規則性を持っています。

でも一個前のデータは何もないので比較不可能。

二行目の"333"は変わらず。個数は3。

三行目の"7777777" は "7777" となっています。個数は4。

四行目は"1"ですが、これも変わらず。個数1。

…と考えていくと、どうやら『個数を4桁にする』的なものと読めますね。

でも4桁にするのなら、二行目は"333" ではなく"3333" となるはずです。
でも変わらず。

個数が変わっているものと変わっていないものをわけてみましょう。
すると、

『4桁以上なら四桁目までで、4桁未満ならそのまま』だと考えることが出来ます。

つまり、手作業でやるなら、一行目の元のデータは"88888888" で 8行。
4桁より多いので、四桁目まで書いて次の行に進む。

8 ↓ 88 ↓ 888 ↓ 8888

と言う風に。

二行目の元の"333"は 三桁ですね。四桁までいかないので、そのまま三桁分書く。

3 ↓ 33 ↓ 333

三行目以降も同様にやる。

これを実装すればいいだけです。

C言語の、fgetsや文字列関数についての...

とあるので、『文字列として取得する』方法でもいいらしいので、

1. 以下を『これ以上ねーぞ』というまで繰り返す 1.1. 文字列として取得する 1.2. 最大個数まで出力する

で実装できそうですね。

でも、(1.2)でやる、『最大個数』がネック。常に4桁…ではなく、『四桁以下』です。

なので、『3桁なのか4桁なのか、1桁なのか、2桁なのか』を考える必要があります。

では、どうしますか?

私なら、『その元の文字数と4(桁)を比較して小さい方を最大個数として用いる』ですね。

C++であれば std::minのような処理をする。

ただし、C言語には標準にないので、if文とかでやる必要があります。
この考え方も上記の『現実世界のシミュレーション』というのでできるはずです。

そうすると、

1. 以下を『これ以上ねーぞ』というまで繰り返す 1.1. 文字列として取得する 1.2. 最大桁数を計算 1.3. (1.2)の長さ分まで出力する

的になるはずです。

三つ。『デバッグせよ』。

プログラミングは「書いて終わり」…ではありません。
デバッグと呼ばれる処理も含みます。

デバッグについては調べてください。

投稿2021/10/18 13:59

BeatStar

総合スコア4962

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

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

0

読み込んだ行がBUF_SIZE文字目以上の場合、次の行を読み込むようにする方法がわかりません

いきなり「次の行を読み込む」まで飛躍しないで、BUF_SIZE文字目以降改行が見つかるまで読み飛ばせばよいのでは?

あるいは、一行の最大文字数が既知なら、とにかく一行読んでしまって先頭のBUF_SIZEを切り出す、という手もあるでしょうが。

投稿2021/10/18 12:53

thkana

総合スコア7703

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問