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

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

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

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

Q&A

解決済

3回答

3042閲覧

K&R演習 解説おねがいします!

senbe

総合スコア27

C

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

0グッド

1クリップ

投稿2015/02/27 23:35

編集2015/02/28 03:52

****プログラミング初心者です。
プログラミング言語C(K&R)の演習1-18の解答例を見たのですが、わからないです。
http://www.c-program-example.com/2011/11/k-r-c-exercise-1-18.html)
関数 get_line と char_remove のしくみを教えて頂けるとありがたいです!

特に
関数 char_remove で配列の中の文字が
’\n’ ' ' '\t'
のときにどうして、i の値をを +1 にしたり、-1
するのかがよくわかりません。

プログラミング言語C(K&R) P38第一章 演習1-18
「各入力行から、行の後のタブやブランクを取り除き、かつ空白行はすべて削除するようなプログラムを書け。」

...c

#include <stdio.h>
#define MAXLINE 1000 /* 入力行の最大長*/

int get_lines(char line[], int maxline); /* 関数 get_lines の宣言 /
int char_remove(char str[]); /
関数 char_removeの宣言 */

main()
{
char line[MAXLINE];/* current input line
: 現在の入力行*/

while((get_lines(line,MAXLINE)) > 0) if (char_remove(line) > 0) printf("%s",line); return 0;

}
/*
remove: trailing blanks and tabs from character string str
文字列から ついていく? タブや空白
*/

int char_remove(char str[])
{
int i = 0; /* i の初期値は 0*/
while (str[i] != '\n') /* 文字が '\n'以外なら*/
++i;/i = i + 1/

--i; /* 文字が'\n'なら、i = i -1*/ while (i >= 0 && (str[i] == ' '|| str[i] == '\t'))/*i が0以上 かつ 文字が空白 あるいは タブなら*/ --i;/* i = i -1*/ if (i >= 0)/*i が0以上なら(文字は空白あるいはタブではない)*/ { ++i;/*i = i + 1*/ str[i] = '\n';/* str[i] に '\n' を代入*/ ++i; str[i] = '\0';/* str[i]に'\0'を代入*/ } return i;/*i の値を返す*/

}
/* getline: read a line into str, return length /
/
str に行を入れて、長さを返す */
int get_lines(char str[], int line)
{
int c,i,j;

for (i = 0, j = 0; (c = getchar()) != EOF && c != '\n'; ++i) /*i ,jの初期値は0.とってきた文字がファイルの終わりではない かつ '\n'でなければ*/ { if (i < line - 1) /*i が 999よりも小さければ */ { str[j++] = c;/*str[j = j +1] に c を代入*/ } } if (c == '\n') /*とってきた文字が '\n'なら*/ { if (i <= line -1) /*iが998以下なら*/ { str[j++] = c; } ++i; } str[j] = '\0';/*str[j]に'\0'を代入*/ return i;/*iの値を返す */

}

コマンドプロンプトで

a.exe < hello.c

と実行すると

#include <stdio.h>
main()
{
printf("hello,");
printf("world");
printf("\n");
}

でした。

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

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

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

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

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

guest

回答3

0

ベストアンサー

仕組みと言われても何をどう解説すれば良いのかわかりません、
まず、わかる行はコメントで自分で解説を入れていくとよいです、
※ int i = 0; の意味くらいはわかりますよね?
その結果、どこの行がわからないのかがわかるはずです。

投稿2015/02/28 01:34

bigfatrat

総合スコア187

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

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

senbe

2015/02/28 03:53

ご指摘ありがとうございます! コメントをいれてみました。
bigfatrat

2015/02/28 05:10

追記お疲れ様です。 \nや\tの意味は理解済みでしょうか? \nは改行を意味します、その他の物は置いといて まずは改行について解説します。 >各入力行から、行の後 とあるように、行の一番後ろを調べる必要があります。 行の一番後ろに必ずあるもの、それは改行です(EOFなら無いですが一旦無視します) 下記の文字列をみてください。 abcdfe\n 0文字目がa,1文字目がbと続いて6文字目が\n、つまり改行です。 abcdfe\nをメモ帳等で入力すると実際は下記のようになります。 abcdfe つまり、行の一番後ろはeなのです。 eの場所を探すにはどうすれば良いか? 文字数はわかりません、最後の文字がなにかももちろんわかりません。 ですが、\n(改行コード)の1個前あると言う事だけはわかります。 なので下記処理で\n(改行コード)を探す必要があるわけです。 while (str[i] != '\n') /* 文字が '\n'以外なら*/ ++i;/*i = i + 1*/ 改行コードの位置が知りたいわけでは無く、 最後の文字が知りたいので、カウンタを-1してあげます。 ここまでは理解できましたか?
bigfatrat

2015/02/28 05:12

>つまり、行の一番後ろはeなのです。 ちょっと間違えました、 行の一番後ろにある入力文字はe、と言う方が正しいですね。
senbe

2015/02/28 06:13

よくわかりました! 次のwhile文で「 i >= 0 」という条件があるのは 最初に入力された文字が改行コードなら(空白行の場合) i = -1 になっているから そして 最後の文字が空白かタブなら、 カウンタを-1する。  ということですか?
bigfatrat

2015/02/28 07:24

>最後の文字が空白かタブなら、カウンタを-1する。 その通りです、 空白かタブ以外になるまでマイナス1するので、 whileを抜けるときは空白かタブの1個までになっているはずです。 空白が無い場合は改行コードの1個前です。 最後の空白かタブは削除したいので、 改行コード・空白・タブのいずれかの1個前の状態になっているはずのカウンタを 1足すことによって、改行コード・空白・タブのいずれかを全て改行コードに置き換えます。
senbe

2015/02/28 20:31

解説ありがとうございます! とてもわかりやすかったです。 最後に、上の質問とは関係ないですが、プログラミングが上手くできるようになるには どうすればいいですか?
guest

0

senbeさんの性格によります。

もしsenbeさんが私と同じでめんどくさがりで勉強が嫌いで、
でもプログラミングが好きなのであれば同じ方法が使えると思います。

  1. 目標を決める

目標と言っても「~~ができるようになる」ではなく「~~を作りたい」と定めます、
「C言語が使えるようになる」が目標だと、何処までやればよいのかわからなくなります。

  1. 最初は寄り道しない

「C言語だけやってて大丈夫だろうか、javaとかやらなくて良いのだろうか」となるかもしれません、
そんなことはC言語を使いこなせるようになってから考えれば良いです、
基礎ができれば他の言語は応用です。

  1. 面倒くさがる

「もっと楽に作業ができないだろうか、むしろ作業しなくて済む方法は無いだろうか」
とか「残業なんて嫌だ早く帰りたい、会議なんて嫌いだ、すぐ終わればよいのに」
と言うようなことを常に考える、そして面倒くさくない方法を考える。

地道にやれば10時間かかる作業を、15時間かけてツールを作って10時間で終らせる。
最初はそんな感じでも良いのでずっと続けてるとそのうち技術が身についてきます。

投稿2015/03/01 02:34

bigfatrat

総合スコア187

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

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

senbe

2015/03/02 09:27

ありがとうございます。 私は「技術者はプログラミングできないとだめだから…」 と、はっきりした目標をもって勉強はしていませんでした。 これからはⅭ言語を使って、めんどくさくないようにツールを作って いっぱい自分の遊べる時間をつくっていきたいです!
guest

0

senbeさん、そのプログラムは、そもそも
「各入力行から、行の後のタブやブランクを取り除き、かつ空白行はすべて削除する」
という動作をしていますか?それをきちんと確認されましたか?

「コマンドプロンプトで >a.exe < hello.c と実行すると…」とありますが、これだけではまともに動作しているのかどうかを(少なくともこちらでは)判断できません。
簡単に判別できるのは空白行が削除されたかどうかです。hello.c に空白行があって、その出力ならまだ望みはありますが、最初からhello.cに空白行が無いのではテストになりません。もっと言えば、hello.c の中に、行の後ろに空白やタブがある行があって

a.exe < hello.c > temp.txt

とした後、エディタで temp.txt を開き、行の後ろの空白やタブが削除されているかどうかを確認する必要があります。コマンドラインの結果を見せていただいただけでは、行の後ろの空白が無くなっているかどうかを判別できないのです。

何でこんな事を書いているかと言うと、私の手元(Cygwin、gcc)では空白行も行の最後の空白も削除されなかったからです(原因はすぐわかったので手元ではバグを取った)。「a.exe」でテストしたのなら私と似たような環境だと思われますので十分疑わしいのです。
ちゃんと動いているかどうかを確認していないのに、仕組みも何も無いのではありませんか?

しかも「解答例」として示されているURLを見て、またびっくり。なんとコンパイルさえ通らないプログラムじゃありませんか笑。つまり、senbeさんはコンパイルが通るように書き変えたのですね?立派立派w
ついでに、get_lines() は読み込んだ行の長さを返しているのだから、その値を利用するようにchar_remove()関数を修正すれば、中の処理を簡単にできる(その分無駄が無くなる)のに、とも思いました。

投稿2015/03/03 11:11

編集2015/03/03 12:31
rubato6809

総合スコア1380

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問