C/C++ + SLLIB + SFITSIOによるデータ解析講習会 [Part1] 解答例

山内@天文データセンター

2013年7月 初版
会場: 天文データセンター


課題1

  1. #include <stdio.h>
    
    static void display_2d_array( double *arr_2d[], int n_x, int n_y )
    {
        int i;
        // 2次元配列としてアクセス
        for ( i=0 ; i < n_y ; i++ ) {                   /* 縦方向のループ */
            int j;
            for ( j=0 ; j < n_x ; j++ ) {               /* 横方向のループ */
                printf("[%g]",arr_2d[i][j]);
            }
            printf("\n");
        }
        return;
    }
    
    int main()
    {
        double array[] = {10.0, 11.1, 12.2, 13.3,
                          20.0, 21.1, 22.2, 23.3};  /* この配列を 4x2 として使う */
        double *p[2];                                 /* ポインタ配列 */
        p[0] = &array[0];
        p[1] = &array[4];
        display_2d_array(p,4,2);
    
        return 0;
    }
    
    結果:
    [10][11.1][12.2][13.3]
    [20][21.1][22.2][23.3]
    

課題2

  1. 3. をご覧ください.
  2. 3. をご覧ください.
  3. #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <sys/types.h>
    
    /**
     * @brief  1つの文字列をスキャンし,デリミタで要素へ分割するための情報を取得
     * @param  str スキャン対象の文字列
     * @param  delim デリミタ(文字セット)
     * @param  begin 各要素文字列の先頭位置 (返り値)
     * @param  length 各要素文字列の長さ (返り値)
     * @param  max_n begin[], length[] のサイズ
     * @return  要素の個数
     */
    static size_t sscan_str( const char *str, const char *delim,
                             size_t begin[], size_t length[], size_t max_n )
    {
        size_t ix = 0;                  /* 文字列のパース位置 */
        size_t n_elem = 0;              /* 要素の個数 */
        size_t spn;
    
        /* 最初のデリミタを飛ばす */
        spn = strspn(str + ix, delim);
        ix += spn;
    
        while ( n_elem < max_n ) {
    
            /* 要素部分 */
            spn = strcspn(str + ix, delim);
            if ( spn == 0 ) break;
    
            /* 配列に登録 */
            begin[n_elem] = ix;
            length[n_elem] = spn;
            n_elem ++;
            ix += spn;
    
            /* デリミタを飛ばす */
            spn = strspn(str + ix, delim);
            if ( spn == 0 ) break;
            ix += spn;
        }
    
        return n_elem;
    }
    
    /**
     * @brief  ファイルから必ず1行を読みとる.バッファサイズ以上の部分は捨てられる
     * @param  fp ファイルハンドラ
     * @param  str 1行分を保存するバッファ
     * @param  size_str str[]のバッファサイズ
     * @return  成功した場合は str を返す<br>
     *          EOFまたはエラーの場合 NULL
     */
    static char *fget_str( FILE *fp, char *str, size_t size_str )
    {
        char *ret;
    
        ret = fgets(str, size_str, fp);
    
        if ( ret != NULL ) {
            size_t length = strlen(str);
    
            /* バッファが足りない場合,読み飛ばす */
            if ( 0 < length && str[length-1] != '\n' ) {
                char junk[256];
                char *r;
                while ( (r=fgets(junk,256,fp)) != NULL ) {
                    size_t len = strlen(junk);
                    if ( len == 0 ) break;
                    length += len;
                    if ( junk[len-1] == '\n' ) break;
                }
                fprintf(stderr,"[WARNING] %s: truncated: total length = %zu\n",
                        __FUNCTION__, length);
            }
        }
    
        return ret;
    }
    
    /**
     * @brief  ファイルから1行を読みとり,デリミタで要素へ分割するための情報を取得
     * @param  fp ファイルハンドラ
     * @param  str 1行分を保存するバッファ
     * @param  size_str str[]のバッファサイズ
     * @param  delim デリミタ(文字セット)
     * @param  begin 各要素文字列の先頭位置 (返り値)
     * @param  length 各要素文字列の長さ (返り値)
     * @param  max_n begin[], length[] のサイズ
     * @return  成功した場合,要素の個数<br>
     *          EOFの場合,負値
     */
    static ssize_t fscan_str( FILE *fp, char str[], size_t size_str,
                              const char *delim,
                              size_t begin[], size_t length[], size_t max_n )
    {
        ssize_t ret = -1;
        char *s;
    
        s = fget_str(fp,str,size_str);
    
        if ( s != NULL ) {
            size_t len = strlen(str);
            if ( 0 < len && str[len - 1] == '\n' ) str[len - 1] = '\0';
            ret = sscan_str( str, delim, begin, length, max_n );
        }
    
        return ret;
    }
    
    /**
     * @brief  安全な strncpy() 関数
     * @param  dest コピー先文字列
     * @param  size_dest コピー先文字列バッファの大きさ
     * @param  src 源泉文字列
     * @param  n コピーを行なう文字数
     */
    inline static char *safe_strncpy( char *dest, size_t size_dest, 
                                      const char *src, size_t n )
    {
        n ++;
        if ( n < size_dest ) size_dest = n;
        if ( 0 < size_dest ) {
            const size_t m = size_dest - 1;
            strncpy(dest,src,m);
            dest[m] = '\0';
        }
        return dest;
    }
    
    int main( int argc, char *argv[] )
    {
        int ret_status = -1;
        FILE *fp = NULL;
    
        if ( 1 < argc ) {
            const char *file = argv[1];
            const size_t max_elem = 32;
            size_t begin[max_elem];
            size_t length[max_elem];
            char buf[512];
            ssize_t n;
    
            /* ファイルをオープン */
            fp = fopen(file, "r");
            if ( fp == NULL ) {
                fprintf(stderr,"[ERROR] cannot open: %s\n",file);
                goto quit;
            }
    
            /* 1行ずつスキャン */
            while ( 0 <= (n=fscan_str(fp,buf,512," ",begin,length,max_elem)) ) {
               if ( n == 3 ) {
                   const size_t size_el = 512;
                   char el[size_el];
                   double ra, dec;
                   safe_strncpy(el,size_el, buf + begin[0], length[0]);
                   printf("%s ",el);
                   safe_strncpy(el,size_el, buf + begin[1], length[1]);
                   ra = M_PI * atof(el) / 180.0;
                   safe_strncpy(el,size_el, buf + begin[2], length[2]);
                   dec = M_PI * atof(el) / 180.0;
                   printf("%g %g %g\n",
                          cos(ra)*cos(dec), sin(ra)*cos(dec), sin(dec));
               }
            }
            
        }
    
        ret_status = 0;
     quit:
        if ( fp != NULL ) fclose(fp);
        return ret_status;
    }
    
    実行結果:
    M1 0.10281 0.921371 0.374841
    M2 0.802345 -0.596687 -0.0143679
    M3 -0.793808 -0.379451 0.475275
    M4 -0.365393 -0.816723 -0.4466
    

課題3