C 如何从文件中获取替代行并将其作为字符串存储到结构中?
我有一个文件需要通过代码读取。该文件如下所示。文件的第一行包含一个整数,表示文件中日记账分录的数量。我需要编写一个C程序来读取文件并将内容存储在动态分配的结构数组中C 如何从文件中获取替代行并将其作为字符串存储到结构中?,c,string,file,struct,io,C,String,File,Struct,Io,我有一个文件需要通过代码读取。该文件如下所示。文件的第一行包含一个整数,表示文件中日记账分录的数量。我需要编写一个C程序来读取文件并将内容存储在动态分配的结构数组中 4 12/04/2010 Interview went well I think, though was told to wear shoes. 18/04/2010 Doc advised me to concentrate on something... I forget. 03/05/2010 Was asked to
4
12/04/2010
Interview went well I think, though was told to wear shoes.
18/04/2010
Doc advised me to concentrate on something... I forget.
03/05/2010
Was asked today if I was an art exhibit.
19/05/2010
Apparently mudcakes not made of mud, or angry wasps.
我能够在struct中存储strok()的日期、月份和年份,但是我一直在将字符串保存到struct中。
这是我的strtok()代码
程序没有使用strcpy(),当我运行它时,它不断崩溃。但是,如果删除strcpy(),它将按如下方式打印:
12
Interview went well I think, though was told to wear shoes.
18
Doc advised me to concentrate on something... I forget.
03
Was asked today if I was an art exhibit.
19
Apparently mudcakes not made of mud, or angry wasps.
这不是我想要存储在结构中的字符串。我被困在如何将字符串存储到结构中。我的结构是
typedef struct journal{
int day;
int month;
int year;
char entry[1024];
} Diary;
任何善良的灵魂都能告诉我哪里不对吗?以下建议代码:
#include <stdio.h>
#include <stdlib.h>
#define MAX_LINE_LEN 1024
struct journal
{
int day;
int month;
int year;
char entry[ MAX_LINE_LEN ];
};
typedef struct journal Diary;
int main( void )
{
FILE* file=fopen("struct.txt","r");
if ( !file )
{
perror("fopen failed");}
exit( EXIT_FAILURE );
}
// implied else, fopen successful
char line[ MAX_LINE_LEN ];
int size;
if( fgets( line, sizeof line, file ) )
{
if ( sscanf( line, "%d", size ) != 1 )
{
fprintf( stderr, "scanf for data count failed\m" );
exit( EXIT_FAILURE );
}
// implied else, input of data count successful
}
else
{
perror( "fgets for data count failed" );
exit( EXIT_FAILURE );
}
// implied else, fgets successful
Diary myDiary[ size ]; // uses VLA (variable length array feature of C
size_t i = 0;
char *token = NULL;
while( i < size && fgets( line, sizeof( line ), file) )
{
token = strtok( line, "/" );
if( token )
{
myDiary[i].day = atoi( token );
token = strtok( NULL, "/" );
if( token )
{
myDiary[i].month = atoi( token );
token = strtok( NULL, "/" );
if( token )
{
myDiary[i].year = atoi( token );
// input data directly into struct instance
fgets( myDiary[i].entry, MAX_LINE_LEN, file );
}
}
}
i++;
}
}
#include <stdio.h>
#include <stdlib.h>
#define MAX_LINE_LEN 1024
struct journal
{
int day;
int month;
int year;
char entry[ MAX_LINE_LEN ];
};
typedef struct journal Diary;
int main( void )
{
FILE* file=fopen("struct.txt","r");
if ( !file )
{
perror("fopen failed");}
exit( EXIT_FAILURE );
}
// implied else, fopen successful
char line[ MAX_LINE_LEN ];
int size;
if( fgets( line, sizeof line, file ) )
{
if ( sscanf( line, "%d", size ) != 1 )
{
fprintf( stderr, "scanf for data count failed\m" );
exit( EXIT_FAILURE );
}
// implied else, input of data count successful
}
else
{
perror( "fgets for data count failed" );
exit( EXIT_FAILURE );
}
// implied else, fgets successful
Diary myDiary[ size ]; // uses VLA (variable length array feature of C
size_t i = 0;
char *token = NULL;
while( i < size && fgets( line, sizeof( line ), file) )
{
token = strtok( line, "/" );
if( token )
{
myDiary[i].day = atoi( token );
token = strtok( NULL, "/" );
if( token )
{
myDiary[i].month = atoi( token );
token = strtok( NULL, "/" );
if( token )
{
myDiary[i].year = atoi( token );
// input data directly into struct instance
fgets( myDiary[i].entry, MAX_LINE_LEN, file );
}
}
}
i++;
}
}
#包括
#包括
#定义最大线长度1024
结构日志
{
国际日;
整月;
国际年;
字符输入[最大行长度];
};
typedef结构日志;
内部主(空)
{
FILE*FILE=fopen(“struct.txt”、“r”);
如果(!文件)
{
perror(“fopen失败”);}
退出(退出失败);
}
//否则,fopen成功了
字符行[MAX_line_LEN];
整数大小;
if(fgets(行、行大小、文件))
{
如果(sscanf(行,“%d”,大小)!=1)
{
fprintf(stderr,“扫描数据计数失败\m”);
退出(退出失败);
}
//否则,数据计数输入成功
}
其他的
{
perror(“数据计数的FGET失败”);
退出(退出失败);
}
//否则,fgets将获得成功
日记我的日记[大小];//使用VLA(C的可变长度数组功能
尺寸i=0;
char*token=NULL;
而(i
您的问题提出了一个经典问题:“当我事先不知道有多少时,如何读取和分配某物的X号?”这实际上是一个更简单的问题,因为您可以从数据文件中读取X
号作为第一行
(在阅读第一行之后,这将问题简化为单个X结构的分配-否则您需要根据需要跟踪当前分配的结构数量和realloc
)
首先,我建议不要创建char条目[1024];
在您的结构中,有两个原因-第一,在堆栈上创建了条目的自动存储,并且一个大的日志很容易堆栈溢出…第二,这只是浪费。如果目标是动态分配,那么只分配每个条目所需的存储。您可以声明一个1024的缓冲区
char用作读取缓冲区,但随后仅分配strlen(buf)+1
char来保存条目(从条目中修剪包含的'\n'
后)
问题的其余部分是任何可靠代码的基础,只是验证每次读取、每次解析和每次分配,以确保您处理的是有效数据,并在整个代码中拥有有效存储。这适用于您编写的每一段代码,而不仅仅是此问题
将这些部分放在一起,并在下面的评论中提供进一步的详细信息,您可以执行以下操作:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct journal {
int day,
month,
year;
char *entry; /* declare a pointer, allocate only need No. of chars */
} diary_t;
#define MAXLENGTH 1024 /* max read buf for diary entry */
int main (int argc, char **argv) {
size_t entries = 0, i, n = 0;
char buf[MAXLENGTH] = "";
diary_t *diary = NULL;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* read first line, parse number of entries */
if (!(fgets (buf, MAXLENGTH, fp)) || /* validate read */
sscanf (buf, "%zu", &entries) != 1) { /* validate conversion */
fputs ("error: failed to read 1st line.\n", stderr);
return 1;
}
/* allocate/validate entries number of diary_t */
if (!(diary = calloc (entries, sizeof *diary))) {
perror ("calloc-diary_pointers");
return 1;
}
for (i = 0; i < entries; i++) { /* loop No. entries times */
size_t len = 0;
if (!fgets (buf, MAXLENGTH, fp)) { /* read/validate date */
fprintf (stderr, "error: failed to read date %zu.\n", i);
return 1;
}
if (sscanf (buf, "%d/%d/%d", /* parse into day, month, year */
&diary[i].day, &diary[i].month, &diary[i].year) != 3) {
fprintf (stderr, "error failed to parse date %zu.\n", i);
return 1;
}
if (!fgets (buf, MAXLENGTH, fp)) { /* read entry */
fprintf (stderr, "error: failed to read entry %zu.\n", i);
return 1;
}
len = strlen (buf); /* get length */
if (len && buf[len - 1] == '\n') /* check last char is '\n' */
buf[--len] = 0; /* overwrite with nul-character */
else if (len == MAXLENGTH - 1) { /* check entry too long */
fprintf (stderr, "error: entry %zu exceeds MAXLENGTH.\n", i);
return 1;
}
/* allocate/validate memory for entry */
if (!(diary[i].entry = malloc ((len + 1)))) {
perror ("malloc-diary_entry");
fprintf (stderr, "error: memory exausted, entry[%zu].\n", i);
break; /* out of memory error, don't exit, just break */
}
strcpy (diary[i].entry, buf); /* copy buf to entry */
n++; /* increment successful entry read */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (i = 0; i < n; i++) { /* output diary entries */
printf ("entry[%2zu]: %2d/%2d/%4d - %s\n", i, diary[i].day,
diary[i].month, diary[i].year, diary[i].entry);
free (diary[i].entry); /* don't forget to free entries */
}
free (diary); /* don't forget to free diary */
return 0;
}
示例使用/输出
$ ./bin/diary <dat/diary.txt
entry[ 0]: 12/ 4/2010 - Interview went well I think, though was told to wear shoes.
entry[ 1]: 18/ 4/2010 - Doc advised me to concentrate on something... I forget.
entry[ 2]: 3/ 5/2010 - Was asked today if I was an art exhibit.
entry[ 3]: 19/ 5/2010 - Apparently mudcakes not made of mud, or angry wasps.
> bin\diary.exe dat\diary.txt
entry[ 0]: 12/ 4/2010 - Interview went well I think, though was told to wear shoes.
entry[ 1]: 18/ 4/2010 - Doc advised me to concentrate on something... I forget.
entry[ 2]: 3/ 5/2010 - Was asked today if I was an art exhibit.
entry[ 3]: 19/ 5/2010 - Apparently mudcakes not made of mud, or angry wasps.
(注意:所有日记条目(整个日记)所需的存储空间仅为309字节
,小于1/10
声明char条目所需的存储空间[1024];
)
始终确认已释放所有已分配的内存,并且没有内存错误
MS Windows
由于您在windows上似乎遇到了问题,下面是上面的代码,除了用%lu
代替%zu
(因为windows将%zu
视为一个文本)之外,没有其他内容,而是在Win7上使用旧版本的VS编译器编译的:
> cl /?
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
编译
$ cat dat/diary.txt
4
12/04/2010
Interview went well I think, though was told to wear shoes.
18/04/2010
Doc advised me to concentrate on something... I forget.
03/05/2010
Was asked today if I was an art exhibit.
19/05/2010
Apparently mudcakes not made of mud, or angry wasps.
> cl /nologo /Wall /wd4706 /wd4996 /Ox /Foobj/diary /Febin/diary /Tc diary.c
(注意:我将.obj文件放在子目录/obj
中,将二进制可执行文件放在/bin
中,以保持源目录干净。这就是上面/Foobj/diary
和/Febin/diary
的目的)
示例使用/输出
$ ./bin/diary <dat/diary.txt
entry[ 0]: 12/ 4/2010 - Interview went well I think, though was told to wear shoes.
entry[ 1]: 18/ 4/2010 - Doc advised me to concentrate on something... I forget.
entry[ 2]: 3/ 5/2010 - Was asked today if I was an art exhibit.
entry[ 3]: 19/ 5/2010 - Apparently mudcakes not made of mud, or angry wasps.
> bin\diary.exe dat\diary.txt
entry[ 0]: 12/ 4/2010 - Interview went well I think, though was told to wear shoes.
entry[ 1]: 18/ 4/2010 - Doc advised me to concentrate on something... I forget.
entry[ 2]: 3/ 5/2010 - Was asked today if I was an art exhibit.
entry[ 3]: 19/ 5/2010 - Apparently mudcakes not made of mud, or angry wasps.
您必须确保将每个%zu
更改为%lu
,否则无法获得正确的输出。您说您已将所有更改为int
,但您在下面的评论中发布的代码段包含%zu
——这在windows上不起作用
请仔细检查,如果您还有其他问题,请告诉我。有两个fgets
呼叫吗?一个用于日期行,一个用于“输入”行。在h[i]=atoi中h
是什么;
?请提供一个。如果我这样做,我应该将日期行和输入行存储到哪里?我尝试使用fgets作为日期和输入,然后继续使用另一个