作業中のメモ

よく「計算機」を使って作業をする.知らなかったことを中心にまとめるつもり.

C 言語による C 言語ファイル操作

どうも,筆者です.

今回は,C 言語を用いて,C 言語ファイルの簡易的な編集を行う.プログラムの勉強であり,実用性は皆無である.

目的

ここでは,C 言語のソースコードを読み込んで,コメントとそれ以外のコードに分けるという操作を行う. ここで,

  1. ソースコード内のタブは読み飛ばす.
  2. スペースは保持する.
  3. コメントは,そのまま出力する.
  4. コメント以外のコードは,指定した文字列以内に収まるように,出力する.この時,改行コードは無視する.

という条件で処理を行う.すなわち,ある程度決まった長さで,コードを区切り,出力するプログラムとなる.

サンプル

今回は,楕円の中心,長軸の長さ,短軸の長さ,回転角の情報を読み取り,構造体に代入するというプログラムを例に,出力結果を示す.

void readPhantom(char *fileName, int numberOfPhantoms, PHANTOM *phantom, int *result){
    FILE *fp;
    int iCnt;
    double paramReal[5];

    if(*result < 0){
        *result = -1;
    }
    else if(NULL == (fp = fopen(fileName, "r"))){
        fprintf(stderr, "%s can't open\n", fileName);
        *result = -1;
    }
    else{
        *result = 1;

        for(iCnt = 0; iCnt < numberOfPhantoms; iCnt++){
            if(
                fscanf(fp, "%lf %lf %lf %lf %lf", &paramReal[0], &paramReal[1], &paramReal[2], &paramReal[3], &paramReal[4]) != 5
            ){
                fprintf(stderr, "%s: format is illegal\n", fileName);
                *result = -1;
                iCnt = numberOfPhantoms;
            }
            else{
                phantom[iCnt].x0 = paramReal[0];
                phantom[iCnt].y0 = paramReal[1];
                phantom[iCnt].A = paramReal[2];
                phantom[iCnt].B = paramReal[3];
                phantom[iCnt].alpha = paramReal[4];
            }
        }
        fclose(fp);
    }
}

これをプログラムに投げると,

void readPhantom(char *fileName, int numberOfPhantoms, PHANTOM *phantom, int *result){FILE *fp;int iCnt;double
paramReal[5];if(*result < 0){*result = -1;}else if(NULL == (fp = fopen(fileName, "r"))){fprintf(stderr, "%s can't open\n", fileName);*result
= -1;}else{*result = 1;for(iCnt = 0; iCnt < numberOfPhantoms; iCnt++){if(fscanf(fp, "%lf %lf %lf %lf %lf", &paramReal[0],
&paramReal[1], &paramReal[2], &paramReal[3], &paramReal[4]) != 5){fprintf(stderr, "%s: format is illegal\n", fileName);*result =
-1;iCnt = numberOfPhantoms;}else{phantom[iCnt].x0 = paramReal[0];phantom[iCnt].y0 = paramReal[1];phantom[iCnt].A =
paramReal[2];phantom[iCnt].B = paramReal[3];phantom[iCnt].alpha = paramReal[4];}}fclose(fp);}}

こうなる.もちろん,コンパイルもできる.

プログラム

たいした処理はしていないが,プログラムがあるので,載せておく.

#include<stdio.h>
#include<stdlib.h>
#define MAX_STRING_LENGTH (128)

typedef unsigned char UI1;

void printString(int iNum, char sz_buf[]);

int main(void){
    int iCnt, iDummy;
    char chReadChar, chComment;
    char sz_buf[MAX_STRING_LENGTH];
    chReadChar = chComment = 0;
    iCnt = iDummy = 0;

    while(EOF != scanf("%c", &chReadChar)){
        /* ヘッダーの出力 */
        if('#' == chReadChar){
            if(iCnt > 0){
                sz_buf[iCnt] = '\0';
                printString(iCnt, sz_buf);
                printf("\n");
                iCnt = 0;
            }

            /* # から始まるものは,改行が出力するまで書き出す */
            while('\n' != chReadChar){
                printf("%c", chReadChar);
                iDummy = scanf("%c", &chReadChar);
            }
            printf("\n");
            continue;
        }

        /* コメントの判定 */
        if('/' == chReadChar){
            iDummy = scanf("%c", &chReadChar);

            if(('*' != chReadChar) && ('/' != chReadChar)){
                if(iCnt + 2 >= (int)MAX_STRING_LENGTH){
                    sz_buf[iCnt] = '\0';
                    printString(iCnt, sz_buf);
                    iCnt = 0;
                }
                sz_buf[iCnt++] = '/';
                sz_buf[iCnt++] = chReadChar;
            }
            else{
                /* 複数行コメントの場合 */
                sz_buf[iCnt] = '\0';
                printString(iCnt, sz_buf);
                printf("\n");
                iCnt = 0;

                if('*' == chReadChar){
                    printf("/");
                    printf("*");
                    chComment = 1;

                    while(1 == chComment){
                        iDummy = scanf("%c", &chReadChar);
                        if('\t' == chReadChar){
                            chReadChar = ' ';
                        }
                        printf("%c", chReadChar);

                        if('*' == chReadChar){
                            iDummy = scanf("%c", &chReadChar);
                            if('\t' == chReadChar){
                                chReadChar = ' ';
                            }
                            printf("%c", chReadChar);

                            if('/' == chReadChar){
                                chComment = 0;
                                printf("\n");
                            }
                        }
                    }
                }
                else{
                    /* 1 行コメントの場合 */
                    printf("//");
                    iDummy = scanf("%c", &chReadChar);
                    while('\n' != chReadChar){
                        printf("%c", chReadChar);
                        iDummy = scanf("%c", &chReadChar);
                    }
                    printf("\n");
                }

            }
        }
        else if('"' == chReadChar){
            sz_buf[iCnt] = '\0';
            printString(iCnt, sz_buf);
            iCnt = 0;

            printf("%c", chReadChar);
            iDummy = scanf("%c", &chReadChar);
            while('"' != chReadChar){
                printf("%c", chReadChar);
                iDummy = scanf("%c", &chReadChar);
            }
            printf("%c", chReadChar);
        }
        else{
            /* 改行文字とタブは読み飛ばす */
            if(('\n' == chReadChar) || ('\t' == chReadChar)){
                continue;
            }
            /* NULL文字を挿入し,文字列を出力 */
            if(iCnt + 2 >= (int)MAX_STRING_LENGTH){
                sz_buf[iCnt] = '\0';
                printString(iCnt, sz_buf);
                iCnt = 0;
            }
            /* 読み込んだ文字列を格納 */
            sz_buf[iCnt++] = chReadChar;
        }
    }
    /* 残った文字列を出力 */
    sz_buf[iCnt] = '\0';
    printf("%s\n", sz_buf);
    iCnt = iDummy;

    return 0;
}

void printString(int iNum, char sz_buf[]){
    int iCnt, iSpaceCnt, isSpacePoint;
    iSpaceCnt = 0;

    /* スペースの数を探索 */
    for(iCnt = 0; iCnt < iNum - 1; iCnt++){
        if(' ' == sz_buf[iCnt]){
            iSpaceCnt++;
            isSpacePoint = iCnt;
        }
    }
    /* スペースが 1 つ以上ある場合 */
    if(iSpaceCnt > 1){
        /* 最後の文字だけ別に出力(途中で文字が切れるのを防ぐため) */
        /*
           int iCnt, iSpaceCnt, isSpacePoint;for(iCnt = 0; iCnt < iNum - 1; iCnt++){if(' ' == sz_bu
           f[iCnt]){iSpaceCnt++;isSpacePoint = iCnt;}}
           とならないようにするため(sz_bu という変数として認識される)
       */
        sz_buf[isSpacePoint] = '\0';
        printf("%s\n", sz_buf);
        printf("%s", &sz_buf[isSpacePoint + 1]);
    }
    /* スペースが 1 つの場合 */
    else{
        /* そのまま出力 */
        printf("%s", sz_buf);
    }

    return;
}

実験

ここでは,前回作成した CSV ファイルを読み出すプログラムを入力し,出力を確認する.まず,ものとプログラムは,以下のようになっている.前回のものをくっつけただけである.

#include<stdio.h>
#include<stdlib.h>

typedef enum {
    RETURN_OK = 0,
    ARGUMENT_ERROR,
    FILE_OPEN_ERROR,
    MALLOC_ERROR
} RETURN_TYPE;

/*
   iCountRowCol: 行数と列数をカウントする

   char *pszFileName:   読み込むファイル名
   unsigned int *piRow: 行数
   unsigned int *piCol: 列数

   return: 正常終了 -> 0
           異常終了 -> 0 以外
 */
int iCountRowCol(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol){
    FILE *prFile;
    int iRet;
    unsigned int uiRow, uiCol;
    char chData;
    iRet = RETURN_OK;

    /* 引数のチェック */
    if((NULL == pszFileName) || (NULL == puiRow) || (NULL == puiCol)){
        fprintf(stderr, "argument error\n");
        iRet = ARGUMENT_ERROR;
        goto EXIT_COUNT_ROWCOL;
    }
    else{
        *puiRow = *puiCol = 0;
    }
    if(NULL == (prFile = fopen(pszFileName, "r"))){
        fprintf(stderr, "Error: %s cannot open\n", pszFileName);
        iRet = FILE_OPEN_ERROR;
        goto EXIT_COUNT_ROWCOL;
    }
    uiRow = uiCol = 0;

    while(EOF != fscanf(prFile, "%c", &chData)){
        /* カンマの場合 */
        if(',' == chData){
            uiCol++;
        }
        /* 改行コードの場合 */
        if('\n' == chData){
            uiCol++;
            uiRow++;
        }
    }
    uiCol /= uiRow;

    *puiRow = uiRow;
    *puiCol = uiCol;
    fclose(prFile);

EXIT_COUNT_ROWCOL:
    return iRet;
}


/*
   iMallocInt:          int 型の malloc を行う

   unsigned int uiSize: 確保するサイズ
   int **ppiArray:      確保先のアドレス

   return: 正常終了 -> 0
           異常終了 -> 0 以外
*/
int iMallocInt(unsigned int uiSize, int **ppiArray){
    unsigned int uiCnt;
    int iRet;
    iRet = RETURN_OK;

    /* 引数チェック */
    if(NULL == ppiArray){
        iRet = ARGUMENT_ERROR;
        goto EXIT_MALLOC_INT;
    }
    /* malloc */
    if(NULL == (*ppiArray = (int *)malloc(sizeof(int) * uiSize))){
        fprintf(stderr, "malloc error\n");
        iRet = MALLOC_ERROR;
        goto EXIT_MALLOC_INT;
    }
    else{
        for(uiCnt = 0; uiCnt < uiSize; uiCnt++){
            (*ppiArray)[uiCnt] = 0;
        }
    }

EXIT_MALLOC_INT:
    return iRet;
}

/*
   freeData: 確保した領域を開放する

   void *pvData: 確保した領域の先頭アドレス
*/
void freeData(void *pvData){
    if(NULL != pvData){
        free(pvData);
    }

    return;
}

/*
   iReadData: データの読み込み

   char *pszFileName:  読み込むファイル名
   unsigned int uiRow: ファイルの行数
   unsigned int uiCol: ファイルの列数
   int *piArray:       データの格納先

   return: 正常終了 -> 0
           異常終了 -> 0 以外
*/
int iReadData(char *pszFileName, unsigned int uiRow, unsigned int uiCol, int *piArray){
    FILE *prFile;
    char chData;
    int iRet;
    unsigned int uiCntRow, uiCntCol, uiCharCnt;
    char achInputDataList[11];
    iRet = RETURN_OK;

    /* 引数のチェック */
    if(NULL == pszFileName){
        iRet = ARGUMENT_ERROR;
        goto EXIT_READ_DATA;
    }

    /* ファイルオープン */
    if(NULL == (prFile = fopen(pszFileName, "r"))){
        fprintf(stderr, "Error: %s cannot open\n", pszFileName);
        iRet = FILE_OPEN_ERROR;
        goto EXIT_READ_DATA;
    }

    /* ファイルの読み込み */
    for(uiCntRow = 0; uiCntRow < uiRow; uiCntRow++){
        for(uiCntCol = 0; uiCntCol < uiCol; uiCntCol++){
            uiCharCnt = 0;
            achInputDataList[0] = '\0';

            /* 1 文字ずつ読み込む  */
            while(EOF != fscanf(prFile, "%c", &chData)){
                /* 「,」または「\n」が来た場合,ループを抜ける */
                if((',' == chData) || ('\n' == chData)){
                    break;
                }

                /* 今回は,数値の部分だけ保存 */
                if(((int)'0' <= (int)chData) && ((int)chData <= (int)'9')){
                    achInputDataList[uiCharCnt++] = chData;
                }
            }
            achInputDataList[uiCharCnt] = '\0';
            piArray[uiCntRow * uiCol + uiCntCol] = atoi(achInputDataList);
        }
    }
    fclose(prFile);

EXIT_READ_DATA:
    return iRet;
}

/*
   iReadCSVFile: CSV ファイルからデータを読み込む

   char *pszFileName:   読み込むファイル名
   unsigned int *piRow: 行数
   unsigned int *piCol: 列数
   int **ppiArray:      確保先のアドレス

   return: 正常終了 -> 0
           異常終了 -> 0 以外
*/
int iReadCSVFile(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol, int **ppiArray){
    int iRet;
    unsigned int uiSize = 0;

    iRet = iCountRowCol(pszFileName, puiRow, puiCol);
    if(RETURN_OK != iRet){
        fprintf(stderr, "Error: iCountRowCol\n");
        goto EXIT_READ_CSV_FILE;
    }

    uiSize = (*puiRow) * (*puiCol);
    iRet = iMallocInt(uiSize, ppiArray);
    if(RETURN_OK != iRet){
        fprintf(stderr, "Error: iMallocInt\n");
        goto EXIT_READ_CSV_FILE;
    }

    iRet = iReadData(pszFileName, *puiRow, *puiCol, *ppiArray);
    if(RETURN_OK != iRet){
        fprintf(stderr, "Error: iReadData\n");
        goto EXIT_READ_CSV_FILE;
    }

EXIT_READ_CSV_FILE:
    return iRet;
}

void printData(unsigned int uiRow, unsigned int uiCol, int *piArray){
    unsigned int uiCntRow, uiCntCol;

    for(uiCntRow = 0; uiCntRow < uiRow; uiCntRow++){
        for(uiCntCol = 0; uiCntCol < uiCol; uiCntCol++){
            printf("%d ", piArray[uiCntRow * uiCol + uiCntCol]);
        }
        printf("\n");
    }
}

int main(int iArgCnt, char **ppchArgVec){
    int iRet;
    unsigned int uiRow, uiCol;
    int *piArray;

    if(iArgCnt == 2){
        iRet = iReadCSVFile(ppchArgVec[1], &uiRow, &uiCol, &piArray);

        if(iRet == RETURN_OK){
            printData(uiRow, uiCol, piArray);
            freeData((void *)piArray);
        }
    }

    return 0;
}

次に,プログラムにより出力したコードを示す.

#include<stdio.h>
#include<stdlib.h>
typedef enum {RETURN_OK = 0,ARGUMENT_ERROR,FILE_OPEN_ERROR,MALLOC_ERROR}
RETURN_TYPE;
/*
 iCountRowCol: 行数と列数をカウントする

 char *pszFileName:   読み込むファイル名
 unsigned int *piRow: 行数
 unsigned int *piCol: 列数

 return: 正常終了 -> 0
         異常終了 -> 0 以外
 */
int iCountRowCol(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol){FILE *prFile;int iRet;unsigned int uiRow,
uiCol;char chData;iRet =
RETURN_OK;
/* 引数のチェック */
if((NULL == pszFileName) || (NULL == puiRow) || (NULL ==
puiCol)){fprintf(stderr, "argument error\n");iRet = ARGUMENT_ERROR;goto EXIT_COUNT_ROWCOL;}else{*puiRow = *puiCol = 0;}if(NULL == (prFile =
fopen(pszFileName, "r"))){fprintf(stderr, "Error: %s cannot open\n", pszFileName);iRet = FILE_OPEN_ERROR;goto EXIT_COUNT_ROWCOL;}uiRow = uiCol = 0;while(EOF !=
fscanf(prFile, "%c", &chData)){
/* カンマの場合 */
if(',' ==
chData){uiCol++;}
/* 改行コードの場合 */
if('\n' == chData){uiCol++;uiRow++;}}uiCol /= uiRow;*puiRow = uiRow;*puiCol = uiCol;fclose(prFile);EXIT_COUNT_ROWCOL:return
iRet;}
/*
 iMallocInt:          int 型の malloc を行う

 unsigned int uiSize: 確保するサイズ
 int **ppiArray:      確保先のアドレス

 return: 正常終了 -> 0
         異常終了 -> 0 以外
*/
int iMallocInt(unsigned int uiSize, int **ppiArray){unsigned int uiCnt;int iRet;iRet =
RETURN_OK;
/* 引数チェック */
if(NULL == ppiArray){iRet = ARGUMENT_ERROR;goto
EXIT_MALLOC_INT;}
/* malloc */
if(NULL == (*ppiArray = (int *)malloc(sizeof(int) *
uiSize))){fprintf(stderr, "malloc error\n");iRet = MALLOC_ERROR;goto EXIT_MALLOC_INT;}else{for(uiCnt = 0; uiCnt < uiSize; uiCnt++){(*ppiArray)[uiCnt] =
0;}}EXIT_MALLOC_INT:return iRet;}
/*
 freeData: 確保した領域を開放する

 void *pvData: 確保した領域の先頭アドレス
*/
void freeData(void *pvData){if(NULL !=
pvData){free(pvData);}return;}
/*
 iReadData: データの読み込み

 char *pszFileName:  読み込むファイル名
 unsigned int uiRow: ファイルの行数
 unsigned int uiCol: ファイルの列数
 int *piArray:       データの格納先

 return: 正常終了 -> 0
         異常終了 -> 0 以外
*/
int iReadData(char *pszFileName, unsigned int uiRow, unsigned int uiCol, int *piArray){FILE *prFile;char chData;int
iRet;unsigned int uiCntRow, uiCntCol, uiCharCnt;char achInputDataList[11];iRet =
RETURN_OK;
/* 引数のチェック */
if(NULL == pszFileName){iRet = ARGUMENT_ERROR;goto
EXIT_READ_DATA;}
/* ファイルオープン */
if(NULL == (prFile =
fopen(pszFileName, "r"))){fprintf(stderr, "Error: %s cannot open\n", pszFileName);iRet = FILE_OPEN_ERROR;goto
EXIT_READ_DATA;}
/* ファイルの読み込み */
for(uiCntRow = 0; uiCntRow < uiRow; uiCntRow++){for(uiCntCol = 0; uiCntCol < uiCol; uiCntCol++){uiCharCnt =
0;achInputDataList[0] =
'\0';
/* 1 文字ずつ読み込む  */
while(EOF !=
fscanf(prFile, "%c", &chData)){
/* 「,」または「\n」が来た場合,ループを抜ける */
if((',' == chData) || ('\n' ==
chData)){break;}
/* 今回は,数値の部分だけ保存 */
if(((int)'0' <= (int)chData) && ((int)chData <= (int)'9')){achInputDataList[uiCharCnt++] =
chData;}}achInputDataList[uiCharCnt] = '\0';piArray[uiCntRow * uiCol + uiCntCol] = atoi(achInputDataList);}}fclose(prFile);EXIT_READ_DATA:return
iRet;}
/*
 iReadCSVFile: CSV ファイルからデータを読み込む

 char *pszFileName:   読み込むファイル名
 unsigned int *piRow: 行数
 unsigned int *piCol: 列数
 int **ppiArray:      確保先のアドレス

 return: 正常終了 -> 0
         異常終了 -> 0 以外
*/
int iReadCSVFile(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol, int **ppiArray){int iRet;unsigned int uiSize
= 0;iRet = iCountRowCol(pszFileName, puiRow, puiCol);if(RETURN_OK !=
iRet){fprintf(stderr, "Error: iCountRowCol\n");goto EXIT_READ_CSV_FILE;}uiSize = (*puiRow) * (*puiCol);iRet = iMallocInt(uiSize, ppiArray);if(RETURN_OK !=
iRet){fprintf(stderr, "Error: iMallocInt\n");goto EXIT_READ_CSV_FILE;}iRet = iReadData(pszFileName, *puiRow, *puiCol, *ppiArray);if(RETURN_OK !=
iRet){fprintf(stderr, "Error: iReadData\n");goto EXIT_READ_CSV_FILE;}EXIT_READ_CSV_FILE:return iRet;}void printData(unsigned int uiRow, unsigned int uiCol, int
*piArray){unsigned int uiCntRow, uiCntCol;for(uiCntRow = 0; uiCntRow < uiRow; uiCntRow++){for(uiCntCol = 0; uiCntCol < uiCol;
uiCntCol++){printf("%d ", piArray[uiCntRow * uiCol +
uiCntCol]);}printf("\n");}}int main(int iArgCnt, char **ppchArgVec){int iRet;unsigned int uiRow, uiCol;int *piArray;if(iArgCnt == 2){iRet =
iReadCSVFile(ppchArgVec[1], &uiRow, &uiCol, &piArray);if(iRet == RETURN_OK){printData(uiRow, uiCol, piArray);freeData((void
*)piArray);}}return 0;}

少し読みにくいが,これでもちゃんとコンパイルがとおり,実行結果も一致する.次回何か書くことがあったら,もっと実用的なものを作成したい.

CSV ファイルを C 言語で読み込む

どうも,筆者です.

今回は,CSV ファイルを C 言語で読み込むことを考える.

考え方

カンマ(,)か改行コード(\n)が出てくるまで,データを char 型の配列に保持する.カンマ(,)か改行コード(\n)が出てきたら,atoi または,atof 関数で数値に変換する. この時,行数と列数が分からないので,一度ファイルの終端コード(EOF)が出てくるまで読み続ける.その後,先頭に戻って再度処理をするという流れになる.

プログラム

まず,戻り値の処理をするため,ヘッダに列挙型を定義する.

/* defineConstant.h */
#ifndef __DEFINECONSTANT_H__
#define __DEFINECONSTANT_H__

typedef enum {
    RETURN_OK = 0,
    ARGUMENT_ERROR,
    FILE_OPEN_ERROR,
    MALLOC_ERROR
} RETURN_TYPE;

#endif

次に,行数と列数をカウントするプログラムを作成する.

#include"defineConstant.h"
/*
   iCountRowCol: 行数と列数をカウントする

   char *pszFileName:   読み込むファイル名
   unsigned int *piRow: 行数
   unsigned int *piCol: 列数

   return: 正常終了 -> 0
           異常終了 -> 0 以外
 */
int iCountRowCol(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol){
    FILE *prFile;
    int iRet;
    unsigned int uiRow, uiCol;
    char chData;
    iRet = RETURN_OK;

    /* 引数のチェック */
    if((NULL == pszFileName) || (NULL == puiRow) || (NULL == puiCol)){
        fprintf(stderr, "argument error\n");
        iRet = ARGUMENT_ERROR;
        goto EXIT_COUNT_ROWCOL;
    }
    else{
        *puiRow = *puiCol = 0;
    }
    if(NULL == (prFile = fopen(pszFileName, "r"))){
        fprintf(stderr, "Error: %s cannot open\n", pszFileName);
        iRet = FILE_OPEN_ERROR;
        goto EXIT_COUNT_ROWCOL;
    }
    uiRow = uiCol = 0;

    while(EOF != fscanf(prFile, "%c", &chData)){
        /* カンマの場合 */
        if(',' == chData){
            uiCol++;
        }
        /* 改行コードの場合 */
        if('\n' == chData){
            uiCol++;
            uiRow++;
        }
    }
    uiCol /= uiRow;

    *puiRow = uiRow;
    *puiCol = uiCol;
    fclose(prFile);

EXIT_COUNT_ROWCOL:
    return iRet;
}

その後,必要なサイズを malloc する関数を定義する.ここでは,int 型で確保する.同時に,領域を開放する関数も書く.

/*
   iMallocInt:          int 型の malloc を行う

   unsigned int uiSize: 確保するサイズ
   int **ppiArray:      確保先のアドレス

   return: 正常終了 -> 0
           異常終了 -> 0 以外
*/
int iMallocInt(unsigned int uiSize, int **ppiArray){
    unsigned int uiCnt;
    int iRet;
    iRet = RETURN_OK;

    /* 引数チェック */
    if(NULL == ppiArray){
        iRet = ARGUMENT_ERROR;
        goto EXIT_MALLOC_INT;
    }
    /* malloc */
    if(NULL == (*ppiArray = (int *)malloc(sizeof(int) * uiSize))){
        fprintf(stderr, "malloc error\n");
        iRet = MALLOC_ERROR;
        goto EXIT_MALLOC_INT;
    }
    else{
        for(uiCnt = 0; uiCnt < uiSize; uiCnt++){
            (*ppiArray)[uiCnt] = 0;
        }
    }

EXIT_MALLOC_INT:
    return iRet;
}

/*
   freeData: 確保した領域を開放する

   void *pvData: 確保した領域の先頭アドレス
*/
void freeData(void *pvData){
    if(NULL != pvData){
        free(pvData);
    }

    return;
}

最後に,データを解析し,読み込んでいく.

/*
   iReadData: データの読み込み

   char *pszFileName:  読み込むファイル名
   unsigned int uiRow: ファイルの行数
   unsigned int uiCol: ファイルの列数
   int *piArray:       データの格納先

   return: 正常終了 -> 0
           異常終了 -> 0 以外
*/
int iReadData(char *pszFileName, unsigned int uiRow, unsigned int uiCol, int *piArray){
    FILE *prFile;
    char chData;
    int iRet;
    unsigned int uiCntRow, uiCntCol, uiCharCnt;
    char achInputDataList[11];
    iRet = RETURN_OK;

    /* 引数のチェック */
    if(NULL == pszFileName){
        iRet = ARGUMENT_ERROR;
        goto EXIT_READ_DATA;
    }

    /* ファイルオープン */
    if(NULL == (prFile = fopen(pszFileName, "r"))){
        fprintf(stderr, "Error: %s cannot open\n", pszFileName);
        iRet = FILE_OPEN_ERROR;
        goto EXIT_READ_DATA;
    }

    /* ファイルの読み込み */
    for(uiCntRow = 0; uiCntRow < uiRow; uiCntRow++){
        for(uiCntCol = 0; uiCntCol < uiCol; uiCntCol++){
            uiCharCnt = 0;
            achInputDataList[0] = '\0';

            /* 1 文字ずつ読み込む  */
            while(EOF != fscanf(prFile, "%c", &chData)){
                /* 「,」または「\n」が来た場合,ループを抜ける */
                if((',' == chData) || ('\n' == chData)){
                    break;
                }

                /* 今回は,数値の部分だけ保存 */
                if(((int)'0' <= (int)chData) && ((int)chData <= (int)'9')){
                    achInputDataList[uiCharCnt++] = chData;
                }
            }
            achInputDataList[uiCharCnt] = '\0';
            piArray[uiCntRow * uiCol + uiCntCol] = atoi(achInputDataList);
        }
    }
    fclose(prFile);

EXIT_READ_DATA:
    return iRet;
}

これで,CSV ファイルからデータを読み込み,格納することができる.後は,これをまとめて行う関数を定義する.

/*
   iReadCSVFile: CSV ファイルからデータを読み込む

   char *pszFileName:   読み込むファイル名
   unsigned int *piRow: 行数
   unsigned int *piCol: 列数
   int **ppiArray:      確保先のアドレス

   return: 正常終了 -> 0
           異常終了 -> 0 以外
*/
int iReadCSVFile(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol, int **ppiArray){
    int iRet;
    unsigned int uiSize = 0;

    iRet = iCountRowCol(pszFileName, puiRow, puiCol);
    if(RETURN_OK != iRet){
        fprintf(stderr, "Error: iCountRowCol\n");
        goto EXIT_READ_CSV_FILE;
    }

    uiSize = (*puiRow) * (*puiCol);
    iRet = iMallocInt(uiSize, ppiArray);
    if(RETURN_OK != iRet){
        fprintf(stderr, "Error: iMallocInt\n");
        goto EXIT_READ_CSV_FILE;
    }

    iRet = iReadData(pszFileName, *puiRow, *puiCol, *ppiArray);
    if(RETURN_OK != iRet){
        fprintf(stderr, "Error: iReadData\n");
        goto EXIT_READ_CSV_FILE;
    }

EXIT_READ_CSV_FILE:
    return iRet;
}

確認

このファイルを readCSVFile.c として保存し,正しく動作するか確認する.main 関数は,以下のようにした.

#include<stdio.h>
#include<stdlib.h>
#include"defineConstant.h"

extern int iReadCSVFile(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol, int **ppiArray);
extern void freeData(void *pvData);
void printData(unsigned int uiRow, unsigned int uiCol, int *piArray);

int main(int iArgCnt, char **ppchArgVec){
    int iRet;
    unsigned int uiRow, uiCol;
    int *piArray;

    if(iArgCnt == 2){
        iRet = iReadCSVFile(ppchArgVec[1], &uiRow, &uiCol, &piArray);

        if(iRet == RETURN_OK){
            printData(uiRow, uiCol, piArray);
            freeData((void *)piArray);
        }
    }

    return 0;
}

void printData(unsigned int uiRow, unsigned int uiCol, int *piArray){
    unsigned int uiCntRow, uiCntCol;

    for(uiCntRow = 0; uiCntRow < uiRow; uiCntRow++){
        for(uiCntCol = 0; uiCntCol < uiCol; uiCntCol++){
            printf("%d ", piArray[uiCntRow * uiCol + uiCntCol]);
        }
        printf("\n");
    }
}

CSV ファイルは,以下のようなものを作成した.

01,02,03,04,05,06,07,08,09,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

実行結果は,以下のようになった.

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 

正しく動作している.

楕円が存在する領域

どうも,筆者です.

楕円を覆う領域

今回は,有限個の楕円が平面状に散らばっている状況を考える.この状況において,すべての楕円を含む長方形領域の最小値を求める問題を解く. 図で示すと以下のような長方形領域を求めることになる.

領域の計算方法

計算方法として,以下のような楕円ごとの長方形の領域を考えた.

この図において,楕円の方程式は,

 { \displaystyle
  \begin{equation}
    \dfrac{x^{2}}{a^{2}} + \dfrac{y^{2}}{b^{2}} = 1
  \end{equation}
}

で与えられる.ここで, {0 \leq b \leq a} である.また,媒介変数  {\theta} を用いると,楕円上の点  {(x, y)} は,

 { \displaystyle
  \begin{equation}
    \left\{
    \begin{array}{ccc}
      x & = & a\cos{\theta}\\
      y & = & b\sin{\theta}\\
    \end{array}
    \right.
  \end{equation}
}

となる.

この時,楕円を  {\phi} だけ回転させた場合,移動後の点  {(X, Y)} は,回転行列を用いて,

 { \displaystyle
  \begin{eqnarray}
    \left(
    \begin{array}{c}
      X\\
      Y\\
    \end{array}
    \right) & = & \left(
    \begin{array}{cc}
       \cos{\phi} & \sin{\phi}\\
      -\sin{\phi} & \cos{\phi}\\
    \end{array}
    \right)\left(
    \begin{array}{c}
      x\\
      y\\
    \end{array}
    \right)\\
    & = & \left(
    \begin{array}{cc}
      \cos{\phi} & \sin{\phi}\\
      -\sin{\phi} & \cos{\phi}\\
    \end{array}
    \right)\left(
    \begin{array}{c}
      a\cos{\theta}\\
      b\sin{\theta}\\
    \end{array}
    \right)\\
    & = & \left(
    \begin{array}{c}
      a\cos{\phi}\cos{\theta} + b\sin{\phi}\sin{\theta}\\
      b\cos{\phi}\sin{\theta} - a\sin{\phi}\cos{\theta}\\
    \end{array}
    \right)
  \end{eqnarray}
}

となる.さらに,三角関数の合成を用いて,

 { \displaystyle
  \begin{eqnarray}
    X & = & \sqrt{a^{2}\cos^{2}{\phi} + b^{2}\sin^{2}{\phi}}\cos{\left( \theta - \gamma_{X} \right)}\\
    Y & = & \sqrt{b^{2}\cos^{2}{\phi} + a^{2}\sin^{2}{\phi}}\sin{\left( \theta - \gamma_{Y} \right)}
  \end{eqnarray}
}

と表せる.ここで,

 { \displaystyle
  \begin{eqnarray}
    \cos{\gamma_{X}} & = & \dfrac{a\cos{\phi}}{\sqrt{a^{2}\cos^{2}{\phi} + b^{2}\sin^{2}{\phi}}}\\
    \sin{\gamma_{X}} & = & \dfrac{b\sin{\phi}}{\sqrt{a^{2}\cos^{2}{\phi} + b^{2}\sin^{2}{\phi}}}\\
    \cos{\gamma_{Y}} & = & \dfrac{b\cos{\phi}}{\sqrt{b^{2}\cos^{2}{\phi} + a^{2}\sin^{2}{\phi}}}\\
    \sin{\gamma_{Y}} & = & \dfrac{a\sin{\phi}}{\sqrt{b^{2}\cos^{2}{\phi} + a^{2}\sin^{2}{\phi}}}
  \end{eqnarray}
}

である.

よって, {X, Y} がそれぞれ最大となる時が,求める長方形領域の半分の長さとなるので, {\ell_{x}, \ell_{y}} は,

 { \displaystyle
  \begin{eqnarray}
    \ell_{x} & = & \sqrt{a^{2}\cos^{2}{\phi} + b^{2}\sin^{2}{\phi}}\\
    \ell_{y} & = & \sqrt{b^{2}\cos^{2}{\phi} + a^{2}\sin^{2}{\phi}}
  \end{eqnarray}
}

となる.

C プログラム

後は,この結果をプログラムに落とすだけである.ここでは,以下のような図を考える.

この図のように,それぞれの楕円に外接する長方形を計算し,原点から最も遠くなる位置を求める.以下に,プログラムを示す.

これで,図に示した青色の領域を求めることができる.

関連記事のサムネイルを表示する

どうも,筆者です.

以前,ブログの見た目を変更しようと思い,関連記事を実装した.その際,サムネイル画像が表示されなかったが,先日,修正方法が記事になっていた.

shota-natuta.hatenablog.com

こちらを参考に再度修正を行った.

ヘッダの修正

Java Script は,普段使わないので,間違えないように修正する.以下は,上記のサイトの一部引用である.

var title = el.find('title').text(); //ブログタイトル
var articleLink = el.find('link').attr('href'); //ブログタイトル
var overview = el.find('summary').text(); //ブログ概要

そして,記事を参考に,imgSrc を articleLink の下に挿入する.後で見たときに分かるように,ブログイメージとコメントを入れておいた.

var title = el.find('title').text(); //ブログタイトル
var articleLink = el.find('link').attr('href'); //ブログタイトル
var imgSrc = el.find('link[type="image/png"]').attr('href'); //ブログイメージ ←追加部分
var overview = el.find('summary').text(); //ブログ概要

最後に,html の部分をサイトの通り,書き換える.この部分は,サイトのものをそのままコピペした.

変更後

デザインの変更をした結果,以下のようになった.

修正したことで,問題なく動作しているようだ.良かった.

ブログの見た目を改善

どうも,筆者です.

ブログの見た目を変更していると,あれも欲しいこれも欲しいって思うようになってくる.ということで,他のすばらしいサイトを参考にしながら,設定を行う.

関連記事

色々なブログを見ていると,関連記事が表示されていることに気付く.これは,設定したいと思い,調べた.以下のサイトで,コードが公開されていたので,記事の数だけ変更して利用させていただいた.

shota-natuta.hatenablog.com

この時,何故か目次の設定(自動生成してくれる JS)が,「記事の下」に HTML で記述されていたので,「記事の上」に移動させておいた.

アイキャッチ画像(サムネイル画像)

関連記事を導入したところで,多少便利になったが,サムネイル画像が表示されないことに気付いた.これも設定していなかったようなので,以下の記事を参考にしながら,設定を行った.

happylife-tsubuyaki.hatenablog.com

サムネイル画像は Inkscape で作成し,アップロードすることにした.ただ,上手に作れないのが難点である.