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

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

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

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

Null

Nullとは、プログラミング言語やデータベースにおけるデータ表現の一種です。コンテキストによって"空"もしくは"長さ0の文字列"、”未知・不明”を意味します。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

2回答

5458閲覧

c言語の空白を含む文字列に含まれる単語をある配列にコピーし、それを単語長とともに出力する問題

macuserdesu

総合スコア8

C

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

Null

Nullとは、プログラミング言語やデータベースにおけるデータ表現の一種です。コンテキストによって"空"もしくは"長さ0の文字列"、”未知・不明”を意味します。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2020/06/16 15:43

「c言語の空白を含む文字列に含まれる単語をある配列にコピーし、それを単語長とともに出力する」問題が学校の課題として課されたのですが、出題者の言葉足らずなのか自分の読解力・理解力不足なのか問題の意図(やらせようとしていること、またはどこがポイントなのか)が理解できない上、コードの正解がわからないという質問です。

問題は下の画像です。ちなみにこの問題では今は危険性ゆえに使用されていないgets関数を使うという条件でした。
イメージ説明

そして、問題文で触れられている基礎課題2の問題が下の画像です。
イメージ説明

この基礎課題2は自力で解けました。以下のコードです。

c

1#include<stdio.h> 2int str_copy(char a[],char b[]); 3 4int main() 5{ 6 char a[128]; 7 char b[128]; 8 9 printf("Input : "); 10 scanf("%s",b); 11 12 printf(" ( %d )\n",str_copy(a,b)); 13} 14 15int str_copy(char a[],char b[]) 16{ 17 int i=0,len=0; 18 19 while(b[i]!='\0') 20 { 21 a[i]=b[i]; 22 i++; 23 len++; 24 } 25 a[i]='\0'; 26 printf("Output : %s",a); 27 return len; 28}

そして、自力で基礎課題3を解こうとして書いたコードが以下です。上記の通り全く意図が汲み取れずにめちゃくちゃなコードになった上にコンパイル結果も当然回答には程遠いものとなりました。

c

1#include<stdio.h> 2int str_copy(char a[],char b[]); 3 4int main() 5{ 6 char a[128]; 7 char b[128]; 8 char c[128]; 9 10 printf("Input : "); 11 gets(b); 12 13 printf(" ( %d ) ",str_copy(a,b)); 14 while(str_copy(a,c)!=0){ 15 printf(" ( %d ) ",str_copy(a,c)); 16 } 17 printf("\n"); 18 19 20 21} 22 23int str_copy(char a[],char b[]) 24{ 25 int i=0,len=0; 26 static char *p; 27 static int flag=0; 28 29 while(flag==0){ 30 if(b[i]!=' '){ 31 a[i]=b[i]; 32 len++; 33 } 34 35 if(b[i+1]==' ' && b[i]!=' '){ 36 len++; 37 flag++; 38 i++; 39 p=&b[i]; 40 while(*p == ' '){ 41 p++; 42 } 43 printf("Output : %s",a); 44 break; 45 } 46 47 i++; 48 } 49 50 51 if(*p=='\0'){ 52 return 0; 53 } 54 55 if(b[0]=='\0'){ 56 while(*p != ' ' || *p!='\0'){ 57 a[i] = *p; 58 p++; 59 i++; 60 len++; 61 } 62 printf("%s",a); 63 64 while(*p == ' '){ 65 p++; 66 } 67 } 68 69 return len; 70}

この問題には正解のコンパイル結果の例があったのですが、実行ファイル名をex01と仮定すると、(△は空白です)

ex01
Input: △ △ △ abcd △ △ △ efg △ △ △ hi

Output: abcd ( 4 ) efg( 8 ) hi ( 2 )

というものです。

この問題の特にわからない点は、
・なぜ2回目以降の第2引数をNULLで固定して呼び出すのか
・戻り値が0なら終了としているのはなぜか

またこの問題が自分が分からない要因として、gets関数が空白をどういう値で配列に格納しているのかが調べてもわからない(調べたがscanfとの空白で終了するかしないかの違いにしか触れられていなかった)というのもあります。

この問題の意図またそれを実現するコードがわかる方がいましたら教えてくれる助かります。

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

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

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

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

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

Daregada

2020/06/16 16:15

1. 「関数 word_copy を作れ」と指定されているにもかかわらず、関数 str_copy を作るというのは「できました」と言えるのか。指定した条件に合致していないと判定されてもしょうがない。
Daregada

2020/06/16 16:19

2.「危険なgetsを使えという条件」と揶揄しているわりに、同じ危険がある scanf で文字列入力をしているのはいいのか。配列の大きさを超えて入力できてしまう点は scanf も同じだろう。そういうことは、 fgets を使うなり get_s を使うなりしてから言ってくれ。 それから、getsを使えという条件は、おそらく「word_copy の中で先頭の空白を読み飛ばす処理を自前で書け」という意図だが、(空白を読み飛ばす)scanf で代用していることで、問題3への繋がりがなくなっている。問題3があなたにとって難題になっているのは、そこも関係している。
Daregada

2020/06/16 16:31

3. 「なぜ2回目以降の第2引数をNULLで固定して呼び出すのか」 長い文字列を継続処理することと、新たに別の文字列を処理することを、(引数は2つのままで)両立させるため。継続処理を、新たな文字列を指定した場合と区別する方法として、(引数を増やすのではなく)「何も指していないことが保証されている」ヌルポインターを使っている。
Daregada

2020/06/16 16:34

4.「戻り値が0なら終了としているのはなぜか」 関数 word_copy が「戻り値はコピーした文字数」という仕様なので、「これ以上単語が見つからない」状態では、 word_copy の戻り値は当然 0 になるはずだから。
Daregada

2020/06/16 16:36

5. 「gets関数が空白をどういう値で配列に格納しているのか」 当たりまえすぎて書いてないのだが、gets は空白を特別扱いしないので、配列にはそのまま空白 ' ' が格納されている。
Daregada

2020/06/16 16:39 編集

まとめると、「画像で提示された問題文を読む限り必要な情報は提供されており、言葉足らずではない。」 課題を解くのはご自分でやってください。課題だから。
macuserdesu

2020/06/16 22:05

丁寧に返信していただきありがとうございました! 関数名シンプルに間違えてました。 他の方の回答も見て、3、4を読んで問題の意図はよくわかりました! とても参考になりましたありがとうございました。
guest

回答2

0

またこの問題が自分が分からない要因として、gets関数が空白をどういう値で配列に格納しているのかが調べてもわからない(調べたがscanfとの空白で終了するかしないかの違いにしか触れられていなかった)というのもあります。

scanfは入力文字列前後の空白を読み飛ばすので、空白を適切に処理させるという課題の趣旨に合わないのでgets関数を使わせているのでしょう。
getsは改行まで空白もそのまま引数の変数へ格納します。
abcd efg hiをscanfしたらabcdしか入って来ません。getsならそのまま入ってきます。

質問者の書いた基礎課題2のコードについて

  • そもそも実装すべき関数の名前が間違っている
  • 先頭の空白が読み飛ばされない
  • 単語の区切りの空白も検知できていない

ということで課題の要件を全然満たしていません。
できてると勘違いしたのはInputにscanfを使ってしまったからです。
まずは基礎課題2をもう一度考え直しましょう。

また、Output:の単語の標準出力はこの関数ではなくmain側で行うべきです。正しくa側に文字列がコピーできたことを示すためにも。

投稿2020/06/16 16:31

hope_mucci

総合スコア4447

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

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

0

ベストアンサー

なぜ2回目以降の第2引数をNULLで固定して呼び出すのか

  • NULLの時は、前に渡された文字列をそのまま利用して、前の文字列の中の次の単語を取り出す
  • 文字列を渡したときは、前の文字列は捨てて、新しく始める

ということでしょう。

例えばb"abc de fghi"が入っているとして、

C

1str_copy(a, b); // 戻り値 3, aには"abc" 2str_copy(a, NULL); // 戻り値 2, aには"de" 3str_copy(a, NULL); // 戻り値 4, aには"fghi" 4str_copy(a, NULL); // 戻り値 0, aには"" 5

戻り値が0なら終了としているのはなぜか

戻り値が0とは単語の長さが0、つまり、もう文字列の中に単語がないということです。もう単語がないのに続けても、また0が返ってくるだけです。

投稿2020/06/16 16:14

Bearded-Ockham

総合スコア430

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

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

macuserdesu

2020/06/16 22:05

返信ありがとうございました! 問題の意図は理解できました。 参考になりましたありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問