合計 昨日 今日

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

[このトピックは解決済みです]

フォーラムルール
フォーラムルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Name: しき
[URL]
入門者(3,148 ポイント)
Date: 2017年8月01日(火) 21:40
No: 1
(OFFLINE)

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

すでにあるファイルにx(変数)を新たに加える関数と、x(変数)をファイルから削除する関数を作成せよ
という問題です。
コードを途中まで作成したのですが実行結果がうまく出ません。
insertの方は追加されるのが(null)のみです。
なにが原因なのでしょうか?
またdelete(削除)の方はいろいろ調べてみたものの、どうすればいいかわかりません・・。
解決策を教えてください。
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#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");  
 
 }
}

Name: かずま
[URL]
Date: 2017年8月01日(火) 22:40
No: 2
(OFFLINE)

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

しき さんが書きました:コードを途中まで作成したのですが実行結果がうまく出ません。
insertの方は追加されるのが(null)のみです。
なにが原因なのでしょうか?

提示されたコードはコンパイルできません。
コンパイルできるコードをインデントをちゃんとつけて貼り付けてください。
インデントを付けるとは、次のように書くことです。
コード[C]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#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文の始まりと終わりなどの対応がちゃんとわかります。

それから、期待する実行例を [code=text] のタグで書いてください。

Name: しき
[URL]
入門者(3,148 ポイント)
Date: 2017年8月01日(火) 23:23
No: 3
(OFFLINE)

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

なるほど。わかっていませんでした。
コードはこれでコンパイルできると思います。
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#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}がはいっています
コード[Text]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
データに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} になっていれば完成です。

Name: みけCAT
[URL]
伝説なるハッカー(670,973 ポイント)
Date: 2017年8月01日(火) 23:44
No: 4
(ONLINE)

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

すぐに気付くエラーは
  • 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で殴ればいい!(死亡フラグ)

Name: みけCAT
[URL]
伝説なるハッカー(670,973 ポイント)
Date: 2017年8月01日(火) 23:48
No: 5
(ONLINE)

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

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

Name: しき
[URL]
入門者(3,148 ポイント)
Date: 2017年8月02日(水) 00:13
No: 6
(OFFLINE)

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

指摘ありがとうございます。修正してみます

みけCAT さんが書きました:「ファイルからメモリにデータを全部読み込む→メモリ上のデータを修正(追加or削除)する→修正したメモリ上のデータをファイルに書き込む(上書きする)」

ということは追加する関数と削除する関数をまとめてしまえばいいのでしょうか?
またファイルフォーマットですが何分初心者なもんでよくわからないのですがどう答えたらいいんでしょうか・・
emacsで作成したファイルに数値をうちこんで作りましたとしか言えないです・・。申し訳ありません・・。

Name: みけCAT
[URL]
伝説なるハッカー(670,973 ポイント)
Date: 2017年8月02日(水) 00:17
No: 7
(ONLINE)

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

しき さんが書きました:追加する関数と削除する関数をまとめてしまえばいいのでしょうか?

「まとめてしまえば(無条件に)いい」ということはできませんが、追加と削除で共通する(=共通のコードでやるべき)処理は少なくないでしょう。

しき さんが書きました:またファイルフォーマットですが何分初心者なもんでよくわからないのですがどう答えたらいいんでしょうか・・

実際のファイルに書いてある内容を教えてください。
例えば
コード[Text]: 全て選択
1
{1,6,2,43,123}

なのか、
コード[Text]: 全て選択
1
1 6 2 43 123

なのか、
コード[Text]: 全て選択
1
2
3
4
5
1
6
2
43
123

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

Name: しき
[URL]
入門者(3,148 ポイント)
Date: 2017年8月02日(水) 00:24
No: 8
(OFFLINE)

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

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

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

Name: しき
[URL]
入門者(3,148 ポイント)
Date: 2017年8月02日(水) 03:10
No: 9
(OFFLINE)

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

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


過去トピック 
viewtopic.php?t=11000

Name: shira211
[URL]
かけだし(1,370 ポイント)
Date: 2017年8月03日(木) 14:08
No: 10
(OFFLINE)

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

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

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

Name: かずま
[URL]
Date: 2017年8月03日(木) 15:56
No: 11
(OFFLINE)

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

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

次のプログラムは、質問の問題とは異なり、
wc.out={1,6,2,43,123} が wc.out={5,6,2,43,123} に
なりませんが、削除をこんな風に処理すればどうで
しょうか、という例なので、よく読んで参考にして
みてはいかがでしょうか?
コード[C]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#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;
}

実行例
コード[C]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  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

めざせ、きれいなインデント。

Name: かずま
[URL]
Date: 2017年8月03日(木) 16:03
No: 12
(OFFLINE)

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

すみません。メニューの一部を訂正します。
コード[C]: 全て選択
1
         "  w [file]: write data to file\n"
 を
コード[C]: 全て選択
1
         "  s [file]: save data to file\n"
にしてください。

Name: しき
[URL]
入門者(3,148 ポイント)
Date: 2017年8月04日(金) 00:28
No: 13
(OFFLINE)

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

[解決!]

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

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

かずまさん、ソースコードの提示ありがとうございます。訂正の件も了解です。参考にさせていただきます。あと、きれいなインデントを目指します!

Offtopic :
今回の質問とは関係ないのですが修正した配列は最終的にソートして探索しようかと思っているので、配列の要素の位置はあまり気にしません・・。書き方が悪かったです。



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

Name: かずま
[URL]
Date: 2017年8月13日(日) 17:41
No: 14
(OFFLINE)

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

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

いつの間にか、解決になっていますね。
そういう重要なことは、以前の記事の修正ではなく、
新たな返信にしてください。

結局、ソートはしないのですか?
私としては、末尾への append だけではなく、
先頭への insert も予定していました。
そのソースを付けておきます。
コード[C]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#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[] はリング状に使用します。

Name: かずま
[URL]
Date: 2017年8月13日(日) 17:49
No: 15
(OFFLINE)

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

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

Name: しき
[URL]
入門者(3,148 ポイント)
Date: 2017年8月14日(月) 18:53
No: 16
(OFFLINE)

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

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

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

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

Name: かずま
[URL]
Date: 2017年8月15日(火) 21:21
No: 17
(OFFLINE)

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

かずま さんが書きました:
しき さんが書きました:
コード[C]: 全て選択
1
2
3
4
    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 は不要です。次のように訂正します。
コード[C]: 全て選択
1
    for (i = head; i != tail && data[i] != x; ++i == MAX_SIZE && (i = 0)) ;

コードを丹念に読んで、その意味を理解しようとすれば
勉強になるのに、そうする人はほとんどいないのでしょう。

実は、head と tail と MAX_SIZE さえあれば、size は要らない
とも言えるのですが、これはあったほうが分かりやすいかなと思って、
残しています。

Name: しき
[URL]
入門者(3,148 ポイント)
Date: 2017年8月15日(火) 22:30
No: 18
(OFFLINE)

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

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


Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[11人]