データの追加と削除について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
しき
記事: 34
登録日時: 11ヶ月前

データの追加と削除について

#1

投稿記事 by しき » 11ヶ月前

すでにあるファイルに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: データの追加と削除について

#2

投稿記事 by かずま » 11ヶ月前

しき さんが書きました: コードを途中まで作成したのですが実行結果がうまく出ません。
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文の始まりと終わりなどの対応がちゃんとわかります。

それから、期待する実行例を

コード:

 のタグで書いてください。

しき
記事: 34
登録日時: 11ヶ月前

Re: データの追加と削除について

#3

投稿記事 by しき » 11ヶ月前

なるほど。わかっていませんでした。
コードはこれでコンパイルできると思います。

コード:

#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} になっていれば完成です。

アバター
みけCAT
記事: 6019
登録日時: 7年前
住所: 千葉県
連絡を取る:

Re: データの追加と削除について

#4

投稿記事 by みけCAT » 11ヶ月前

すぐに気付くエラーは
  • 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削除)する→修正したメモリ上のデータをファイルに書き込む(上書きする)」
という方法をとるのが簡単でしょう。
具体的なファイルフォーマットは教えていただけますか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6019
登録日時: 7年前
住所: 千葉県
連絡を取る:

Re: データの追加と削除について

#5

投稿記事 by みけCAT » 11ヶ月前

追加する処理を走らせた後で「追加する値」を読み込んで(そしてその値を無視して)も、意味ないですよね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

しき
記事: 34
登録日時: 11ヶ月前

Re: データの追加と削除について

#6

投稿記事 by しき » 11ヶ月前

指摘ありがとうございます。修正してみます
みけCAT さんが書きました: 「ファイルからメモリにデータを全部読み込む→メモリ上のデータを修正(追加or削除)する→修正したメモリ上のデータをファイルに書き込む(上書きする)」
ということは追加する関数と削除する関数をまとめてしまえばいいのでしょうか?
またファイルフォーマットですが何分初心者なもんでよくわからないのですがどう答えたらいいんでしょうか・・
emacsで作成したファイルに数値をうちこんで作りましたとしか言えないです・・。申し訳ありません・・。

アバター
みけCAT
記事: 6019
登録日時: 7年前
住所: 千葉県
連絡を取る:

Re: データの追加と削除について

#7

投稿記事 by みけCAT » 11ヶ月前

しき さんが書きました:追加する関数と削除する関数をまとめてしまえばいいのでしょうか?
「まとめてしまえば(無条件に)いい」ということはできませんが、追加と削除で共通する(=共通のコードでやるべき)処理は少なくないでしょう。
しき さんが書きました:またファイルフォーマットですが何分初心者なもんでよくわからないのですがどう答えたらいいんでしょうか・・
実際のファイルに書いてある内容を教えてください。
例えば

コード:

{1,6,2,43,123}
なのか、

コード:

1 6 2 43 123
なのか、

コード:

1
6
2
43
123
なのか…とか。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

しき
記事: 34
登録日時: 11ヶ月前

Re: データの追加と削除について

#8

投稿記事 by しき » 11ヶ月前

わかりました。せっかくまとめるという方法を提示していただいいたのですが、今回は削除する関数と追加する関数、別々に分けようと思います。今回のこのコードが完成してからまとめてみる方法にも挑戦したいと思います。

なるほどファイルフォーマットはそういうことなのですか。
でしたら二番目です。

しき
記事: 34
登録日時: 11ヶ月前

Re: データの追加と削除について

#9

投稿記事 by しき » 11ヶ月前

追加する方はなんとか形になりましたが削除する方がやはりどうしていいかわかりません・・。
調べてみたところ過去のトピックで似たようなことをやっていたのですがよくわからなかったです・・。
たぶんこれがみけCATさんがおっしゃっていたやり方に近いかなと思うのですが・・。


過去トピック 
http://dixq.net/forum/viewtopic.php?t=11000

shira211
記事: 13
登録日時: 2年前

Re: データの追加と削除について

#10

投稿記事 by shira211 » 11ヶ月前

追加が形になったのなら、それをここに書いてください。

削除のほうですが、
1 6 2 43 123の数字が入っている箱Aと、何も入っていない箱Bがあるとき、箱Bを箱Aから1を取り除いたものにするにはどうするか?
というのを考えればいいです。ただし、コンピューターの動きを再現するため、
数字を読み取るだけでは値は消えない、変わらない
一度に扱える数字は1つまで
とします。
あとはこれをC言語に置き換えるだけです。

かずま

Re: データの追加と削除について

#11

投稿記事 by かずま » 11ヶ月前

ちょっと変なことを思いつきました。
データの中に絶対に使用しない値があるとすれば、
それを削除マークにしてしまうというものです。

次のプログラムは、質問の問題とは異なり、
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: データの追加と削除について

#12

投稿記事 by かずま » 11ヶ月前

すみません。メニューの一部を訂正します。

コード:

         "  w [file]: write data to file\n" 
 を

コード:

         "  s [file]: save data to file\n" 
にしてください。

しき
記事: 34
登録日時: 11ヶ月前

Re: データの追加と削除について

#13

投稿記事 by しき » 11ヶ月前

shira211さん、かずまさん返信ありがとうございます。

shira211さん、追加の関数ですが不具合を見つけたので修正中です・・。不具合というのは追加した値が最後の要素にくっついてしまうというものなんですが、かずまさんのコードを見ていたら直すべきところが分かり、それを現在修正しています。また削除の件、アドバイスありがとうございます!実践してみます。

かずまさん、ソースコードの提示ありがとうございます。訂正の件も了解です。参考にさせていただきます。あと、きれいなインデントを目指します!
オフトピック
今回の質問とは関係ないのですが修正した配列は最終的にソートして探索しようかと思っているので、配列の要素の位置はあまり気にしません・・。書き方が悪かったです。

追記:一週間たったのでひとまずかずまさんのコードを最終コードとし、解決といたします。協力ありがとうございました。

かずま

Re: データの追加と削除について

#14

投稿記事 by かずま » 11ヶ月前

しき さんが書きました: 追記:一週間たったのでひとまずかずまさんのコードを最終コードとし、解決といたします。協力ありがとうございました。
いつの間にか、解決になっていますね。
そういう重要なことは、以前の記事の修正ではなく、
新たな返信にしてください。

結局、ソートはしないのですか?
私としては、末尾への 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: データの追加と削除について

#15

投稿記事 by かずま » 11ヶ月前

すみません。バグがありました。
read_data() の中に、del_count = 0;を
追加してください。

しき
記事: 34
登録日時: 11ヶ月前

Re: データの追加と削除について

#16

投稿記事 by しき » 11ヶ月前

かずまさん、返信遅くなり申し訳ありません。
データの追加はheadやtailで追加する場所を変更できるのですね。
ソースありがとうございます。自分では思いつきませんでした・・。

またソートの関数は以前の記事で完成したので省略させていただきました。
リンク
http://dixq.net/forum/viewtopic.php?f=3&t=19436

ちなみにここでのソートは探索をするためのものを想定していたためファイルの中身自体を入れ替えるものではないです。
もしこのソート法ではうまくいかないのであれば見当違いなことを言っているとは思いますがご了承ください。

かずま

Re: データの追加と削除について

#17

投稿記事 by かずま » 11ヶ月前

かずま さんが書きました:
しき さんが書きました:

コード:

    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 は要らない
とも言えるのですが、これはあったほうが分かりやすいかなと思って、
残しています。

しき
記事: 34
登録日時: 11ヶ月前

Re: データの追加と削除について

#18

投稿記事 by しき » 11ヶ月前

配慮ありがたいです。
理解するためにも、もう一度コードを見直してみます!
最後までありがとうございました。

返信

“C言語何でも質問掲示板” へ戻る