2017-12-29 75 views
0

私は、その部分が "、"で区切られた情報を持つcsvファイルを持っています。私がしたいことは、この情報を受け取り、それを別の構造体変数に格納することですが、情報をそこに格納する方法はわかりません。C:データ値を構造体に読み込む

これは私のメインのファイルです:

struct items beer [100]; 

int main(int argc, char **argv) { 
    char *oneline, *tok; 
    char envara[512]; 
    char delim [] = ","; 
    FILE *fp; 
    int i = 0; 
    fp = fopen("varor.csv", "r"); 

    printf("ID\n"); 

    while (!feof(fp)) { 
     if (fp == NULL) { 
      fprintf(stderr, "File varor.csv could not be opened\n"); 
      exit(-1); 
     } 
     fgets(envara, 512, fp); 
     envara[strlen(envara) -1] = '\0'; 

     printf("En rad; %s\n", envara); 

     oneline = strdup(envara); 
     tok = strtok(oneline, delim); 

     while (tok != NULL) { 
      printf("%s\n", tok); 
      tok = strtok(NULL,delim); 
     } 
    } 
    return 0; 
} 

そして、これが私の構造体である:

struct items { 
    int itemnumber; 
    char name [100]; 
    float price; 
    float volyme; 
    char types [100]; 
    char style [100]; 
    char package [20]; 
    char country [20]; 
    char producer [50]; 
    float alcohol_amount; 
}; 
+0

「頻繁に」Cタブ、2番目のエントリ:( –

+0

を見あなたがあなたのトークン化されたラインから構造体のフィールドをロードするためにいくつかの実際のコードを記述する必要があるとしている、ことを修正。 –

+0

あなたはそれをリンクしてもらえますか? – Furiousfuzzy

答えて

3

fgetsを使用して行われるべき行ずつファイルを読み込みます。読み込んだストリームがファイルの終わりにある場合は、NULLポインタを返します。 feofwrongです。

読み込み行をトークン化することはより良い方法ですが、sscanfを使って各行のデータをstruct itemsに抽出することもできます。次のように読むことが私の例を簡単にするために、私はstruct itemsを変更しました:

typedef struct item_t { 
    char name[20]; 
    float weight; 
    unsigned long id; 
    float price; 
} Item; 

あなたはCSVファイル内のヘッダ行を持っていない場合、あなたにシンプルにそれを解析することができます

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

#define MAX_ITEM 5 

typedef struct item_t { 
    char name[20]; 
    float weight; 
    unsigned long id; 
    float price; 
} Item; 

int main() { 
    Item items[MAX_ITEM]; 
    int i = 0, parsedData; 

    char line[512]; 
    FILE* csvFile = fopen("test.csv", "r"); 

    if(csvFile == NULL) { 
     perror("Failed to open file."); 
     exit(EXIT_FAILURE); 
    } 

    while(fgets(line, sizeof(line), csvFile) != NULL && i < MAX_ITEM) { 
     parsedData = sscanf(line, "%20[^,],%f,%lu,%f", 
       items[i].name, &items[i].weight, &items[i].id, &items[i].price); 
     if(parsedData == 4) 
      items[i++].name[19] = '\0'; 
     else 
      fprintf(stderr, "Format error in line: %s\n", line); 
    } 

    fclose(csvFile); 
    return 0; 
} 

私の例では、最初の値にスペースも含めることができます。%20[^,]は、フォーマット文字列の一部を意味します。カンマ文字ではないものを最大20文字読み込みます。

Live Demo

注:sscanf機能を使用することは、多くの方法でオーバーフローや未定義の動作を引き起こす可能性があり、安全ではありません。したがって、フォーマット文字列でCSVファイルのフィールドを解析可能に保ち、sscanf関数のパラメータリストを適切に保つことは、あなたの責任です。私の例では、最初のコンマの前に20文字以上が含まれている場合は現在の行をスキップします。 idに長すぎる数値を指定すると、整数のオーバーフローを防ぐことができません。より安全なコードを書くには、それぞれのフィールドごとに独自の変換関数を作成し、適切な入力チェックを行い、次に例を使用することを検討してください。あなたのstruct itemsを埋めるために、これらの関数を使って行をトークン化します。

+0

そして、最初のカンマの前に19文字以上のデータがあるとどうなりますか? '* scanf()'は厄介です。 –

+0

@AndrewHenle、 '* scanf()'は最初の不一致時に停止しますので、私の例では 'char name [20]'にバッファオーバーフローは発生しませんが、残りのデータは解析されません。とにかく、あなたは正しいです、 '* scanf()'を使うのは最も安全な方法ではありません。私はそれを私の答えの通知として加えました。 – Akira

関連する問題