【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※返信付き投稿の削除は禁止!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら


本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール掲示板2こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.21342

構造体配列の動的確保
投稿者---甚平(2005/06/11 16:56:28)


csv形式のファイルからデータを取得し、格納する領域をmain側
ではなく、関数側で動的に領域確保を行ってmainでは引き渡す
だけで使用しようと思いましたが、2つ目以降のデータがうまく
取れません。
どこが間違っているのでしょうか。

また、関数側で、「DATA **data;」としていますが、ポインタの
ポインタにする必要はあるのでしょうか。
領域解放のfeeも1回ですが問題ないのでしょうか。

------------------------------------
2005,05,01,yamada.taro,100
2005,05,01,yamada.hanako,100
2005,05,02,yamada.hanako,100
2005,05,01,yamada.hanako,100
2005,05,01,yamada.hanako,100
2005,05,01,suzuki.ichiro,100
2005,05,01,sato.jiro,100
2005,05,03,sato.jiro,100

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

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>

typedef struct {
    char *year ;
    char *month ;
    char *day ;
    char *name ;
    long kingaku ;
} DATA ;

int data_sort(DATA **,int *) ;
int comp(const void *, const void *) ;
int data_prn(DATA **,int) ;

main(int argc, char *argv[])
{
    DATA *data ;
    int  tbl_cnt ;
    int ret ;

    tbl_cnt = 0 ;
    ret = data_sort(&data,&tbl_cnt) ;
    if (ret != 0) {
        printf("error\n") ;
        exit(1) ;
    }

    ret = data_prn(&data,tbl_cnt) ;
    if (ret != 0) {
        printf("error\n") ;
        exit(1) ;
    }

   exit(0) ;
}

int data_sort(DATA **data,int *tbl_cnt)
{
    FILE *fp ;
    char buff[1024] ;
    char log_msg[128] ;
    char read_data[256] ;
    char *p ;
    int n = 0 ;
    int size = 1024 ;
    int i ;

    memset(log_msg,'\0',sizeof(log_msg)) ;

    if ((fp = fopen("text.csv","r")) == NULL) {
        printf("FileError : file open failed (%s)\n", "text.csv") ;
        return(-1) ;
    }

    memset(buff,'\0',sizeof(buff)) ;
    (*data) = NULL ;
    while (fgets(buff, sizeof buff, fp)) {

        if ((*data) == NULL || n >= size) {
             (*data) = realloc((*data), (size *= 2) * sizeof(DATA)) ;
             if ((*data) == NULL) {
                 return puts("out of memory"), 1 ;
             }
        }

        p = strtok(buff,",") ;
        (data[n])->year=strdup(p) ;
        p = strtok(NULL,",") ;
        (data[n])->month=strdup(p) ;
        p = strtok(NULL,",") ;
        (data[n])->day=strdup(p) ;
        p = strtok(NULL,",") ;
        (data[n])->name=strdup(p) ;
        p = strtok(NULL,",") ;
        (data[n])->kingaku=atol(p) ;

        n++ ;
    }

    qsort((*data), n, sizeof(DATA), comp) ;

    *tbl_cnt = n ;

    fclose(fp) ;
    return(0) ;
}

int comp(const void *p1, const void *p2)
{
    DATA *a ;
    DATA *b ;
    int diff ;

    a = (DATA *)p1 ;
    b = (DATA *)p2 ;

    diff = strcmp(a->year, b->year) ;
    if (diff == 0) {
        diff = strcmp(a->month, b->month) ;
        if (diff == 0) {
            diff = strcmp(a->day, b->day) ;
            if (diff == 0) {
                diff = strcmp(a->name, b->name) ;
                return diff ;
            }
        }
    }
    return diff ;
}

int data_prn(DATA **data,int tbl_cnt)
{

    int i ;

    for(i=0 ; i<tbl_cnt ; i++) {
        printf("[%s][%s][%s][%s][%ld]\n",
        (data[i])->year,
        (data[i])->month,
        (data[i])->day,
        (data[i])->name,
        (data[i])->kingaku
        ) ;
    }

    free(*(data)) ;

    return(0) ;
}




この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:構造体配列の動的確保 21343 まきじ 2005/06/11 17:17:39
<子記事> Re:構造体配列の動的確保 21348 かずま 2005/06/11 22:27:56


No.21343

Re:構造体配列の動的確保
投稿者---まきじ(2005/06/11 17:17:39)


>(*data) = realloc((*data), (size *= 2) * sizeof(DATA)) ;

領域確保は、malloc を使います。
realloc は、既に確保された領域のサイズを変更する場合に使います。

malloc で、データ件数(行数)分だけDATA 型の配列として
確保すれば良いと思います。

確保しながら、データを格納するのであれば、
1 件目は、mallocで確保し、2 件目以降は、
1 件分のデータのサイズずつ、realloc で増やせば良いと思います。


この投稿にコメントする

削除パスワード

No.21344

Re:構造体配列の動的確保
投稿者---nop(2005/06/11 17:24:16)


>領域確保は、malloc を使います。
>realloc は、既に確保された領域のサイズを変更する場合に使います。

第一引数がNULLの場合のrealloc()は、
malloc()と同一の動作を行います。


この投稿にコメントする

削除パスワード

No.21345

Re:構造体配列の動的確保
投稿者---蛇足(2005/06/11 17:52:33)


>>領域確保は、malloc を使います。
>>realloc は、既に確保された領域のサイズを変更する場合に使います。
>
>第一引数がNULLの場合のrealloc()は、
>malloc()と同一の動作を行います。

そして第二引数が 0 の場合realloc()は
free()と同一の動作を行います。


やってはいけない複合機能関数の典型。



この投稿にコメントする

削除パスワード

No.21347

Re:構造体配列の動的確保
投稿者---RAPT(2005/06/11 19:55:14)


realloc()で第一引数と同じ識別子を左側に書くのは問題があります。

メモリ不足のためブロックを指定されたサイズに拡張できない場合は
元のブロックを変更せず、NULLを返すため、結果として元のメモリは
開放できなくなりメモリリークとなります。

これを回避するには、一度別の識別子でrealloc()の結果を受け、
非NULLの場合、元の識別子に渡すような対処が必要です。

例)
p = realloc(p, 10);

ではなく、
r = realloc(p, 10);
if( r != NULL ){
  p = r;
  //...

のように書くべき。




この投稿にコメントする

削除パスワード

No.21354

Re:構造体配列の動的確保
投稿者---さい(2005/06/12 00:36:18)


以下の様にしてみました。
どうでしょうか。

int data_sort(DATA **data,int *tbl_cnt)
{
    FILE *fp ;
    char buff[1024] ;
    char log_msg[128] ;
    char read_data[256] ;
    char *p ;
    int n = 0 ;
    int size = 1024 ;
    int i ;
    DATA *wk_tbl ;

    memset(log_msg,'\0',sizeof(log_msg)) ;

    if ((fp = fopen("text.csv","r")) == NULL) {
        printf("FileError : file open failed (%s)\n", "text.csv") ;
        return(-1) ;
    }

    memset(buff,'\0',sizeof(buff)) ;
    (*data) = NULL ;
    wk_tbl = NULL
    while (fgets(buff, sizeof buff, fp)) {

        if ((*data) == NULL || n >= size) {

             wk_tbl = realloc((*data), (size *= 2) * sizeof(DATA)) ;
             if (wk_tbl == NULL) {
                 return puts("out of memory"), 1 ;
             } else {
                 *data = wk_tbl ;
             }

        }

        p = strtok(buff,",") ;
        (data[n])->year=strdup(p) ;
        p = strtok(NULL,",") ;
        (data[n])->month=strdup(p) ;
        p = strtok(NULL,",") ;
        (data[n])->day=strdup(p) ;
        p = strtok(NULL,",") ;
        (data[n])->name=strdup(p) ;
        p = strtok(NULL,",") ;
        (data[n])->kingaku=atol(p) ;

        n++ ;
    }

    qsort((*data), n, sizeof(DATA), comp) ;

    *tbl_cnt = n ;

    fclose(fp) ;
    return(0) ;
}




この投稿にコメントする

削除パスワード

No.21360

Re:構造体配列の動的確保
投稿者---甚平(2005/06/12 09:30:27)


RAPTさん、さいさん
ありがとうございます。
試してみます。


この投稿にコメントする

削除パスワード

No.21362

Re:構造体配列の動的確保
投稿者---甚平(2005/06/12 12:17:08)


かずまさん、RAPTさん、さいさん
アドバイスがりがとうございます。
皆さんのアドバイスをもとに、一応、動くものができました。

>if ((*data) == NULL || n >= size) {
ですが、
if (wk_tbl == NULL || n >= size) {
とした方がいいのでしょうか。


この投稿にコメントする

削除パスワード

No.21363

メモリリークとは
投稿者---kokoko(2005/06/12 13:42:28)


>結果として元のメモリは開放できなくなりメモリリークとなります。

どのような状況、状態になるのでしょうか。
プログラムが終了してもメモリは解放されない。
メモリが使える容量が少なくなる。
マシンを再起動しないとメモリは再起動されない。



この投稿にコメントする

削除パスワード

No.21348

Re:構造体配列の動的確保
投稿者---かずま(2005/06/11 22:27:56)


> csv形式のファイルからデータを取得し、格納する領域をmain側
> ではなく、関数側で動的に領域確保を行ってmainでは引き渡す
> だけで使用しようと思いましたが、2つ目以降のデータがうまく
> 取れません。
> どこが間違っているのでしょうか。

data_sort() の中の (data[n])->year=strdup(p) ; は間違い。
(*data)[n].year = strdup(p); です。他も同様。

data_prn() の中の data[i])->year, も間違い。
(*data)[i].year, です。



この投稿にコメントする

削除パスワード

No.21351

Re:構造体配列の動的確保
投稿者---甚平(2005/06/11 23:46:32)


>data_sort() の中の (data[n])->year=strdup(p) ; は間違い。
>(*data)[n].year = strdup(p); です。他も同様。

>data_prn() の中の data[i])->year, も間違い。
>(*data)[i].year, です。

ポインタのポインタを指しているですね。
((*data)+i)->yearと書いてもいいですね。



この投稿にコメントする

削除パスワード

No.21355

教えてください。
投稿者---kokoko(2005/06/12 00:40:59)


mainで、*dataと宣言した変数が
関数に引き渡すとき、ポインタのポインタ(*data)に
なるのですか。

また、参照するとき、
(*data)[n].year = strdup(p); です。他も同様。
((*data)+i)->yearと書いてもいいですね。

となるのですか。



この投稿にコメントする

削除パスワード

No.21361

Re:教えてください。
投稿者---kokoko(2005/06/12 10:58:41)


ポインタのポインタですか。

date:先頭アドレス
*date:アドレス(実体)を格納している先頭アドレス
**date:実体のデータの先頭

つまり、
dateで先頭を指す。
*dateで実体の先頭アドレス指す。
それが、配列だから[i]で指す。



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧