ページ 11

プログラミング言語C 第2版(K&R) 演習1-22について

Posted: 2015年8月09日(日) 21:39
by cookierinon
C言語初心者です。プログラミング言語C 第2版(K&R)の内容について質問させていただきます。環境はVisual Studio 2010です。

演習1-22 長い入力行を、入力のn字文字目までにある最後の非ブランク文字の後で、”折りたたむ”プログラムを書け。プログラムは、行が非常に長くても、また指定桁までにブランクもタブもない場合についても、ちゃんと動作するようにせよ。
において、
例えばabcd ~ xyz\nEOFとアルファベットを全て入力すると、
abcdefghijklmnopqrs-
tu
までしか出力されません。
34行目のif文が1度までは正しく実行されるのですが以降おかしい。
50行目以降の記述が怪しいのですが何がおかしいかまではわかりません。
誤っている箇所と訂正内容のご指摘願えないでしょうか?

コード:

/* n(今回は20)文字までにある空白以外の文字の後で折りたたむ */
/* ※行が非常に長い or n文字までに空白が1つもなくても動作するよう */
/* ※タブは長さがわからないので無視する */

#include <stdio.h>
#define MAXLINE 1000
#define MAXLENGTH 21	/* 21文字までに必ず改行*/

int main(void){
	int c, i;
	int colspace;	/* 空白が入力される度に空白の文字位置を格納 */
	int len;
	char buf[MAXLINE];
	char word[MAXLINE];
	len = 0;
	colspace = -1;

	printf("文章を入力してください。\n");
	printf("1行の長さが%d文字以上にはなりません。\n", MAXLENGTH-1);
	
	for(i=0; ; i++){
		c = getchar();
		if(c == ' '){
			colspace = i;
			buf[i] = c;
		}
		else if(c == '\t'){
			--i;
			continue;
		}
		else
			buf[i] = c;

		if(i == MAXLENGTH -1 || c == '\n'){	/* このif文に入るまで入力を繰り返す */
			if(c == '\n')	/* 21文字までに改行の入力がある */
				buf[i+1] = '\0';
			else if(0 <= colspace && colspace < MAXLENGTH){	/* 21文字までに空白があり、改行の入力がない */
				buf[colspace] = '\n';
				buf[MAXLENGTH+1] = '\0';
			}
			else if(colspace == -1){	/* 21文字までに一度も空白がなく、改行の入力がない */
				buf[i+2] = buf[i];
				buf[i+1] = buf[i-1];
				buf[i] = '\n';
				buf[i-1] = '-';

				buf[i+3] = '\0';
			}
		
			for(i=0; buf[i] != '\0'; i++)
				word[i + len] = buf[i];
			if(MAXLINE < i+len){
				printf("文章が長すぎます。%f文字以上は入力しないでください。\n", MAXLINE+1);
				return 1;
			}
			len += i;
			colspace = -1;
			for(i=0; buf[i] != '\0'; i++)
				buf[i] = '\0';
			i = 0;
		}
		if(c == EOF){
			word[len] = '\0';
			break;
		}
	}

	printf("12345678901234567890\n");
	printf("%s", word);
	return 0;
}

Re: プログラミング言語C 第2版(K&R) 演習1-22について

Posted: 2015年8月09日(日) 21:52
by みけCAT
  • 19行目:メッセージと動作が合っていません。MAXLENGTH-1ではなくMAXLENGTHとするべきでしょう。
  • 53行目:データと書式指定文字列が合っていません。%fではなく%dとするべきでしょう。
  • 60行目:i++の影響が考慮されていません。i = 0;ではなくi = -1;とするべきでしょう。
詳しく見てはいないですが、とりあえずこれらを修正したら入力「abcd ~ xyz\nEOF」に対する動作が改善しました。

Re: プログラミング言語C 第2版(K&R) 演習1-22について

Posted: 2015年8月09日(日) 22:01
by みけCAT
次の行を出力した時でも気にせずMAXLENGTH-1文字出力してしまうので、入力

コード:

abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
に対する出力がおかしいです。
次の行に行った文字列の長さを管理し、MAXLENGTHからその長さを引いた値を次の行でのMAXLENGTHとみなすといいでしょう。

Re: プログラミング言語C 第2版(K&R) 演習1-22について

Posted: 2015年8月09日(日) 23:09
by cookierinon
みけCATさん、回答ありがとうございます。
みけCAT さんが書きました:
  • 60行目:i++の影響が考慮されていません。i = 0;ではなくi = -1;とするべきでしょう。
前の質問に引き続き同じ誤りを…情けない限りです。

修正コードです。ご指摘くださった内容から変数nextwordを追加、42行目MAXLENGTH+1をMAXLENGTHに修正。
テストでは正常に機能したのを確認しましたが、念のためご確認お願いします。

コード:

/* n(今回は20)文字までにある空白以外の文字の後で折りたたむ */
/* ※行が非常に長い or n文字までに空白が1つもなくても動作するよう */
/* ※タブは長さがわからないので無視する */

#include <stdio.h>
#define MAXLINE 1000
#define MAXLENGTH 21	/* 21文字までに必ず改行*/

int main(void){
	int c, i;
	int colspace;	/* 空白が入力される度に空白の文字位置を格納 */
	int len;
	int nextword;	/* 現在の行から次の行に移される文字の文字数 */
	char buf[MAXLINE];
	char word[MAXLINE];
	len = 0;
	colspace = -1;
	nextword = 0;

	printf("文章を入力してください。\n");
	printf("1行の長さが%d文字以上にはなりません。\n", MAXLENGTH);
	
	for(i=0; ; i++){
		c = getchar();
		if(c == ' '){
			colspace = i;
			buf[i] = c;
		}
		else if(c == '\t'){
			--i;
			continue;
		}
		else
			buf[i] = c;

		if(i == (MAXLENGTH -1) - nextword || c == '\n'){	/* このif文に入るまで入力を繰り返す */
			nextword = 0;
			if(c == '\n')	/* 21文字までに改行の入力がある */
				buf[i+1] = '\0';
			else if(0 <= colspace && colspace < MAXLENGTH){	/* 21文字までに空白があり、改行の入力がない */
				buf[colspace] = '\n';
				buf[MAXLENGTH] = '\0';
				nextword = i - colspace;
			}
			else if(colspace == -1){	/* 21文字までに一度も空白がなく、改行の入力がない */
				buf[i+2] = buf[i];
				buf[i+1] = buf[i-1];
				buf[i] = '\n';
				buf[i-1] = '-';
				buf[i+3] = '\0';
				nextword = 2;
			}
		
			for(i=0; buf[i] != '\0'; i++)
				word[i + len] = buf[i];
			if(MAXLINE < i+len){
				printf("文章が長すぎます。%d文字以上は入力しないでください。\n", MAXLINE+1);
				return 1;
			}
			len += i;
			colspace = -1;
			for(i=0; buf[i] != '\0'; i++)
				buf[i] = '\0';
			i = -1;
		}
		if(c == EOF){
			word[len] = '\0';
			break;
		}
	}

	printf("12345678901234567890\n");
	printf("%s", word);
	return 0;
}

Re: プログラミング言語C 第2版(K&R) 演習1-22について

Posted: 2015年8月09日(日) 23:21
by みけCAT
56行目からのエラーチェックが甘そうです。

コード:

			for(i=0; buf[i] != '\0'; i++)
				word[i + len] = buf[i];
			if(MAXLINE < i+len){
				printf("文章が長すぎます。%d文字以上は入力しないでください。\n", MAXLINE+1);
				return 1;

コード:

			for(i=0; buf[i] != '\0'; i++){
				if(MAXLINE - 1 <= i+len){
					printf("文章が長すぎます。%d文字以上は入力しないでください。\n", MAXLINE);
					return 1;
				}
				word[i + len] = buf[i];
			}
とするほうがいいと思います。

Re: プログラミング言語C 第2版(K&R) 演習1-22について

Posted: 2015年8月09日(日) 23:22
by みけCAT
また、入力の最後に改行が無い場合、最後に出力するべき内容が出力されないことがある不都合がありますね。

Re: プログラミング言語C 第2版(K&R) 演習1-22について

Posted: 2015年8月10日(月) 00:23
by cookierinon
みけCATさん、回答ありがとうございます。
if(MAXLINE - 1 <= i+len)
とするのはi+lenが0である場合を考慮するからですね。
みけCAT さんが書きました:また、入力の最後に改行が無い場合、最後に出力するべき内容が出力されないことがある不都合がありますね。
36行目を修正

コード:

        if(i == (MAXLENGTH -1) - nextword || c == '\n' || c == EOF){
40行目から以下を挿入

コード:

else if(c == EOF)    /* 21文字目までの途中でEOFが入力され、改行の入力がない */
    buf[i] = '\0';
でしょうか?

Re: プログラミング言語C 第2版(K&R) 演習1-22について

Posted: 2015年8月11日(火) 21:15
by みけCAT
大丈夫そうだと思います。
返信が遅くなって申し訳ありません。

Re: プログラミング言語C 第2版(K&R) 演習1-22について

Posted: 2015年8月12日(水) 02:56
by cookierinon
みけCATさん、回答ありがとうございます。

いくらでも待てますので、次の質問の機会があればよろしければ回答いただけると助かります。