【问题标题】:Reading different values from file in C and print based on conditions从 C 中的文件中读取不同的值并根据条件打印
【发布时间】:2019-03-15 22:49:39
【问题描述】:

我想使用一维数组读取存储在 C 文件中的不同值。 文本中有不同类型的数据和许多记录。每条记录由一个空格分隔,一条记录包含一个name、一个palate Number、一个布尔值type 1 或0、costdate。文件结构如下:

Hanif Hefaz
BA123HB
0
100.50
20180101

Jacki Shroff
UP673MK
1
3000.99
20170512

. . .

问题是我想从文件中读取每条记录并打印namespalate Numbers 只有那些date 是一年多以后的人。如果是这样,我这次想查看type。如果type1,那么我想打印一个新值,假设amount 以及该记录的namepalate Number 在某种程度上,cost 乘以@987654338 @ 如果type0,则cost 应该乘以2.5

简述:

read file
check if the date in the record is more than 1 year from now
if yes
check type
if type = 1
amount = cost * 1.5
else
if type = 0
amount = cost * 2.5
print name, palate Number, amount

目前,我可以打印文件中的所有记录。但是如何实现这些条件呢?

这是我的代码:

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

void FileRead(FILE *pr)
{
    fseek(pr, 0,0);
    while(1)
    {
    char name[100];
    if(fgets(name,100,pr) == NULL)
    {
        break;
    }
    printf("Name: : %s", name);
    char palateNumber [20];
    fgets(palateNumber,20,pr);
    printf("spz: %s", palateNumber);
    char type [2];
    fgets(type,20,pr);
    printf("type: %s", type);
    char cost [10];
    fgets(cost,10,pr);
    printf("cena: %s", cost);
    char date [15];
    fgets(date,15,pr);
    printf("date : %s", datum);
    fgets(name, 50, pr);
    printf("%s", name);
    }

}


int main()
{

   char x;
   FILE *pr;
   pr=fopen("file.txt","r");
   if(pr==NULL)
   {
       printf("File can not be opened.");
       return 0;
   }

  while(scanf("%c", &x))
    {
        switch(x)
        {

        case 'v' :
            FileRead(pr);
        break;

        }
    }
fclose(pr);
    return 0;
}

我也知道使用这个函数来查找当前日期和文件中日期之间的差异,这是我最近从here的某人那里得到的

time_t fill_broken_down_time (int y, int m, int d)
{                   /* initialize struct members */
    struct tm bdt = { .tm_sec=0, .tm_min=0, .tm_hour=0, .tm_mday=d,
                    .tm_mon=m>0?m-1:0, .tm_year=y-1900, .tm_isdst=-1 };

    return mktime(&bdt);    /* return mktime conversion to time_t */
}
        while (fgets (buf, MAXC, pr)) {     // read each line.

        if (sscanf (buf, "%4d%2d%2d", &y, &m, &d) != 3) {
            continue;
        }
        time_t  now = time(NULL),
        then = fill_broken_down_time (y, m, d);
        double secs = difftime (now, then);
        printf ("%g\n",secs / 86400.0);
        }

【问题讨论】:

  • 找到了——给我一点时间来消化它:)你有没有谈到在你的课堂上创建一个结构?喜欢struct mydata { char name[20]; char label[20]; int multflag; double value; char date[9] }; 吗?这是将不同类型的数据作为一个单元进行协调的好方法。告诉我。
  • 好吧,我更喜欢在没有结构的情况下使用一维数组。我也不擅长结构。我们可以使用一维数组来做到这一点吗?
  • char type [2]; fgets(type,20,pr); 将中断。数组中需要放置 3 个字符,而不是 2 个:单个数字、换行符和 NUL 终止符。 20 的大小会让这种情况发生,但只有 2 个字符的空间。
  • 没错,我什至不想要两个字符,应该是一个! 1 还是 0 对吗?
  • while(scanf("%c", &amp;x)) 应该是while(scanf("%c", &amp;x) == 1),否则您将无法检测到EOFscanf 系列的返回值必须始终与一个特定值进行比较:应该扫描的项目数。

标签: c file


【解决方案1】:

好吧,我得到了您的意见,但让我们尝试一个 struct 数组 以使您的数据处理更易于管理。这不是您最后一个问题的简单补充。尝试协调 5 个单独的数组(其中 3 个是 2D 字符数组)会带来比其价值更多的问题。 struct 是将不同类型的信息作为一个单元进行协调的正确方法。此外,除非您有持续使用 bool 的需求,否则只需使用 int 代替。编译器可以同样高效地处理原生类型 int

让我们从你的结构开始。 struct 只不过是一个方便的包装器,允许您收集不同的类型并将它们作为一个对象处理。在您的情况下,您的字符串name, plate, date、您的int type 和您的double value(您的amount)可以是struct 的成员。您可以将typedef 用于结构以使其使用更方便,因此您可以像使用普通类型一样简单地使用类型化的nameofstruct,而不是在任何地方编写struct nameofstruct,就像int。例如:

#define MAXS   16u  /* max number of structs */
#define MAXNM  32u  /* max characters in name and other arrays in struct */
#define MAXC 1024u  /* max characters in read buffer */
#define SECPY 31536000u /* seconds per-year */

typedef struct mydata {
    char name[MAXNM],
        plate[MAXNM],
        date[MAXNM];
    int type;
    double value;
} mydata_t;

使用mydata_ttypedef 创建一个struct mydata,它是struct mydata 的引用(别名)(您实际上可以省略mydata,而只需键入定义匿名结构)。

现在您可以创建一个struct mydata 或简单mydata_t 的数组,并且该数组的每个元素都是一个可以保存其中每个值的结构。

现在让我们开始解决您的问题。如上所述,只需声明一个 mydata_t 数组,而不是 5 个单独的数组,例如

int main (int argc, char **argv) {
    ...
    int n = 0, ndx = 0; /* NOTE when dealing with array, start at ZERO */
    ...
    mydata_t data[MAXS] = {{ .name = "" }};

现在您有一个 16 结构数组可以使用(根据需要调整数组的常量大小),并且您有 2 个计数器 n 来跟踪您当前正在阅读的结构中的哪个成员,以及 @ 987654347@你正在填充的数组中哪个结构的索引。

使用它们,您可以像在上一个问题中一样阅读每一行,并使用 n 来确定如何处理该行(您可以使用 isspace() 检查第一个字符是否为 whitespae(其中包括 '\n' ) 跳过空行。然后您只需将n 传递给switch(n) 以对该行采取适当的操作(或使用一堆if ... else if ... else if ...)例如:

   while (fgets (buf, MAXC, fp)) {     /* read each line in file */
        if (isspace(*buf))  /* skip blank lines (or start with space) */
            continue;
        buf[strcspn (buf, "\r\n")] = 0; /* trim '\n' from end of buf */
        /* if line isn't a date line, just output line as non-date line */
        switch (n) {
            case 0: /* fill the name in struct */
            case 1: /* fill the plate in struct */
            case 2: /* set the type in struct */
            ...

(注意:buf[strcspn (buf, "\r\n")] = 0; 只是一种方便的方法,可以在将 buf 末尾的 '\n'(或 \r\n)复制到 name, plate, date 等之前对其进行修剪。 .)

在每种情况下,您只需在复制之前验证使用fgets 读取的字符串是否适合您的结构的字符串成员,或者将字符串转换为您需要的数值,例如:

            case 0: 
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].name, buf);
                else {
                    fputs ("error: name exceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;   /* advance n counter to act on next member */
                break;

            case 2:
                if (sscanf (buf, "%d", &data[ndx].type) != 1) {
                    fputs ("error: type not an integer.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;

(在处理结构本身时,您使用'.'(点)运算符来访问结构的每个成员,或者如果您拥有的是一个指向的指针,则使用'-&gt;'(箭头)运算符 struct。当你有一个 stuct 数组时,数组索引 ([..]) 充当取消引用。与其他任何数组完全相同)

由于您不存储year, month, day,您只需要一个检查从现在开始的时间的函数,以便您可以测试它是否超过一年。这样,您只需将日期传递给函数并以秒为单位以 double 的形式返回时间,例如

 double check_time_from_now (const char *str)
{
    int y, m, d;

    if (sscanf (str, "%4d%2d%2d", &y, &m, &d) != 3) {
        fprintf (stderr, "error non-date string: '%s'.\n", str);
        exit (EXIT_FAILURE);
    }

    time_t  now = time(NULL),
            then = fill_broken_down_time (y, m, d);
    double secs = difftime (now, then); /* get seconds between dates */

    return secs;
}

另一个简单的函数允许您打印结构数组,例如

void prn_data_t_array (mydata_t *data, int n)
{
    for (int i = 0; i < n; i++)
        printf ("%-12s %-8s  %d  %9.2f %s\n", data[i].name, data[i].plate,
                data[i].type, data[i].value, data[i].date);
}

我们可以查看您的 switch(n) 的其余部分,其中显示了如何处理每种情况:

    while (fgets (buf, MAXC, fp)) {     /* read each line in file */
        if (isspace(*buf))  /* skip blank lines (or start with space) */
            continue;
        buf[strcspn (buf, "\r\n")] = 0; /* trim '\n' from end of buf */
        /* if line isn't a date line, just output line as non-date line */
        switch (n) {
            case 0: 
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].name, buf);
                else {
                    fputs ("error: name exceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 1:
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].plate, buf);
                else {
                    fputs ("error: plate exceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 2:
                if (sscanf (buf, "%d", &data[ndx].type) != 1) {
                    fputs ("error: type not an integer.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 3:
                if (sscanf (buf, "%lf", &data[ndx].value) != 1) {
                    fputs ("error: value not a double.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 4: 
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].date, buf);
                else {
                    fputs ("error: date exceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                if (check_time_from_now (data[ndx].date) > SECPY) {
                    if (data[ndx].type)
                        data[ndx].value *= 1.5;
                    else
                        data[ndx].value *= 2.5;
                }
                n = 0;
                ndx++;
                if (ndx == MAXS)
                    goto arrayfull;
                break;
            default:
                fputs ("error: you shouldn't get here!\n", stderr);
                break;
        }
    }

(注意: 仔细查看 case 4: 以及行计数器 n 是如何重置为零的,以及数组索引 ndx 是如何递增的,因此你可以在你的下一个结构中填充数组。另外注意您可以通过检查 if (ndx == MAXS) 来保护您的数组边界,以确保您编写的结构体不会超过数组中的结构体。)

总而言之,您将拥有:

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

#define MAXS   16u  /* max number of structs */
#define MAXNM  32u  /* max characters in name and other arrays in struct */
#define MAXC 1024u  /* max characters in read buffer */
#define SECPY 31536000u /* seconds per-year */

typedef struct {
    char name[MAXNM],
        plate[MAXNM],
        date[MAXNM];
    int type;
    double value;
} mydata_t;

time_t fill_broken_down_time (int y, int m, int d)
{                   /* initialize struct members */
    struct tm bdt = { .tm_sec=0, .tm_min=0, .tm_hour=0, .tm_mday=d, 
                    .tm_mon=m>0?m-1:0, .tm_year=y-1900, .tm_isdst=-1 };

    return mktime(&bdt);    /* return mktime conversion to time_t */
}

double check_time_from_now (const char *str)
{
    int y, m, d;

    if (sscanf (str, "%4d%2d%2d", &y, &m, &d) != 3) {
        fprintf (stderr, "error non-date string: '%s'.\n", str);
        exit (EXIT_FAILURE);
    }

    time_t  now = time(NULL),
            then = fill_broken_down_time (y, m, d);
    double secs = difftime (now, then); /* get seconds between dates */

    return secs;
}

void prn_data_t_array (mydata_t *data, int n)
{
    for (int i = 0; i < n; i++)
        printf ("%-12s %-8s  %d  %9.2f %s\n", data[i].name, data[i].plate,
                data[i].type, data[i].value, data[i].date);
}

int main (int argc, char **argv) {
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    int n = 0, ndx = 0; /* NOTE when dealing with array, start at ZERO */
    char buf[MAXC];     /* buffer to hold each line read from file */
    mydata_t data[MAXS] = {{ .name = "" }};

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fgets (buf, MAXC, fp)) {     /* read each line in file */
        if (isspace(*buf))  /* skip blank lines (or start with space) */
            continue;
        buf[strcspn (buf, "\r\n")] = 0; /* trim '\n' from end of buf */
        /* if line isn't a date line, just output line as non-date line */
        switch (n) {
            case 0: 
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].name, buf);
                else {
                    fputs ("error: name exceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 1:
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].plate, buf);
                else {
                    fputs ("error: plate exceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 2:
                if (sscanf (buf, "%d", &data[ndx].type) != 1) {
                    fputs ("error: type not an integer.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 3:
                if (sscanf (buf, "%lf", &data[ndx].value) != 1) {
                    fputs ("error: value not a double.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 4: 
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].date, buf);
                else {
                    fputs ("error: date exceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                if (check_time_from_now (data[ndx].date) > SECPY) {
                    if (data[ndx].type)
                        data[ndx].value *= 1.5;
                    else
                        data[ndx].value *= 2.5;
                }
                n = 0;
                ndx++;
                if (ndx == MAXS)
                    goto arrayfull;
                break;
            default:
                fputs ("error: you shouldn't get here!\n", stderr);
                break;
        }
    }
    arrayfull:;
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    puts ("\ncomputed information\n");
    prn_data_t_array (data, ndx);   /* print the computed values */

    return 0;
}

现在使用您的数据文件:

输入文件示例

$ cat dat/namelbltypevaldate.txt
Hanif Hefaz
BA123HB
0
100.50
20180101

Jacki Shroff
UP673MK
1
3000.99
20170512

使用/输出示例

代码会产生:

$ ./bin/time_from_now3 dat/namelbltypevaldate.txt

computed information

Hanif Hefaz  BA123HB   0     251.25 20180101
Jacki Shroff UP673MK   1    4501.48 20170512

如果您选中,则相应的乘数已应用于每个。

我真的不想用 5 个单独的数组来做这个。结构是完成这项工作的合适工具。你可以使用 5 个数组,就像我使用上面的 struct 数组一样——你只是有一个更长的变量列表和更多的名称来跟踪你的代码。看看这个,如果你有更多问题,请告诉我。

动态分配结构数组

从功能上讲,程序并不关心数据的存储位置。但是,使用自动存储进行分配确实有一个缺点,即在您继续添加记录时无法动态增长。使用malloc, calloc, realloc 动态分配数据的替代方法。这会增加一些额外的复杂性,因为现在由您来跟踪分配的可用存储空间、已使用的存储空间,并在您使用的存储空间等于可用存储空间时重新分配。

你不想realloc 每一行——那是低效的。相反,您将分配一些合理的起始数量的结构,填充它们直到达到限制,然后重新分配。重新分配多少取决于您,但常见的重新分配方案是将当前分配的大小加倍(或者您可以添加一些其他倍数,例如 3/2 等...取决于您希望分配的速度增长)。该示例使用了良好的旧 double 方法。

首先,更改(仅打印超过 1 年的行)只是将您的输出移动到内部:

                if (check_time_from_now (data[ndx].date) > SECPY) {

添加一个函数来输出记录 ndx 是您可以做的事情,以保持代码主体的整洁,例如

void prn_data_t_rec (mydata_t *data, int n)
{
    printf ("%-12s %-8s  %d  %9.2f %s\n", data[n].name, data[n].plate,
            data[n].type, data[n].value, data[n].date);
}

从代码主体调用:

                if (check_time_from_now (data[ndx].date) > SECPY) {
                    if (data[ndx].type)
                        data[ndx].value *= 1.5;
                    else
                        data[ndx].value *= 2.5;
                    prn_data_t_rec (data, ndx);  /* output > 1 year */
                }

现在到动态分配。而不是声明:

mydata_t data[MAXS] = {{ .name = "" }};

您只需将声明和初始分配更改为:

#define MAXS   16u  /* initial number of structs */
...
    int maxs = MAXS;    /* variable to track allocated number of struct */
    mydata_t *data = calloc (maxs, sizeof *data); /* allocate storage */

(注意: calloc 被选中而不是 malloc,因为我想将所有内存初始化为零并避免编写显式初始化程序来将每个 typevalue 成员设置为否则为零。允许calloc 这样做的开销可以忽略不计)

现在*验证每个分配

    if (!data) {    /* validate every allocation */
        perror ("calloc-data");
        return 1;
    }

这同样适用于每次重新分配,但需要注意的是。您始终使用临时指针realloc。如果您使用指针本身重新分配,例如 ptr = realloc (ptr, newsize);realloc 无法返回 NULL - 您会使用 NULL 覆盖您的原始地址,从而造成内存泄漏并失去对现有数据的所有访问权限!

在您到达case 4: 中的realloc 之前,代码中的所有其他内容都是相同的switch()。当(ndx == maxs) 你必须realloc 额外的存储空间,例如

            case 4: 
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].date, buf);
                else {
                    fputs ("error: date excceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                if (check_time_from_now (data[ndx].date) > SECPY) {
                    if (data[ndx].type)
                        data[ndx].value *= 1.5;
                    else
                        data[ndx].value *= 2.5;
                    prn_data_t_rec (data, ndx);
                }
                n = 0;
                ndx++;
                if (ndx == maxs) {  /* check if realloc required */
                    /* realloc w/temp pointer to 2X current size */
                    void *tmp = realloc (data, 2 * maxs * sizeof *data);
                    if (!tmp) { /* validate every allocation */
                        perror ("realloc-data");
                        goto outofmem;  /* original data still good */
                    }
                    data = tmp; /* set data to newly reallocated block */
                    /* zero the new memory allocated (optional) */
                    memset (data + maxs, 0, maxs * sizeof *data);
                    maxs *= 2;  /* update the currently allocated max */
                }
                break;

(注意:继续使用goto -- 如果realloc 失败,这里必须保留你原来的data。即使失败,你原来的所有@987654407 @ 仍然很好 - 由于您使用 临时指针 来测试重新分配,因此您并没有失去对它的访问权限。所以只需跳出开关和 while 循环,您就可以继续不再需要时使用它并free它。

把整个例子放在一起,你会得到:

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

#define MAXS   16u  /* initial number of structs */
#define MAXNM  32u  /* max characters in name and other arrays in struct */
#define MAXC 1024u  /* max characters in read buffer */
#define SECPY 31536000u /* seconds per-year */

typedef struct {
    char name[MAXNM],
        plate[MAXNM],
        date[MAXNM];
    int type;
    double value;
} mydata_t;

time_t fill_broken_down_time (int y, int m, int d)
{                   /* initialize struct members */
    struct tm bdt = { .tm_sec=0, .tm_min=0, .tm_hour=0, .tm_mday=d, 
                    .tm_mon=m>0?m-1:0, .tm_year=y-1900, .tm_isdst=-1 };

    return mktime(&bdt);    /* return mktime conversion to time_t */
}

double check_time_from_now (const char *str)
{
    int y, m, d;

    if (sscanf (str, "%4d%2d%2d", &y, &m, &d) != 3) {
        fprintf (stderr, "error non-date string: '%s'.\n", str);
        exit (EXIT_FAILURE);
    }

    time_t  now = time(NULL),
            then = fill_broken_down_time (y, m, d);
    double secs = difftime (now, then); /* get seconds between dates */

    return secs;
}

void prn_data_t_array (mydata_t *data, int n)
{
    for (int i = 0; i < n; i++)
        printf ("%-12s %-8s  %d  %9.2f %s\n", data[i].name, data[i].plate,
                data[i].type, data[i].value, data[i].date);
}

void prn_data_t_rec (mydata_t *data, int n)
{
    printf ("%-12s %-8s  %d  %9.2f %s\n", data[n].name, data[n].plate,
            data[n].type, data[n].value, data[n].date);
}

int main (int argc, char **argv) {
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    int n = 0, ndx = 0, /* NOTE when dealing with array, start at ZERO */
        maxs = MAXS;    /* variable to track allocated number of struct */
    char buf[MAXC];     /* buffer to hold each line read from file */
    mydata_t *data = calloc (maxs, sizeof *data); /* allocate storage */

    if (!data) {    /* validate every allocation */
        perror ("calloc-data");
        return 1;
    }

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    puts ("\ncomputed information for records > 1 year from now\n");

    while (fgets (buf, MAXC, fp)) {     /* read each line in file */
        if (isspace(*buf))  /* skip blank lines (or start with space) */
            continue;
        buf[strcspn (buf, "\r\n")] = 0; /* trim '\n' from end of buf */
        /* if line isn't a date line, just output line as non-date line */
        switch (n) {
            case 0: 
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].name, buf);
                else {
                    fputs ("error: name excceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 1:
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].plate, buf);
                else {
                    fputs ("error: plate excceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 2:
                if (sscanf (buf, "%d", &data[ndx].type) != 1) {
                    fputs ("error: type not an integer.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 3:
                if (sscanf (buf, "%lf", &data[ndx].value) != 1) {
                    fputs ("error: value not a double.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                n++;
                break;
            case 4: 
                if (strlen (buf) < MAXNM)
                    strcpy (data[ndx].date, buf);
                else {
                    fputs ("error: date excceeds storage.\n", stderr);
                    exit (EXIT_FAILURE);
                }
                if (check_time_from_now (data[ndx].date) > SECPY) {
                    if (data[ndx].type)
                        data[ndx].value *= 1.5;
                    else
                        data[ndx].value *= 2.5;
                    prn_data_t_rec (data, ndx);
                }
                n = 0;
                ndx++;
                if (ndx == maxs) {  /* check if realloc required */
                    /* realloc w/temp pointer to 2X current size */
                    void *tmp = realloc (data, 2 * maxs * sizeof *data);
                    if (!tmp) { /* validate every allocation */
                        perror ("realloc-data");
                        goto outofmem;  /* original data still good */
                    }
                    data = tmp; /* set data to newly reallocated block */
                    /* zero the new memory allocated (optional) */
                    memset (data + maxs, 0, maxs * sizeof *data);
                    maxs *= 2;  /* update the currently allocated max */
                }
                break;
            default:
                fputs ("error: you shouldn't get here!\n", stderr);
                break;
        }
    }
    outofmem:;
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    puts ("\nall stored information\n");
    prn_data_t_array (data, ndx);   /* print the computed values */

    free (data);    /* don't forget to free what you allocate */

    return 0;
}

注意:它在循环期间打印&gt; 1 year并在最后输出总记录——根据需要调整)

使用/输出示例

使用相同的数据文件:

$ ./bin/time_from_now4 dat/namelbltypevaldate.txt

computed information for records > 1 year from now

Hanif Hefaz  BA123HB   0     251.25 20180101
Jacki Shroff UP673MK   1    4501.48 20170512

all stored information

Hanif Hefaz  BA123HB   0     251.25 20180101
Jacki Shroff UP673MK   1    4501.48 20170512

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您都有 2 个职责:(1)始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放

您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出分配块的边界,尝试读取或基于未初始化的值进行条件跳转,最后,以确认您释放了已分配的所有内存。

对于 Linux,valgrind 是正常的选择。每个平台都有类似的内存检查器。它们都易于使用,只需通过它运行您的程序即可。

$ ./bin/time_from_now4 dat/namelbltypevaldate.txt
==4331== Memcheck, a memory error detector
==4331== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4331== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==4331== Command: ./bin/time_from_now4 dat/namelbltypevaldate.txt
==4331==

computed information for records > 1 year from now

Hanif Hefaz  BA123HB   0     251.25 20180101
Jacki Shroff UP673MK   1    4501.48 20170512

all stored information

Hanif Hefaz  BA123HB   0     251.25 20180101
Jacki Shroff UP673MK   1    4501.48 20170512
==4331==
==4331== HEAP SUMMARY:
==4331==     in use at exit: 0 bytes in 0 blocks
==4331==   total heap usage: 12 allocs, 12 frees, 5,333 bytes allocated
==4331==
==4331== All heap blocks were freed -- no leaks are possible
==4331==
==4331== For counts of detected and suppressed errors, rerun with: -v
==4331== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放已分配的所有内存并且没有内存错误。

如果您还有其他问题,请告诉我(此时可能需要提出新问题)

【讨论】:

  • 感谢您的出色工作,非常感谢您。它几乎可以工作,我唯一不想要的是它打印每条记录,即使日期差从现在开始不到一年。为什么我们不能使用 malloc 来做到这一点?请告诉我一种与现在做同样事情但使用 malloc 的方法,因为我需要使用 malloc 来做。
  • 当然,我会放弃更新。由于所需的验证和在realloc 上使用临时指针,使用mallocrealloc 会增加一些复杂性。除了为每条记录分配之外,代码将是相同的。您可以将打印内容移到 if (check_time_from_now (data[ndx].date) &gt; SECPY) 有条件的内部,以仅在超过一年前打印。我今天下午有时间更新。
  • 嗯,我想我们也可以通过输入那个命令来解决日期的问题。我的意思是当我输入命令打印结果时,我们还可以输入当前日期为20190316 作为输入,然后找到输入日期与文件中每条记录的日期之间的差异。
  • 我只是在整理补充,给我5分钟:)
  • 很高兴为您提供帮助。祝你的编码好运——并始终验证每次读取和每次分配:)
猜你喜欢
  • 1970-01-01
  • 2021-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-02
  • 2011-05-11
相关资源
最近更新 更多