AIと戦って、あなたの人生のリスク診断 >>

入力用ファイルの情報を読み込み,このファイルの情報をランレングス符号化を用いて符号化し,結果を出力用ファイル名に出力するCプログラムを作成しようとしているのですが正確に符号化することができません(情報の個数が正しくカウントできない)どうすればよいのかわからないので教えていただけないでしょうか。
#include <stdio.h>
main(void){
FILE *fi;
FILE *fo;
int ccs;
unsigned char c=1;
char a,b,d;
fi=fopen("files99.txt","rb");
fo=fopen("files100.dat","wb");

fread(&a,sizeof(a),1,fi);
ccs=fread(&d,sizeof(d),1,fi);

while(ccs>0){
fread(&b,sizeof(b),1,fi);
if(a==b){
c=c+1;
} else {
fwrite(&a,sizeof(a),1,fo);
fwrite(&c,sizeof(c),1,fo);

a=b;
c=1;
}
ccs=fread(&d,sizeof(d),1,fi);
}

これでは入力用ファイルをfiles99.txtとし
出力用ファイルをfiles100.datとしています。
どこを改善すればよいのか手持ちの資料や学校の図書館を全て調べてもわかりませんでした。
どうかよろしくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (3件)

★アドバイス


・最初『ccs=fread(&d,sizeof(d),1,fi);』を読み込んでいるが、
 a=d が同じか、違うかをチェックしていない。
・ループ中で
 『fread(&b,sizeof(b),1,fi);』を読み込んだ後に、また
 『fread(&d,sizeof(d),1,fi);』を読み込んでいる。
 ここでもb=dが同じか、違うのかをチェックしていない。
 よって正しく符号化が出来ないのです。
・直すとしたら次のステップになります。
 (1)最初に1文字(a)を読み込む
 (2)do-while でループを構成
 (3)『fread(&b,sizeof(b),1,fi);』を削除
 (4)if(a==b){ … }の処理を記述
 (5)do-while の直前で次の1文字(b)を読み込む
 (6)do-while の条件式で fread の戻り値が 0 なら終了
 とします。
・でも1文字取得する場合は fgetc を使えば分かりやすくなりますよ。
 fgetc ならばファイルの終わりは EOF が返されます。
 あと c カウンタは unsigned char 型ですので同じ文字が 256 以上の場合は
 c カウンタが 0 にリセットされます。ここの部分を考慮して改良してください。
 前回のサンプルにある『else if ( n >= 255 ){』でもファイルに書き出しています。
 c カウンタが 255 になったら文字コード、連続する数をファイルに書き出しましょう。
・以上。まずは fread から fgetc に書き直してみる。この方が分かりやすいと思うよ。
    • good
    • 0

※訂正。


>(3)どうして ccs の値でループして処理をしているのですか?
> files99.txt ファイルにNULコードが含まれているの?
> ここがおかしい気がします。
 ↑
 freadの戻り値ならおかしくないね。
・失礼しました。

この回答への補足

ccsのループはfreadの返り値が0のときになれば最後まで読み込んだことになるので終了するという意味です。

プログラムを最後まで書き込んでいませんでした。

fclose(fo);
fclose(fi);

return 0;
}
が続きますすみませんでした。
情報の個数をカウントするにはどこを改善すればよいでしょうか?

補足日時:2007/11/15 09:57
    • good
    • 0

★アドバイス


 (1)念のために fopen の戻り値をチェックして下さい。
 (2)fread よりも fgetc で1文字読み込むほうが分かりやすい気がします。
 (3)どうして ccs の値でループして処理をしているのですか?
  files99.txt ファイルにNULコードが含まれているの?
  ここがおかしい気がします。
>どこを改善すればよいのか手持ちの資料や学校の図書館を全て調べてもわかりませんでした。
 ↑
 手持ちの資料がない。
 学校の図書館でも分からない。
 それならネットで検索をして下さい。
 見つかりますよ。
 例えば
 http://ja.wikipedia.org/wiki/%E9%80%A3%E9%95%B7% …→『連長圧縮』
 などを参考にして下さい。
 これは『ランレングス圧縮』の基本です。

サンプル:
int n = 1; // ランレングス(文字カウンタ)
int b; // 1つ前の文字コード
int c; // 今現在の文字コード

for ( b = -1 ; (c = fgetc(fi)) != EOF ; b = c ){
 if ( c != b ){
  if ( b != -1 ){
   fputc( b, fo );
   fputc( n, fo );
   n = 1;
  }
 }
 else if ( n >= 255 ){
  fputc( b, fo );
  fputc( n, fo );
  n = 1;
 }
 else{
  n++;
 }
}
fputc( b, fo );
fputc( n, fo );

以上。
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QC++でランレングス符号化のプログラムを組みたいです。

C++で、while,if文,char,intでランレングス符号化のプログラムを組みたいです。
たとえば、文字列aabcccと入力するとa2,b1,c3となるようにしたいです。
配列は使わずに、charで変数を二つ用意し、cinで入力、if文で判定しカウントという流れをwhileで繰り返す。そしてEOFで終了というような感じにしたいと思ってます。

よろしくお願いします。

Aベストアンサー

まず自分でコード組め。
とりあえず以下のような感じかな?
コメント全然つけてませんが、これぐらい分からないと苦しいぞ。

char c = 0, cc = 0;
int cnt = 0;
while ( 1 )
{
 c << cin;
 if ( c == '\n' ) break;
 if ( c == cc ) {
  cnt++;
 } else {
  if ( cc != 0 ) printf("%c%d", cc, cnt);
  cnt = 0; cc = c;
 }
}

※インデントに全角スペースを使っています
間違ってたらスマンw

Qランレングス法を用いたC言語解凍プログラムです

次の仕様を満たすプログラムを作成しろという課題なのですが
全く手が出ません
ある程度の解説を付けたソースコードを作成していただけないでしょうか。

1. 解凍対象となる文字列として, txtファイル内が(2_6*3_2*4_2*1_2*6_4*6_4*8_2*8_2*6_4*6_2*1_2*4_2*3_6*2_)となる
ファイルnewcompressed_C.txtを作成し
コマンドラインでファイルをchar 型のcontents[400]に読み込む.
2. contents[400]の内容を画面に表示させる.
3. 解凍用関数としてint fn_decompress(char *before, int str_num, char *after)を定
義する.仮引数before には,contents[0]のアドレスを与える.また,解凍後
の文字の代入用としてde_contents[100]を定義するとともに,仮引数after に
はde_contents[0]のアドレスを与える.fn_decompress()はde_contents[100]の要
素数を返すものとする.
4. 最後に,de_contents[100]の要素を画面上に表示させる.なお1 行
につき10 文字,改行して計10 行とし,
アルファベットCが現れればプログラムとして正しい出力表示とする.
5.ファイル名を誤って指定した場合には”Error”と表示する.

よろしくお願いいたします。

次の仕様を満たすプログラムを作成しろという課題なのですが
全く手が出ません
ある程度の解説を付けたソースコードを作成していただけないでしょうか。

1. 解凍対象となる文字列として, txtファイル内が(2_6*3_2*4_2*1_2*6_4*6_4*8_2*8_2*6_4*6_2*1_2*4_2*3_6*2_)となる
ファイルnewcompressed_C.txtを作成し
コマンドラインでファイルをchar 型のcontents[400]に読み込む.
2. contents[400]の内容を画面に表示させる.
3. 解凍用関数としてint fn_decompress(char *before, int str_num, char *after)を...続きを読む

Aベストアンサー

本当に全く手が出せないというのであれば、その講義をあきらめるなり再履修されるなりした方がよいかと思います。
少なくとも1,2,4,5はできると思うんですが。

Qcharと%c , %s の関係について

char型の変数の扱いで悩んでいます。
具体的には以下の二つのプログラムの差異についてです。

----------------------
char c;

scanf("%c", &c);
printf("%c\n", c);

-----------------------
char c;

scanf("%s", &c);
printf("%s\n", &c);

-----------------------


上のプログラムは正しいと思うのですが、下のプログラムが正しいのかどうか、わかる方に教えていただきたいと思い質問させていただきました。

どちらのプログラムも問題なく動作します。
僕自身は 下のプログラムの printf 関数については間違った使い方なのではないかと思っています。

scanf("%s", &c) は入力された文字のうち、終端文字の手前までの文字を引数のポインタが示すオブジェクトへ順に格納していく関数だと理解しているので、入力された文字が一文字だった場合、&cの示すオブジェクトに文字が代入されると考えたからです。

逆に printf("%s", &c) は、&cの示すオブジェクトから”ヌル文字”の手前までの文字列を順に表示する関数だと理解しているので、問題なく動作しているのは&cで示されるオブジェクトの後ろの領域が偶然'\0'だったからではないかと考えたからです。

何かの本で、未使用の領域は0である確率が高いという記述をみたことがあり、'\0'は0と同じだということなので問題なく動作する率が高いのではないかと思っています。


僕の考え方がどの程度正しくて、正確にはどうなのかを教えて欲しいです。


ちなみに、

-----------------------
char c;
char str[100];

scanf("%s", str);
scanf("%c", &c);
------------------------

と書くと c には改行文字が代入されてしまいます。
scanf("%s", str);
において"aasssdd "と最後に空白を入れると
c には空白文字が代入されます。

しかし、
--------------------------
char str1[100];
char str2[100];

scanf("%s", str1);
scanf("%s", str2);
--------------------------
においては、
scanf("%s", str1);
で "asdfg "と最後に空白を入れても次のstr2が空白で始まることはありません。


この辺りの処理がどのような法則で実行されているのかが分かりづらくて悩んでいます。
おそらく、
scanf("%s", str);
の場合には最初の文字が空白や改行文字でも、その次に有効な文字があればそれらの改行や空白を無視するのではないかと思っています。


分かる方がいましたら回答をよろしくお願いします。

char型の変数の扱いで悩んでいます。
具体的には以下の二つのプログラムの差異についてです。

----------------------
char c;

scanf("%c", &c);
printf("%c\n", c);

-----------------------
char c;

scanf("%s", &c);
printf("%s\n", &c);

-----------------------


上のプログラムは正しいと思うのですが、下のプログラムが正しいのかどうか、わかる方に教えていただきたいと思い質問させていただきました。

どちらのプログラムも問題なく動作します。
僕自身は 下...続きを読む

Aベストアンサー

> char c;
> scanf("%s", &c);
char c では1文字分の領域しか確保されていないので、
1文字以上の文字列を無理矢理格納すると
他のデータが存在しているかもしれない領域を書き換えてしまいます。(メモリ破壊)

なお、'\0'はscanfが(本来書き込んではいけない領域に対してですが)書き込んでいます。


> と書くと c には改行文字が代入されてしまいます。
最初のscanfが改行文字を読み込んでいないからです。
以下のページに書かれている内容と本質的には同じ。
http://www9.plala.or.jp/sgwr-t/c/sec05.html#s5-

> 最初の文字が空白や改行文字でも、その次に有効な文字があればそれらの改行や空白を無視するのではないかと思っています。
そう考えて問題ないと思います。

Qtxtファイルの文字を配列に格納

ファイル関数を使ってoutput.txt(txtファイル)の文字を配列に格納するプログラムを作っているのですが、配列に文字を入れられない状態です。
※参考になるページやアドバイスがあれば宜しくお願い致します。

■プログラム
#include <stdio.h>

void main(){
int i;
int data[10];
FILE *fp;
fp = fopen("output.txt","r");
if(fp == NULL){
printf("ファイルが見つかりません。");
}else{
for(i=0;fp != EOF;i++){
data[i] = fgetc( fp );
}
}
}

■output.txt
001 100 猫A 好きな物 ねこまんま
002 200 猫B 好きな物 キャットフード

Aベストアンサー

これで、やりたいこと、できませんかね?
++++++++++++++++++++++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
int i = 0, j = 0;
char temp, data[10][100];
FILE *fp;
fp = fopen("output.txt","r");
/* 初期化 */
memset(data, 0, sizeof(data));

if(fp == NULL){
printf("Cannot find file");
}else{
while((temp = fgetc(fp)) != EOF){
if (temp == ' ' || temp == '\n') {
data[i][j] = '\n';
i++;
j = 0;
} else {
data[i][j] = temp;
j++;
}
}
for (i = 0; i < 10; i++) {
printf("[%d] Output : %s \n", i, data[i]);
}
fclose(fp);
}

return 0;
}
++++++++++++++++++++++

これで、やりたいこと、できませんかね?
++++++++++++++++++++++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
int i = 0, j = 0;
char temp, data[10][100];
FILE *fp;
fp = fopen("output.txt","r");
/* 初期化 */
memset(data, 0, sizeof(data));

if(fp == NULL){
printf("Cannot find file");
}else{
while((temp = fgetc(fp)) != EOF){
if (temp == ' ' || temp == '\n') {
data[i][j] = '\n';
i++;
j = 0;
} else {
data[i][j] = temp;
j++;
}...続きを読む

Qc言語 ファイルから数字を読み込む

c言語初心者です。
forループをつかって、
ファイルから空白で区切られた数字を一つずつ読み込む
プログラムを作りたいのですが、
forループの中をどう書いたらいいかわかりません。

#include <stdio.h>

int main (int argc, char *argv[])
{
char *fileName = argv[1];

FILE *fp = fopen("fileName", "r");

int num;
int i;

for(i=0; i<10; i++){
fscanf(fp, "%d", &num);
printf("%d\n", num);
}
fclose(fp);
}

ファイルの内容は、10個の数字が書かれている設定です。

Aベストアンサー

FILE *fp = fopen("fileName", "r");
は、
FILE *fp = fopen(fileName, "r");
でしょうね。
他はいいと思いますが。

細かいことを言うと、argv[1] を参照する前に、argcの値をチェックすべき。

QN原子のsp3混成軌道について教えてください.

とある教科書で
N原子の基底状態
1s (↑↓)
2s (↑↓)
2p (↑↑↑)
となっており,sp3混成軌道をとる場合については
1s (↑↓)
sp3 (↑↑↑↑)
というような表記がされていました.

率直に・・・これは正しいのでしょうか??
正しいのであれば,sp3混成軌道をとる場合,電子が一つ足りないのはなぜなのか.
また,間違っている場合は,電子の正しい軌道配置?を教えて頂ければと思います.

色々自分で調べては見たのですが,ほとんどの説明はカーボン原子で説明されているため,N原子についてはほとんど見あたりませんでした・・・.

御存知の方おられましたら,書き込みよろしくお願いします!!

Aベストアンサー

間違ってます。

1s  (↑↓)
sp3 (↑↓、↑、↑、↑)

が正しい電子配置です。
四つの等価なsp3軌道のうち一つにはスピンが逆向きになるよう二つの電子が
収容され、残り三つに一つずつ電子が入ります。

電子が二つはいった軌道は非共有電子対に相当し
一つだけ入った軌道は不対電子に相当します。

Qファイル出力で改行を入れたい!

data.txtにファイル出力を行うのですが、gets(c)で入力した一語一語に改行を入れてdata.txtに出力したいのですがどうすればよいでしょうか。
返答のほどよろしくお願いいたします。
include<stdio.h>
#define SIZE 20
void main(void)
{
char c[SIZE], *p;
FILE *fp;

fp = fopen("data.txt","w+");
p = c;
while(gets(c) != NULL){
fputs(p,fp);
}

fclose(fp);
printf("data.txtへ出力しました\n");

}

Aベストアンサー

一語一語ってのは、1回の入力毎って事でしょうか?
とするならば、これでどうでしょうか?

#include <stdio.h>
#define SIZE 20
void main(void)
{
  char c[SIZE], *p;
  FILE *fp;
  
  fp = fopen("data.txt","w+");
  p = c;
  while(gets(c) != NULL){
    fputs(p,fp);
    fputc('\n', fp);
  }
  
  fclose(fp);
  printf("data.txtへ出力しました\n");
  
}

Qデータを圧縮したい

変数の配列を圧縮したいのですが、全く検討もつきません。
どうすればいいでしょうか?
簡単な圧縮の勉強サイトはないのでしょうか?

Aベストアンサー

まあ役に立つかどうかはわかりませんが

Run-Length圧縮の一例(ゆみみみっくす フォーマット解説:圧縮されたデータの展開のしかた)
http://ku-www.ss.titech.ac.jp/~yatsushi/yumimi.html
Windows DIBのRun-Length圧縮(BMP(DIB)フォーマット解説:圧縮について)
http://hp.vector.co.jp/authors/VA022217/tips/doc/bitmap.html

いわゆる"辞書法"による圧縮(LZ77/LZ78法)
技術評論社 Software Technologyシリーズ
C言語による最新アルゴリズム事典(ISBN4-87408-414-1)
http://www.gihyo.co.jp/books/syoseki.php/4-87408-414-1

# 最近高速化のためのindexingとかばかりで
# 「データをでっかくする方向」ばかり
# やってたからちょっと新鮮。

Q標準状態の液体や気体の変換方法を教えてください。

標準状態にある液体を気体に(その逆も)変換するときの計算方法を教えてください。ネットで検索すると色々な式が出ているのですが、どの単位で数値を入れればよいか等の基本的なことからわかりません。
お手数ですが、計算方法と素人でもかなり基礎的なところから勉強できるようなサイト等を教えてください。
かなりの素人なのでできるだけわかりやすい言葉で書かれているところがあればありがたいです。
よろしくお願いいたします。

Aベストアンサー

 No.1さんがすでに回答されていますが、補足的に。
 気体の状態方程式
PV = nRT
が基本ですが、単位は場合によって違うものが使われます。
 最も汎用性のある単位は、SI(国際単位系、“SI”はフランス語での頭文字です)に定められている単位です。
圧力:Pa(パスカル)
   Pa = N m^(-2)(ニュートン毎平方メートル))
     = J m^(-3)(ジュール毎立方メートル)
体積:m^3(立方メートル)
です。しかし、圧力と体積は、しばしば次の単位で表されます。SI単位との関係式をその下に記します。
圧力:atm(気圧)
   1 atm = 1.01325×10^5 Pa
体積:L(リットル)
   1 L = 10^(-3) m^3
物質量の単位はmol(モル)、温度(絶対温度、熱力学温度)の単位はK(ケルビン)です。セルシウス温度との関係は、次の通りです。
絶対温度/K = セルシウス温度/℃ + 273.15
たとえば、0 ℃を絶対温度に直すには、
絶対温度/K = 0 + 273.15 = 273.15 ∴絶対温度 = 273.15 K
となります。高校の範囲では、よく273 Kと省略して使われます。
 標準状態(0 ℃、1 atm)での1 molの理想気体の体積は、
約22.4141 L
です。No.1さんのご回答のように、よく22.4 Lと略して使われます。
 気体定数Rは、使う単位によって数値が異なります。SI単位を使うと、
R = 8.314510 J K^(-1) mol^(-1) (ジュール毎ケルビン毎モル)
となります。8.314と覚えておけばよいでしょう。単位の換算の際に、
J = N・m(ニュートン・メートル) = Pa・m^3(パスカル・立方メートル)
の関係が必要になります。
 単位atm、Lを使うと、気体定数は
R = 0.082057 atm L K^(-1) mol^(-1) (気圧・リットル毎ケルビン毎モル)
となります。私は高校でこちらを習いました。値は0.08206か0.0821と覚えておけばよいでしょう。
 それから、PV = nRTを次のように変換して使う場合があります。
 両辺をVで割って、P = (n/V)RTとし、モル濃度cの定義式c=n/Vを代入して、
P = cRT …(1)
としたりします。式(1)は、濃度平衡定数と圧平衡定数の間の変換を行う際に使ったりします。
 また、物質量nと質量m、モル質量M(無名数の原子量、分子量、式量に単位g/molをつけたもの)の間の関係
n=m/M
を代入して、
PV = (m/M)RT
これを変形して
PM = (m/V)RT
ここに、密度ρの定義式ρ=m/Vを代入して、
PM = ρRT …(2)
と変形し、この式(2)を使ったりします。
 全部の式を覚える必要はありません。必要最小限の関係式と定数の値、そして単位の間の関係を覚え、上のように式の代入、文字の消去をして、式を自在に変形できるようになっておきましょう(そして計算間違いのないように)。

 No.1さんがすでに回答されていますが、補足的に。
 気体の状態方程式
PV = nRT
が基本ですが、単位は場合によって違うものが使われます。
 最も汎用性のある単位は、SI(国際単位系、“SI”はフランス語での頭文字です)に定められている単位です。
圧力:Pa(パスカル)
   Pa = N m^(-2)(ニュートン毎平方メートル))
     = J m^(-3)(ジュール毎立方メートル)
体積:m^3(立方メートル)
です。しかし、圧力と体積は、しばしば次の単位で表されます。SI単位との関係式をその下に記します。
圧力:a...続きを読む

QC言語 ファイルの指定された行を表示

こんにちは。
回答お願いします。
今私は作業の高効率化を目指すためプログラムを考えています。
まだぜんぜんできていませんが・・
ファイルの指定された行を表示する関数がないだろうか?
もしくは似たような方法はないだろうかと考えています。

できれば例題とともに教えていただければ幸いです。
具体的にどういう風にしたいのかというと
----test.txt-------
aaaa
bbbbb
cccccc
dddd
eeeeeeee
ffffff
-------------------
というファイルがあったとしたらgetsで4と入れてやったら
四行目のddddが表示されるようにしたいのです。
まだまだ初心者ですのでさっと考えることができません。
どうかご教授お願いします。

Aベストアンサー

★高効率を目指しているの?
・固定長データなら高効率で1行を取得できたりします。
 例えば
 ----test.txt-------
 aaaaa
 bbbbb
 ccccc
 ddddd
 eeeee
 fffff
 -------------------
 という固定長データ(5文字×6行)の場合は
 int no = 4; ←4行目を取得したい時
 fseek( fp, ((no - 1) * 7), SEEK_SET ); ←5文字+\r+\n=『7』
 fgets( buff, sizeof(buff), fp );
 ↑
 これなら行番号で指定した1行を fgets() 関数で取得可能です。
 ※なおバイナリモードでオープンして下さい。
・可変長データの場合は行の先頭のオフセット位置を最初の読み込みで管理します。
 例えば
 ----test.txt-------
 aaaa
 bbbbb
 cccccc
 dddd
 eeeeeeee
 ffffff
 -------------------
 という可変長データ(4,5,6,4,8,6文字)の場合は
 オフセット位置の配列を行数分用意します。→事前に分かれば楽ですね。行数。
 long offset[ 100 ]; ←100行だと仮定
 int max;
 
 for ( max = 0 ; !feof(fp) ; max++ ){
  if ( max >= 100 ){ ←安全対策
   break;
  }
  offset[ max ] = ftell( fp );
  fgets( buff, sizeof(buff), fp );
 }
 ↑
 ここまでがオフセット位置の読み込みです。次は読み出しです。
 int no = 4; ←4行目を取得したい時
 fseek( fp, offset[no - 1], SEEK_SET );
 fgets( buff, sizeof(buff), fp );
 ↑
 これで行番号で指定した1行を fgets() 関数で取得可能です。
 ※やっぱりバイナリモードでオープンして下さい。
・あと行数の指定時に 1~max の範囲になるように補正処理も入れたほうが良いかも。
 例えば
 if ( no < 1 ){
  no = 1;
 }
 else if ( no >= max ){
  no = max;
 }
 ↑
 こんな感じで。
・以上を参考にして下さい。
 下の『参考URL』もどうぞ。

参考URL:http://www9.plala.or.jp/sgwr-t/lib/fseek.html

★高効率を目指しているの?
・固定長データなら高効率で1行を取得できたりします。
 例えば
 ----test.txt-------
 aaaaa
 bbbbb
 ccccc
 ddddd
 eeeee
 fffff
 -------------------
 という固定長データ(5文字×6行)の場合は
 int no = 4; ←4行目を取得したい時
 fseek( fp, ((no - 1) * 7), SEEK_SET ); ←5文字+\r+\n=『7』
 fgets( buff, sizeof(buff), fp );
 ↑
 これなら行番号で指定した1行を fgets() 関数で取得可能です。
 ※なおバイナリモードでオープンして下さ...続きを読む


人気Q&Aランキング