이것은 내 a.txt
파일이며 총 세 줄입니다. 추가 공백이나 인쇄할 수 없는 문자를 포함하지 않습니다.
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
파일에서 fread
27바이트를 읽습니다. 그게 전부이고 sizeof(var)가 int + 4 및 2 패딩의 경우 2 x 15보다 크기 때문입니다. fread
읽은 바이트 수를 반환합니다. 일반적으로 이 수를 확인합니다.
fread
void *ptr
그것이 무엇을 의미하는지 모릅니다. 줄 struct info
바꿈을 제거하지 않고 \0
NUL 문자로 문자열을 종료하지 않으며 숫자 문자열을 int
. 점유된 메모리 공간의 구조에 대해.
string
함수를 사용하여 직접 바이트 청크를 구문 분석 해야 합니다 strtol
(두 가지 모두에 대한 매뉴얼 페이지가 있습니다). 따라서 중간 배열을 읽어야 합니다 char buf [80];
.
출력의 처음 3줄은 전체 입력입니다. 다행히도 실수로 NUL 문자를 만나서 프로그램이 중단되지는 않습니다.
네 번째 줄은 아마도 int 에서 액세스되는 바이트 "976D"일 것입니다 info.num
. CPU가 리틀 엔디안이므로 바이트 순서가 반대입니다.
다섯 번째 줄은 re-accessing 이며 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에서 다시 시작하고 종료되지 않은 또 다른 문자열을 출력합니다.