ページ 1 / 1
データの追加と削除について
Posted: 2017年8月01日(火) 21:40
by しき
すでにあるファイルにx(変数)を新たに加える関数と、x(変数)をファイルから削除する関数を作成せよ
という問題です。
コードを途中まで作成したのですが実行結果がうまく出ません。
insertの方は追加されるのが(null)のみです。
なにが原因なのでしょうか?
またdelete(削除)の方はいろいろ調べてみたものの、どうすればいいかわかりません・・。
解決策を教えてください。
コード:
#include <stdio.h>
#include <stdlib.h>
#define DATA 10000
int insert(const char filename[20],int a[DATA] )
{
int n;
FILE *fin;
if ((fin=fopen(filename,"a"))==NULL){
return -1 ; }
for(n = 0; n < 1 ; n++){
fprintf(fin,"%s",a[n]);
}
fclose(fin);
}//xをデータに加える関数
int delete(){}//xをデータから削除する関数
int main(void)
{
char filename[20];
int a[DATA];
char A[2];
puts("データにxを加えるならi、データからxを除去するならd を押してください");
scanf("%s",A);
if(A[0] == 'i'){
printf("ファイル名=");
scanf("%s",filename);
n=insert(filename,a);
if(n==-1){
printf("ファイルをオープンできません。\n");
}
else{
printf("追加する値を入力\n");
scanf("%d",&a[i]);
}
}
if(A[0] == 'd'){
printf("delete\n");
}
}
Re: データの追加と削除について
Posted: 2017年8月01日(火) 22:40
by かずま
しき さんが書きました:
コードを途中まで作成したのですが実行結果がうまく出ません。
insertの方は追加されるのが(null)のみです。
なにが原因なのでしょうか?
提示されたコードはコンパイルできません。
コンパイルできるコードをインデントをちゃんとつけて貼り付けてください。
インデントを付けるとは、次のように書くことです。
コード:
#include <stdio.h>
#include <stdlib.h>
#define DATA 10000
int insert(const char filename[20], int a[DATA])
{
int n;
FILE *fin;
if ((fin = fopen(filename, "a")) == NULL) {
return -1;
}
for(n = 0; n < 1 ; n++){
fprintf(fin, "%s", a[n]);
}
fclose(fin);
}//xをデータに加える関数
int delete() {} //xをデータから削除する関数
int main(void)
{
char filename[20];
int a[DATA];
char A[2];
puts("データにxを加えるならi、データからxを除去するならdを押してください");
scanf("%s", A);
if (A[0] == 'i') {
printf("ファイル名=");
scanf("%s", filename);
n = insert(filename, a);
if (n == -1) {
printf("ファイルをオープンできません。\n");
}
else{
printf("追加する値を入力\n");
scanf("%d", &a[i]);
}
}
if (A[0] == 'd') {
printf("delete\n");
}
}
関数の始まりと終わり、if文の始まりと終わりなどの対応がちゃんとわかります。
それから、期待する実行例を
Re: データの追加と削除について
Posted: 2017年8月01日(火) 23:23
by しき
なるほど。わかっていませんでした。
コードはこれでコンパイルできると思います。
コード:
#include <stdio.h>
#include <stdlib.h>
#define DATA 10000
int insert(const char filename[20],int a[DATA] )
{
int n;
FILE *fin;
if ((fin=fopen(filename,"a"))==NULL){
return -1 ; }
for(n = 0; n < 1 ; n++){
fprintf(fin,"%s",a[n]);
}
fclose(fin);
}//xをデータaに加える関数
int delete(){}
int main(void)
{
char filename[20];
int a[DATA];
char A[2];
int n,i;
puts("データにxを加えるならi、データからxを除去するならd を押してください");
scanf("%s",A);
if(A[0] == 'i'){
printf("ファイル名=");
scanf("%s",filename);
n=insert(filename,a);
if(n==-1){
printf("ファイルをオープンできません。\n");
}
else{
printf("追加する値を入力\n");
scanf("%d",&a[i]);
}
}
if(A[0] == 'd'){
printf("delete\n");
}
}
期待する実行例です。※wc.out={1,6,2,43,123}がはいっています
コード:
データにxを加えるならi、データからxを除去するならdを押してください
i
ファイル名=wc.out
追加する値を入力
5
^C
データにxを加えるならi、データからxを除去するならdを押してください
d
ファイル名=wc.out
削除する値を入力
1
^C
これでwc.out={1,6,2,43,123} が wc.out={5,6,2,43,123} になっていれば完成です。
Re: データの追加と削除について
Posted: 2017年8月01日(火) 23:44
by みけCAT
すぐに気付くエラーは
- 12行目で、ナル終端の文字列を指すchar*型のデータを要求する書式%sにint型のデータを渡しているので、未定義動作になる
- 32行目で、return文を通らずに戻った関数の戻り値を計算に使う可能性があり、未定義動作になる可能性がある
- 37行目で、未初期化の自動変数i(値は不定)を計算(添字)に使っているので、未定義動作になる
ですね。
しき さんが書きました:これでwc.out={1,6,2,43,123} が wc.out={5,6,2,43,123} になっていれば完成です。
数GBとかの大量のデータが入力されるなら話は別ですが、
現代の普通のパソコンで実行するなら少なくとも100MB程度までのデータであれば追加、削除ともに
「ファイルからメモリにデータを全部読み込む→メモリ上のデータを修正(追加or削除)する→修正したメモリ上のデータをファイルに書き込む(上書きする)」
という方法をとるのが簡単でしょう。
具体的なファイルフォーマットは教えていただけますか?
Re: データの追加と削除について
Posted: 2017年8月01日(火) 23:48
by みけCAT
追加する処理を走らせた後で「追加する値」を読み込んで(そしてその値を無視して)も、意味ないですよね。
Re: データの追加と削除について
Posted: 2017年8月02日(水) 00:13
by しき
指摘ありがとうございます。修正してみます
みけCAT さんが書きました:
「ファイルからメモリにデータを全部読み込む→メモリ上のデータを修正(追加or削除)する→修正したメモリ上のデータをファイルに書き込む(上書きする)」
ということは追加する関数と削除する関数をまとめてしまえばいいのでしょうか?
またファイルフォーマットですが何分初心者なもんでよくわからないのですがどう答えたらいいんでしょうか・・
emacsで作成したファイルに数値をうちこんで作りましたとしか言えないです・・。申し訳ありません・・。
Re: データの追加と削除について
Posted: 2017年8月02日(水) 00:17
by みけCAT
しき さんが書きました:追加する関数と削除する関数をまとめてしまえばいいのでしょうか?
「まとめてしまえば(無条件に)いい」ということはできませんが、追加と削除で共通する(=共通のコードでやるべき)処理は少なくないでしょう。
しき さんが書きました:またファイルフォーマットですが何分初心者なもんでよくわからないのですがどう答えたらいいんでしょうか・・
実際のファイルに書いてある内容を教えてください。
例えば
なのか、
なのか、
なのか…とか。
Re: データの追加と削除について
Posted: 2017年8月02日(水) 00:24
by しき
わかりました。せっかくまとめるという方法を提示していただいいたのですが、今回は削除する関数と追加する関数、別々に分けようと思います。今回のこのコードが完成してからまとめてみる方法にも挑戦したいと思います。
なるほどファイルフォーマットはそういうことなのですか。
でしたら二番目です。
Re: データの追加と削除について
Posted: 2017年8月02日(水) 03:10
by しき
追加する方はなんとか形になりましたが削除する方がやはりどうしていいかわかりません・・。
調べてみたところ過去のトピックで似たようなことをやっていたのですがよくわからなかったです・・。
たぶんこれがみけCATさんがおっしゃっていたやり方に近いかなと思うのですが・・。
過去トピック
http://dixq.net/forum/viewtopic.php?t=11000
Re: データの追加と削除について
Posted: 2017年8月03日(木) 14:08
by shira211
追加が形になったのなら、それをここに書いてください。
削除のほうですが、
1 6 2 43 123の数字が入っている箱Aと、何も入っていない箱Bがあるとき、箱Bを箱Aから1を取り除いたものにするにはどうするか?
というのを考えればいいです。ただし、コンピューターの動きを再現するため、
数字を読み取るだけでは値は消えない、変わらない
一度に扱える数字は1つまで
とします。
あとはこれをC言語に置き換えるだけです。
Re: データの追加と削除について
Posted: 2017年8月03日(木) 15:56
by かずま
ちょっと変なことを思いつきました。
データの中に絶対に使用しない値があるとすれば、
それを削除マークにしてしまうというものです。
次のプログラムは、質問の問題とは異なり、
wc.out={1,6,2,43,123} が wc.out={5,6,2,43,123} に
なりませんが、削除をこんな風に処理すればどうで
しょうか、という例なので、よく読んで参考にして
みてはいかがでしょうか?
コード:
#include <stdio.h>
#define MAX_SIZE 10000
#define DELETED 99999999
char filename[256];
int data[MAX_SIZE];
int size;
int modified;
void menu(void)
{
puts(" m: display this menu\n"
" p: print data\n"
" r file: read data form file\n"
" a data: append data\n"
" d data: delete data\n"
" w [file]: write data to file\n"
" q: quit");
}
void print_data(void)
{
for (int i = 0; i < size; i++)
if (data[i] != DELETED) printf(" %d", data[i]);
printf("\n");
}
void read_data(const char *buf)
{
if (sscanf(buf+1, "%s", filename) != 1) {
puts("filename");
return;
}
FILE *fp = fopen(filename, "r");
if (!fp) {
printf("can't open %s\n", filename);
return;
}
for (size = 0; size < MAX_SIZE; size++)
if (fscanf(fp, "%d", &data[size]) != 1) break;
fclose(fp);
modified = 0;
}
void append_data(const char *buf)
{
int x;
if (sscanf(buf+1, "%d", &x) != 1) { puts("no data"); return; }
if (size >= MAX_SIZE) { puts("no space"); return; }
data[size++] = x;
modified = 1;
}
void delete_data(const char *buf)
{
int x, i;
if (sscanf(buf+1, "%d", &x) != 1) { puts("no data"); return; }
for (i = 0; i < size && data[i] != x; i++) ;
if (i >= size) { puts("not found"); return; }
data[i] = DELETED;
modified = 1;
}
void save_data(const char *buf)
{
if (filename[0] == '\0' && sscanf(buf+1, "%s", filename) != 1) {
puts("no filename"); return;
}
FILE *fp = fopen(filename, "w");
if (!fp) { printf("can't create %s\n", filename); return; }
for (int i = 0; i < size; i++)
if (data[i] != DELETED) fprintf(fp, "%d ", data[i]);
fclose(fp);
modified = 0;
}
int main(void)
{
char buf[1024];
menu();
while (printf(">> "), fgets(buf, sizeof buf, stdin)) {
if (buf[0] == 'm') menu();
else if (buf[0] == 'p') print_data();
else if (buf[0] == 'r') read_data(buf);
else if (buf[0] == 'a') append_data(buf);
else if (buf[0] == 'd') delete_data(buf);
else if (buf[0] == 's') save_data(buf);
else if (buf[0] == 'q') {
if (!modified) break;
printf("data modified. really quit[y/n]? ");
if (fgets(buf, sizeof buf, stdin) && buf[0] == 'y') break;
}
}
return 0;
}
実行例
コード:
m: display this menu
p: print data
r file: read data form file
a data: append data
d data: delete data
w [file]: write data to file
q: quit
>> r wc.out
>> p
1 6 2 43 123
>> a 5
>> p
1 6 2 43 123 5
>> d 1
>> p
6 2 43 123 5
>> s
>> q
めざせ、きれいなインデント。
Re: データの追加と削除について
Posted: 2017年8月03日(木) 16:03
by かずま
すみません。メニューの一部を訂正します。
コード:
" w [file]: write data to file\n"
を
コード:
" s [file]: save data to file\n"
にしてください。
Re: データの追加と削除について
Posted: 2017年8月04日(金) 00:28
by しき
shira211さん、かずまさん返信ありがとうございます。
shira211さん、追加の関数ですが不具合を見つけたので修正中です・・。不具合というのは追加した値が最後の要素にくっついてしまうというものなんですが、かずまさんのコードを見ていたら直すべきところが分かり、それを現在修正しています。また削除の件、アドバイスありがとうございます!実践してみます。
かずまさん、ソースコードの提示ありがとうございます。訂正の件も了解です。参考にさせていただきます。あと、きれいなインデントを目指します!
オフトピック
今回の質問とは関係ないのですが修正した配列は最終的にソートして探索しようかと思っているので、配列の要素の位置はあまり気にしません・・。書き方が悪かったです。
追記:一週間たったのでひとまずかずまさんのコードを最終コードとし、解決といたします。協力ありがとうございました。
Re: データの追加と削除について
Posted: 2017年8月13日(日) 17:41
by かずま
しき さんが書きました:
追記:一週間たったのでひとまずかずまさんのコードを最終コードとし、解決といたします。協力ありがとうございました。
いつの間にか、解決になっていますね。
そういう重要なことは、以前の記事の修正ではなく、
新たな返信にしてください。
結局、ソートはしないのですか?
私としては、末尾への append だけではなく、
先頭への insert も予定していました。
そのソースを付けておきます。
コード:
#include <stdio.h>
#define MAX_SIZE 10000
#define DELETED 99999999
char filename[256];
int data[MAX_SIZE];
int head, tail;
int size, del_count;
int modified;
void menu(void)
{
puts(" m: display this menu\n"
" p: print data\n"
" r file: read data form file\n"
" i data: insert data\n"
" a data: append data\n"
" d data: delete data\n"
" s [file]: save data to file\n"
" q: quit");
}
void print_data(void)
{
for (int i = head; i != tail; ++i == MAX_SIZE && (i = 0))
if (data[i] != DELETED) printf(" %d", data[i]);
printf("\n");
}
void read_data(const char *buf)
{
if (sscanf(buf+1, "%s", filename) != 1) { puts("filename"); return; }
FILE *fp = fopen(filename, "r");
if (!fp) { printf("can't open %s\n", filename); return; }
for (size = 0; size < MAX_SIZE; size++)
if (fscanf(fp, "%d", &data[size]) != 1) break;
fclose(fp);
head = 0;
tail = size;
modified = 0;
}
int no_space(void)
{
if (size < MAX_SIZE - 1) return 0;
if (del_count == 0) return 1;
int j = head;
for (int i = head; i != tail; ++i == MAX_SIZE && (i = 0))
if (data[i] != DELETED) {
data[j++] = data[i];
if (j == MAX_SIZE) j = 0;
}
tail = j;
size -= del_count;
del_count = 0;
return 0;
}
void insert_data(const char *buf)
{
int x;
if (sscanf(buf+1, "%d", &x) != 1) { puts("no data"); return; }
if (no_space()) { puts("no space"); return; }
if (head == 0) head = MAX_SIZE;
data[--head] = x;
size++;
modified = 1;
}
void append_data(const char *buf)
{
int x;
if (sscanf(buf+1, "%d", &x) != 1) { puts("no data"); return; }
if (no_space()) { puts("no space"); return; }
if (tail == MAX_SIZE - 1) tail = 0;
data[tail++] = x;
size++;
modified = 1;
}
void delete_data(const char *buf)
{
int x, i;
if (sscanf(buf+1, "%d", &x) != 1) { puts("no data"); return; }
if (head <= tail)
for (i = head; i != tail && data[i] != x; i++) ;
else
for (i = head; i != tail && data[i] != x; ++i == MAX_SIZE && (i = 0)) ;
if (i == tail) { puts("not found"); return; }
data[i] = DELETED;
del_count++;
modified = 1;
}
void save_data(const char *buf)
{
if (sscanf(buf+1, "%s", filename) != 1 && filename[0] == '\0') {
puts("no filename"); return;
}
FILE *fp = fopen(filename, "w");
if (!fp) { printf("can't create %s\n", filename); return; }
for (int i = head; i != tail; ++i == MAX_SIZE && (i = 0))
if (data[i] != DELETED) fprintf(fp, "%d ", data[i]);
fclose(fp);
modified = 0;
}
int main(void)
{
char buf[1024];
menu();
while (printf(">> "), fgets(buf, sizeof buf, stdin)) {
if (buf[0] == 'm') menu();
else if (buf[0] == 'p') print_data();
else if (buf[0] == 'r') read_data(buf);
else if (buf[0] == 'i') insert_data(buf);
else if (buf[0] == 'a') append_data(buf);
else if (buf[0] == 'd') delete_data(buf);
else if (buf[0] == 's') save_data(buf);
else if (buf[0] == 'q') {
if (!modified) break;
printf("data modified. really quit[y/n]? ");
if (fgets(buf, sizeof buf, stdin) && buf[0] == 'y') break;
}
}
return 0;
}
空きがなくなると、削除マークを取り去って空きを作ろうとします。
先頭への挿入を楽にするため、data[] はリング状に使用します。
Re: データの追加と削除について
Posted: 2017年8月13日(日) 17:49
by かずま
すみません。バグがありました。
read_data() の中に、del_count = 0;を
追加してください。
Re: データの追加と削除について
Posted: 2017年8月14日(月) 18:53
by しき
かずまさん、返信遅くなり申し訳ありません。
データの追加はheadやtailで追加する場所を変更できるのですね。
ソースありがとうございます。自分では思いつきませんでした・・。
またソートの関数は以前の記事で完成したので省略させていただきました。
リンク
http://dixq.net/forum/viewtopic.php?f=3&t=19436
ちなみにここでのソートは探索をするためのものを想定していたためファイルの中身自体を入れ替えるものではないです。
もしこのソート法ではうまくいかないのであれば見当違いなことを言っているとは思いますがご了承ください。
Re: データの追加と削除について
Posted: 2017年8月15日(火) 21:21
by かずま
かずま さんが書きました:しき さんが書きました:
コード:
if (head <= tail)
for (i = head; i != tail && data[i] != x; i++) ;
else
for (i = head; i != tail && data[i] != x; ++i == MAX_SIZE && (i = 0)) ;
delete_data() の中ですが、これは無駄なコードでした。
if は不要です。次のように訂正します。
コード:
for (i = head; i != tail && data[i] != x; ++i == MAX_SIZE && (i = 0)) ;
コードを丹念に読んで、その意味を理解しようとすれば
勉強になるのに、そうする人はほとんどいないのでしょう。
実は、head と tail と MAX_SIZE さえあれば、size は要らない
とも言えるのですが、これはあったほうが分かりやすいかなと思って、
残しています。
Re: データの追加と削除について
Posted: 2017年8月15日(火) 22:30
by しき
配慮ありがたいです。
理解するためにも、もう一度コードを見直してみます!
最後までありがとうございました。