このプログラムが構造体のテキストファイルを読み取れないのはなぜですか? [閉鎖]

このプログラムが構造体のテキストファイルを読み取れないのはなぜですか? [閉鎖]

これは私のa.txtファイルで、合計3行です。余分なスペースや印刷できない文字は含まれません。

David Joans
018976
David12

これはCこのファイルを読み取るために使用するコードです。このコードを読むためにその中に構造を作成しました。パスワード::

#include<stdio.h>
#include<stdlib.h>
        
#pragma pack(1)
        
typedef struct info {
  char name[15];
  int num;
  char pass[15];
}info;
        
int main(int argc, char const* argv[])
{
  FILE* fp = NULL;
  if (fp = fopen("a.txt", "r")) {
    info var;
    fread(&var, 1, sizeof(var), fp);
    printf("%s\n%d\n%s\n", var.name, var.num, var.pass);
  }
  else {
    perror("File can not be opened!!\n");
    exit(EXIT_FAILURE);
  }
  return 0;
}

出力は次のとおりです。

David Joans
018976
David12
171325241
David12

プログラムの実際の問題は何ですか?私が理解するのを手伝ってください。

答え1

ファイルのバイナリ表現は構造体の実際のバイナリ表現と一致する必要はありませんinfo。コンパイラは、構造体フィールド間にパディングスペースを自由に使用できます。したがって、目的の操作を実行する唯一の信頼できる方法は、ファイル内の各フィールドを個別に読み取り、構造内の対応するフィールドに割り当てることです。このような:

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

#pragma pack(1)

typedef struct info {
  char name[15];
  int num;
  char pass[15];
}info;

int main(int argc, char const* argv[])
{
  FILE* fp = NULL;
  if (fp = fopen("a.txt", "r")) {
    info var;
    char num_str[15];
    char *endl_ptr;

    fgets (var.name, sizeof (var.name), fp);
    fgets (num_str, sizeof (num_str), fp);
    fgets (var.pass, sizeof (var.pass), fp);

    /* parse num_str into an integer */
    var.num = strtol(num_str, NULL, 10);

    /* replace the trailing endline character by a NULL */
    if ((endl_ptr = strchr (var.name, '\n')))
        *endl_ptr = '\0';
    if ((endl_ptr = strchr (var.pass, '\n')))
        *endl_ptr = '\0';

    printf("%s\n%d\n%s\n", var.name, var.num, var.pass);
  }
  else {
    perror("File can not be opened!!\n");
    exit(EXIT_FAILURE);
  }
  return 0;
}

あるいは、実際のバイナリ表現が構造のバイナリ表現と一致するファイルがある場合もあります。たとえば、infoすでに構造化されたプログラムでファイルが生成されている場合、単純な構造ファイルはトリックをwrite実行します。ただし、これは他のシステムに移植することはできません。

答え2

ファイルからfread27バイトを読みます。これはすべてで、sizeof(var)がint + 4と2のパディングの場合は2 x 15より大きいためです。fread読み込んだバイト数を返します。通常、この数を確認してください。

freadvoid *ptrそれが何を意味するのか分からない。改行struct infoを削除せずに\0NUL文字で文字列を終了せず、数値文字列をint。占有されたメモリ空間の構造について。

string関数を使用して直接バイトチャンクを解析する必要がありますstrtol(両方のマニュアルページがあります)。したがって、中間配列を読む必要がありますchar buf [80];

出力の最初の3行はフル入力です。幸いなことに、誤ってNUL文字に遭遇してもプログラムは中断されません。

4行目はおそらくintからアクセスされるバイト「976D」ですinfo.num。 CPUがリトルエンディアンなので、バイト順が逆です。

5行目は再アクセスでinfo.pass、ここで入力の最後の行が終わります。

fread(&var, 1, sizeof(var), fp);ファイルから36バイトのデータをインポートし、&varポインタが指定した場所に連続して保存します。 &varがどのような構造を指しているのか、受信領域がどれだけ大きいのかわかりません(または気にしません)。varはいただメモリアドレス - サイズまたはタイプが添付されていません。また、テキストファイルがsizeof(var)

渡すまた訪れるprintf("%s\n%d\n%s\n", var.name, var.num, var.pass);、一部のデータを複数回出力するという意味です。printf構造体の各部分のアドレスを知らせますが、それでも構造体メンバーの種類や長さはわかりません。終了していない文字列をvar.name取得します。みんな入力データ。その後、var.num入力データの16バイト目から始めて、4バイトのテキストを使用し、それを意味のある整数と誤って考えます。その後、var.pass入力のバイト20から再開し、終了していない別の文字列を出力します。

関連情報