080218


※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

080218

春です。本日は genshiken wiki にごアクセスいただき…

平均単語長

小数点第一位までの平均単語長を返す関数を書いてください。
例えば以下の文章の場合は、
this is a pen.
(4 + 2 + 1 + 3) / 4 で 2.5 文字になります。
単語末の「,.」は単語に含まれません。気をつけてください。
(数字や「!?」はとりあえずいいです。)
余裕がある人は標準入力から渡された文章の平均単語長を出力するコードを書いてみてください。

入力例

this is a pen.
sleeping beauty.
Answer to Life, the Universe, and Everything.

出力例

2.5
7.0
5.1

提出

niha28(atmark)gmail.com

ヒント

  • 文字列処理は文字列処理のための関数を使おう。
  • 「小数点第一位までの」平均単語長を返す関数、です。わざと意地悪にしてあります。

解答例

何か曜日感覚が若干ずれてて遅れました。
#include <string.h>
#include <stdlib.h>

double average_word_length(char *str){
  int all, words;
  char *ptr, *temp;
  all = words = 0;
  ptr = (char*)malloc(strlen(str) + 1); /* 1 */
  strcpy(ptr, str); /* 2 */
  temp = ptr;
  while (temp = strtok(temp, " ,.")){ /* 3 */
    all += strlen(temp);
    words++;
    temp = NULL;
  }
  free(ptr); /* 4 */
  return (all * 10 / words) / 10.0; /* 5 */
}

解説

今回は色々と出題に失敗しました。皆力技で実装しようとしてしまっていて、意図としては strsep や strtok を使って欲しかったんですが…
ちなみに力技の実装ですが全員間違っていました。残念。そちらの解説は省きます。
この関数が何をしているか説明すると、
  1. 渡された文字列を入れられるだけのメモリを確保する。 /* 1 */
  2. 確保したメモリに文字列を複製する。/* 2 */
  3. 文字列をトークンに区切って処理する。/* 3 */
  4. 確保したメモリを開放する /* 4 */
  5. 少数以下第一位だけを残して返す /* 5 */
となっています。
今回の課題の一番重要な部分は、文字列をトークンに切り分ける処理なわけですが、ヒントにもあるように標準関数にはそういった関数が用意されています。 strsep 、 strtok などがこれにあたります。今回は strtok を利用しましょう。
関数の詳しい詳細は man strtok してください。 -> http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strtok.3.html
strtok を利用する上で注意すべき点は、渡す文字列は const ではいけないということです。
const な文字列(文字列リテラルとか)が渡されても動くようにするには、渡された文字列を毎回 const ではないメモリ領域にコピーする必要があります。そのために1、2、4番目の各処理が存在するわけです。
少数第一位だけを残すには、総文字数を一度10倍した上で、10.0(少数型)で割ればできます。

strtok 説明

strtok は、文字列をトークンに切り分ける関数です。
初回の呼び出しでは第一引数には対象の文字列を取り、第二引数には切り分ける文字の配列(つまり文字列)を指定します。
二回目以降は第一引数には NULL を取ります。
返り値は次のトークンがあればトークンへのポインタを、なければNULLを返します。
char str[10];
strcpy(str, "hoge hage");
token = strtok(str, " "); /* 初回の呼び出しは str を指定 */
printf("%s\n", token); /* token には "hoge" が入っている */
token = strtok(NULL, " "); /* 以降は NULL を */
printf("%s\n", token); /* token には "hage" が入っている */

教訓

文字列の操作には文字列の操作のための関数をできるだけ使いましょう。
標準関数にない処理や、あるけれど問題のある関数などもあるので、そういった場合は自分で書きましょう。

補足

質問などあったらここより下に質問内容と名前を書いといてくれたら答えます。編集はページ最上部のメニューより。