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

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

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

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

Q&A

解決済

4回答

791閲覧

C言語 paizaカンマ区切りのN個のデータの入力 について

nayoaka

総合スコア1

C

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

0グッド

0クリップ

投稿2024/08/31 01:40

実現したいこと

https://paiza.jp/works/mondai/stdin/stdin_comma_n/edit?language_uid=c&t=9ecdd71f9dbb19d3069d5b28c63359d9
こちらの問題を解こうとしています。

発生している問題・分からないこと

イメージ説明

該当のソースコード

#include <stdio.h> #include <string.h> int main(void){ //int kakunou; char str[1000]; char changeS[10] = ","; //変更する文字を指定 char * point; int num; fgets(str,sizeof(str),stdin); //一行目引数を入力 sscanf(str,"%d", &num); //引数をnumに格納 for(int i=0; i < num; i++){ fgets(str,sizeof(point),stdin); point = strtok(str, changeS); printf("%s\n",point); point = strtok(NULL, changeS); } return 0; }

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

引数num回分ループの処理を入れてstrtokで,をNULLにしたのを、printfすることで解けそうというとこまでわかりました。 いろいろ入れ替えたり()の中設定を変えたりしましたが、うまくいっていません。どうした良いか教えて頂けると幸いです。

補足

特になし

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

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

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

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

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

hiroki-o

2024/08/31 02:16

リンク先はpaizaのアカウントが無いので見られませんが、何を入力したら何が出力される問題なのでしょうか?
tatsu99

2024/08/31 03:50 編集

リンク先をクリックしましたが 404 Not Foundが表示されます。 前の方が、言われているように、「何を入力したら何が出力される問題」なのかを提示したほうが回答がつくと思います。 入力データと期待する出力結果のサンプルがあると、なお良いでしょう
jimbe

2024/08/31 04:29 編集

最初の画像にあるシェア用 URL を提示されるべきでしょう。 質問者さんがアクセスした時の URL はご自身用のパラメータ付きなのでアクセスできません。
melian

2024/08/31 05:04

入力例4で試してみると、以下の結果になります。 10 31415926,qqqqqq,abab313,xyz31131,5,6,7,8,9,10 => 3141592 6 q 13 1131 6 10 10 10 10 以下の部分で sizeof(point) の値(ポインタサイズ)は 8 や 4 になります。根本的に勘違いをされている様です。 char * point;   : for(int i=0; i < num; i++){   fgets(str,sizeof(point),stdin);
nayoaka

2024/09/01 03:47

考え直したらそうでした。ありがとうございます。sizeof(str)は試したのですが 1行目の読み込みが3回出力されるようになってしまっていて、理解が足りず、具体的にどうしたらいいかわかっていない状況です。
guest

回答4

0

ベストアンサー

何時どのような形で何を標準入力から取得し、何をループして何をするのか・・・つまり全体的な入出力の設計が出来ていません。 strtok うんぬんは末端のことで、それ以前の問題です。
strtok を使うよう指示があるわけでもありませんので strtok を使わず文字配列を自身で弄る形にしたほうが良いかもしれません。

いろいろ入れ替えたり()の中設定を変えたりしました

プログラムはテキトウに弄って動けば良いというモノではありません。機械式時計の歯車のように全て意味が有り噛み合ってこそのプログラム/システムであり、ただ正解が出れば良いと運に任せるようでは勉強する意味が無いでしょう。
ついキツイことを言ってしまいますが、もしそのような考えでたまたま動いたプログラムが原子炉の制御システムや飛行機の航行システム・銀行等の基幹システムに入っていて問題が起きたら、運が悪かったでは済まされません。

以下は strtok を使わない場合です。
二行目の最大文字数(100)が入る配列に gets で読み込み、各文字毎に判断して文字の表示もしくは改行・処理終了を行います。読み込んだ全てを処理すれば良いので N を使う必要はありません。

c

1#include <stdio.h> 2 3int main(void){ 4 char b[100+1]; //最大100文字+終端文字分 5 6 gets(b); //一行目取得 7 int N = atoi(b); //(取得したけども使わない) 8 gets(b); //二行目取得 9 for(int i=0; ; i++) { //文字毎にループ 10 if(b[i] == ',' || b[i] == '\0') { //区切りか文字列の終わりなら 11 printf("\n"); //改行 12 if(b[i] == ',') continue; //区切りなら次のループへ 13 break; //区切りじゃない(=文字列の終わり)なら終了 14 } 15 printf("%c", b[i]); //文字を表示 16 } 17}

入力

3 aaaaa,bbbbbb,cccc

出力

aaaaa bbbbbb cccc

strtok 的に書くと

c

1#include <stdio.h> 2 3int main(void){ 4 char b[100+1]; //最大100文字+終端文字分 5 6 gets(b); //一行目取得 7 int N = atoi(b); //(取得したけども使わない) 8 gets(b); //二行目取得 9 char *p = b; 10 for(int last=0/*false*/; !last; ) { //最後の処理まで 11 char *e = p; 12 while(*e!=',' && *e!='\0') e++; //文字列の終わりを探す 13 if(*e == '\0') { 14 last = 1; //true: これが最後 15 } else { 16 *e = '\0'; //',' を '\0' に書き換え 17 } 18 printf("%s\n", p); //文字列を表示 19 p = e + 1; //次の文字列の先頭 20 } 21}

strtok を使うなら以下のようになります。
for ループ内に埋め込んでいますが、最初は第一引数に文字列の先頭を指定し、ループ二回目以降は NULL とします。

c

1#include <stdio.h> 2#include <string.h> 3 4int main(void){ 5 char b[100+1]; //最大100文字+終端文字分 6 7 gets(b); //一行目取得 8 int N = atoi(b); //(取得したけども使わない) 9 gets(b); //二行目取得 10 for(char *p=strtok(b, ","); p!=NULL; p=strtok(NULL,",")) { //文字列が取得できている間ループ 11 printf("%s\n", p); //文字列を表示 12 } 13}

for を while に変えるとこんな感じに。

c

1#include <stdio.h> 2#include <string.h> 3 4int main(void){ 5 char b[100+1]; //最大100文字+終端文字分 6 7 gets(b); //一行目取得 8 int N = atoi(b); //(取得したけども使わない) 9 gets(b); //二行目取得 10 char *p = strtok(b, ","); //最初の文字列を取得 11 while(p != NULL) { //文字列が取得できている間ループ 12 printf("%s\n", p); //文字列を表示 13 p = strtok(NULL, ","); //次の文字列を取得 14 } 15}

投稿2024/08/31 04:36

編集2024/09/01 06:17
jimbe

総合スコア13168

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

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

nayoaka

2024/09/01 03:53

プログラミングの確信を教えてくださりありがとうございます。また、具体的な解決例も添えてくださりありがとうございます。何故プログラミング自体始めて数週間で基礎の理解や考え方が足りず申し訳ありませんでした。教えてくださったコード読んで見て調べてみて、少しずつ理解させていただきます。
jimbe

2024/09/01 06:42

責めているつもりはありませんので謝ることはありません。 特に切羽詰まった学生さんとかはとにかく動作させようと弄りまくったりしてしまいがちです。考え続けて手を動かさないのも問題ですが考えず手を動かすだけなのも問題ですし、でもそのバランスは慣れないと分からないもので、結局どうすりゃいいんだとなってしまいますね。学生さんならそういう時こそ講師とかに聞くべきなんですが、(人間関係的に?)聞き辛いとかそもそのような環境が無いとかだと、迷走が長くなるのは仕方ありません。 学習サイトの小さなプログラムの質問に基幹システムだったら等というのは大袈裟過ぎるのは確かですが、 teratail は(一応?)エンジニア対象を謳っていますので、指向を汲み取って頂けたなら幸いです。 回答のコードに関しましては私に説明責任があると思いますので、何か不明な点がありましたらこちらに書いて頂ければ出来るだけ説明致します。
nayoaka

2024/09/02 04:11

ありがとうございます。私の場合少し趣味的に勉強を始めたところがあり、意識が足りなかったのは事実ですので… 質問はgetsとfgetsは違うものだと理解してますが、書き換える場合は、gets(b)を fgets(b,"%s",stdin)とすると同じ動き?働き?になるんでしょうか? Main.c:10:13 : warning: incompatible pointer to integer conversion passing 'char [3] to parameter of type 'int' [-Wint-conversion]が出たようなんですが回答提出していたら出力は間違っていなかったようです。
jimbe

2024/09/02 04:24 編集

>fgets(b,"%s",stdin) fgets は(正確な詳細は実装それぞれですが) char *fgets (char *buff, int buffsize, FILE *stream); です。第二引数が文字列へのポインタ(char*)で数値(int)でないのでおかしいと言われているのではないでしょうか。 fscanf とかとごちゃになっていませんか。 用いる関数のパラメータや戻り値などは検索して確認するようにしたほうが良いです。 google検索: c fgets ( https://www.google.com/search?q=c+fgets ) https://chaste.web.fc2.com/Reference.files/C_Standard.files/fgets.html https://bituse.info/c_func/28
nayoaka

2024/09/02 05:14

確認したらそうでした。覚え間違いや勘違いも気をつけるべきですね。fgets(b,sizeof(b),stdin)が正しそうでした。それで提出したらうまく行きました。ありがとうございます。
jimbe

2024/09/02 09:12

私も最近 paiza をちょこちょこやってますが、常に検索してます^^; 特にパラメータの並び順とかで、どれが入力でどれが出力だっけみたいなのが多いですね。
guest

0

scanfの書式で頑張る方法もあります。

c

1#include <stdio.h> 2int main(void){ 3 char str[101]; 4 int num; 5 6 scanf("%d", &num); 7 8 for(int i=0; i < num; i++){ 9 scanf("%*c%[^,\n]", str); 10 printf("%s\n", str); 11 } 12 return 0; 13}

%*cで1文字読み飛ばし(初回は1行目行末の改行、それ以降はカンマ)、%[^,\n]でカンマ・改行以外からなる文字列を読み込みます。詳細は、Wikipediaのscanfの説明あたりを参照してください。

投稿2024/09/02 21:22

actorbug

総合スコア2388

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

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

0

以下は IEEE Std 1003.1-2024: getdelim, getline - read a delimited record from stream を利用する場合です。

c

1#include <stdio.h> 2#include <stdlib.h> 3 4int main(void) 5{ 6 char *line = NULL; 7 size_t len = 0; 8 ssize_t read; 9 10 getline(&line, &len, stdin); // skip first line 11 free(line); line = NULL; 12 read = getline(&line, &len, stdin); 13 for(int i=0;i<read;i++) 14 if (line[i] == ',') 15 line[i] = '\n'; 16 printf("%s", line); 17 18 free(line); 19 return 0; 20}

投稿2024/09/02 04:58

melian

総合スコア20574

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

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

nayoaka

2024/09/02 07:09

こういう書き方もあるんですね。参考になりました。調べて読み解いてみてみます。
guest

0

「基本的に入ってきたものをそのまま出力するんだけど,カンマがあった場合はそこで改行してね」
…っていう話だと見えるので,とりあえず1文字ずつ愚直に入出力していけばどうでしょうか.

C

1int main(void) 2{ 3 //※入力の1行目は要らないので読み飛ばす 4 while( getchar() != '\n' ){ /* N O P */ } 5 6 //入力2行目:1文字ずつ読み取る 7 while( 1 ) 8 { 9 //1文字読み取って… 10 int c = getchar(); 11 //読み取ったもの次第で処理分け: 12 //・カンマだったら改行出力 13 //・改行コードだったら改行出力して終了 14 //・その他の文字はそのまま出力 15 if( c==',' ){ putchar('\n'); } 16 else if( c=='\n' ){ putchar( '\n' ); break; } 17 else { putchar( c ); } 18 } 19 return 0; 20}

投稿2024/09/02 02:53

編集2024/09/02 02:54
fana

総合スコア11954

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

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

nayoaka

2024/09/02 07:04

なるほど。わかりやすいコメントとコード自体も短く理解しやすかったです。キーボードからの入力ならこれが使える感じですね。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問