ページ 11

教えてください

Posted: 2007年5月03日(木) 17:41
by そら
英単語(最大15文字)を*が現れるまで1つづつ読み込み、読み込んだ英単語の文字数を計算して文字数の度数分布(同一文字数の出現回数)を表示するプログラムを作成せよ。
ただし、文字数を計算するプログラムは文字列を格納する領域の確保は配列を使用し、実行文では配列を使用しないでポインタを使用すること。
という課題が出ているんですが全く分からないので教えてください。

例えば a b c URL * と入力したら
実行結果はこんな感じになります。
文字数  出現回数
1  3
2  0
3  1
4  0
5  0
: :
: :
: :
15 0

Re:教えてください

Posted: 2007年5月03日(木) 22:17
by 管理人
そらさん、こんにちは。

課題っていざやろうとすると難しく感じるものですよね。
しかし、沢山しないといけないことがくっついているから難しく感じているだけで、わけてわけて作っていけば、簡単だったりします。

そらさんがどの程度Cを知っていらっしゃるのかわからないので、先にお聞きしますが、

① 入力を文字列に格納する。
② 格納した配列の中に入っているスペースの文字を数える

この2つは出来ますか?
少しでも出来そうにないと思ったら遠慮なく言ってくださいね。

少しずつ作っていきましょう。
もし出来るなら、上の2つを作ってみてください。

課題1
① 入力を文字列に格納する。
② 格納した配列の中に入っているスペースの文字を数える

このプログラムを作ってください。

作ったら投稿してください。

Re:教えてください

Posted: 2007年5月03日(木) 22:33
by 管理人
時間のあるうちにサキサキ書いておきますので、順番に見て行って下さい。

くれぐれも下には回答がかいてありますので、○○を作ってくださいと言ったら下をすぐ見ずに、自分で作ってみてから、下の回答と照らし合わせて確認してください。

現在上記2つの事をしてほしいといっていますので、それが出来るまでは(またはどうしてもわからない場合以外は)下に進まないで下さい。

それでは下に回答を続けます。

Re:教えてください

Posted: 2007年5月03日(木) 22:39
by 管理人
① 入力を文字列に格納する。

よっしゃ、それならscanfで簡単ジャン!
と思うでしょう。scanfでプログラムを書いてみます。
#include <stdio.h>

int main(){
	char ch[1000];

	scanf("%s",ch);

	printf("-->>> %s\n",ch);

	return 0;
}

実行結果

abciusaop234
-->>> abciusaop234
 
 
これで出来た!
・・・と思うでしょうが、実際に今回必要とする、スペースを含んだ入力をしてみます。
実行結果

when I liked soccer.
-->>> when
 
 
あれ?「when」しか入ってないぞ?と思うでしょう。
そうなんです。
scanfはスペースや改行で区間を区切るため、スペースを含む入力には使用できません。
そこでgetcharを使用してみます。

getchar関数というのは、入力された文字列を1文字ずつ返す関数です。
つまり
「when I liked soccer.」
という文字列を入力すると、
1回目にgetcharを呼ぶと「w」が返って来ます。
2回目にgetcharを呼ぶと「h」が返って来ます。
3回目にgetcharを呼ぶと「e」が返って来ます。
4回目にgetcharを呼ぶと「n」が返って来ます。
ですから、

char n;
n = getchar();

で、nを表示していけば1文字ずつ表示できます。
これを使ってみましょう。

Re:教えてください

Posted: 2007年5月03日(木) 22:43
by 管理人
while( ( ch=getchar() ) != '\n')

これは何をしているかというと、
まず最初にch=getchar()が行われますから、入力された文字列の中から1文字取ってきます。
取ってきた文字が改行で無い限りループします。
iをドンドン進めていけば、入力された文字列が格納できますね。

最後に終端記号を入れましょう。

以下プログラムを見てください。

#include <stdio.h>

int main(){
	int i=0;
	char ch[1000];

	while( ( ch=getchar() ) != '\n')
		i++;
	ch = '\0';

	printf("-->>> %s\n",ch);

	return 0;
}

実行結果

when I liked soccer.
-->>> when I liked soccer.

 
 
ご覧の通り、スペースも含めて格納する事が出来ました。
では次にこのスペースの数をカウントしていきましょう。

Re:教えてください

Posted: 2007年5月03日(木) 22:49
by 管理人
格納する時に一つ一つ文字を確認しているので、
そこでいっぺんにスペースの調査もしてしまいましょう。
numという文字数をカウントする変数を用意し、
スペースが発見されるたびに1カウントアップさせます。

以下のようになります。
#include <stdio.h>

int main(){
	int i=0,num=1;
	char ch[1000];

	while( ( ch=getchar() ) != '\n'){
		if(ch==' ')
			num++;
		i++;
	}
	ch = '\0';


	printf("\n\n");
	printf("%s --> の中に単語は%d個\n",ch,num);

	return 0;
}


実行結果

when I liked soccer.


when I liked soccer. --> の中に単語は4個


別に難しい事はないですね?ここまでで、私から出した2つの課題は終わりです。
次の課題に進みましょう。

Re:教えてください

Posted: 2007年5月03日(木) 22:52
by 管理人
課題2
上記プログラムを利用して、各単語の長さをカウントする機能を追加してください。

Re:教えてください

Posted: 2007年5月03日(木) 23:09
by 管理人
回答です。

今回どうやって数えるかが当然ミソになってきます。
15種類のカウントする変数が必要になってきますね。
変数が多く、同じ型が必要ですから配列で用意しましょう。
カウントするので、なまえをcntとし、
int cnt[16];
として用意します。
なんで15種類なのに16個かというと、[0]を使用するとわかりにくくなるため、[0]は使用しません。
今回は[1]から[15]を使用するので一つ多く宣言しました。
1文字の時は[1]を一つカウントアップ( [1]++; )
2文字の時は[2]を一つカウントアップ( [2]++; )
3文字の時は[3]を一つカウントアップ( [3]++; )

という感じで15文字までいきましょう。
するとcnt配列の各要素は文字数となります。
つまり、文字数をlenとすると
cnt[len]++;
とすればいいわけですね。

各単語の文字数をカウントするには、スペースからスペースまで、または改行までの間の長さを調べてやればいいですね。
ですから
もしスペースなら文字数を表すlenを使ってそれまでの文字数をカウントし、
文字数をカウントするlenを初期化
if(ch==' ' || ch=='\n'){
  cnt[len]++;
  len=0;
}
します。
それ以外のときは、スペース以外ですから、lenを増やせばlenで文字数がカウントできます。
else
  len++;

これらをループで表すと

while(1){
	ch=getchar();
	if(ch==' ' || ch=='\n'){
		cnt[len]++;
		len=0;
	}
	else
		len++;
	if(ch=='\n') 
		break;
	i++;
}
 
 
 
こうなりますね。
では、これを通してみてみます。

#include <stdio.h>

int main(){
	int i=0,cnt[16]={},len=0;
	char ch[1000];

	while(1){
		ch=getchar();
		if(ch==' ' || ch=='\n'){
			cnt[len]++;
			len=0;
		}
		else
			len++;

		if(ch=='\n') 
			break;
		i++;
	}
	ch[i] = '\0';

	printf("\n\n");

	for(i=1;i<=15;i++)
		printf("%d文字 -> %d個\n", i, cnt[i]);

	return 0;
}

実行結果

1文字 -> 1個
2文字 -> 0個
3文字 -> 0個
4文字 -> 1個
5文字 -> 1個
6文字 -> 0個
7文字 -> 1個
8文字 -> 0個
9文字 -> 0個
10文字 -> 0個
11文字 -> 0個
12文字 -> 0個
13文字 -> 0個
14文字 -> 0個
15文字 -> 0個
 
 
 
これで各文字数がカウントできました。では次の課題へ参りましょう。

Re:教えてください

Posted: 2007年5月03日(木) 23:23
by 管理人
今度の課題は今までとは直接関係有りません。
さっぱり忘れてしまってOKです。

今、
int a[5];
と宣言したとします。
配列の領域は連続して確保されるので、[0]のアドレス+1が[1]になり、[1]のアドレス+2が[2]となっていきます。
(実際には4バイト置きにアドレスが確保されているんですが、ポインタを使うとそれを意識しなくていいので、省略します)

ちょっとポインタについておさらいしておきましょう。
ポインタとは、変数のアドレスをいれる変数です。
変数のアドレスをいれる専用の箱ということです。
今、
int *p;
と宣言すると
pには何かのアドレスを入れることになります。

今aを宣言し、aのアドレスをいれて表示してみましょう。
#include <stdio.h>

void main(){
	int *p,a=1;
	printf("%d\n",a);
	p=&a;
	printf("%d\n",*p);
}

実行結果
1
1
 
 
意味がわかりますか?
では、その配列バージョンを見てみましょう。
#include <stdio.h>

void main(){
	int *p,a[3]={1,2,3};
	printf("%d %d %d\n",a[0],a[1],a[2]);
	p=a;
	printf("%d %d %d\n",*p,*(p+1),*(p+2));
}

実行結果

1 2 3
1 2 3
 
 
 
わかりますか?
a[1]はa[0]のアドレス+1だからこのように表せるわけです。

では課題です。




課題3
int a[10]={0,1,2,3,4,5,6,7,8,9};としてaを宣言し、この配列を扱うためのポインタを用意し、ポインタを使ってa[8]の内容を表示してください。

Re:教えてください

Posted: 2007年5月03日(木) 23:26
by 管理人
私がお教えするのはとりあえずここまでです。
先ほどまでは「わからなければ下をみたらいいや」と思って気軽に見てしまったかもしれませんが(見ずに一生懸命やってたらすみません)、今度は答えを書かないのでご自分で考えてみてください。
今までの事をしっかり理解すれば必ず出来ます。

もし出来上がったら思うでしょう。
最初 こんなのできない! と思っていた課題でも少しずつやってみることで自分の力でも出来るという事を。

なんでもそうですが、諦めてしまったらそこまでなので、課題が難しければ機能を分割して、少しずつ作ってみる事で案外簡単になるものですから諦めず頑張ってください。

わからないことがあれば聞いてくださいね。

Re:教えてください

Posted: 2007年5月08日(火) 00:34
by 管理人
そらさんは、この質問に対して解決なさったんでしょうか?