如何在结构数组中访问struct

问题描述 投票:0回答:3

在学校作业中,我必须对位于二进制文件中的结构元素进行排序。我想我已经设法对它进行排序,但是打印结果时遇到问题。我不知道如何访问struct的元素,因为必须从文件中读取数据,所以我只有数组中第一个结构的地址。 (我认为它应该保留在数组中,以便我可以使用qsort。)

这是主要代码:

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

typedef struct {
char name[32];
double value;
} record;

int nuvu(record* a, record* b){
    if(a->name < b->name) return -1;
    if(a->name > b->name) return 1;
    if(a->value < b->value) return -1;
    if(a->value > b->value) return 1;
}

int main()
{
    long N;
    unsigned char* p = readfile( "d.bin", &N );
    char* s;
    scanf("%s",&s);

    int k= N/sizeof(record);
    qsort(p,k,sizeof(record),(int(*)(const void*, const void *))nuvu);

    printf???

    free(p);
    return 0;
}

附加:readfile.c

#include "readfile.h"
unsigned char* readfile( char* filename, long* pN )
{
    FILE* f= fopen(filename,"rb");
    if(f==0){
        *pN=-1;
        return 0;
    }
    fseek(f,0,SEEK_END);
    *pN=ftell(f);
    fseek(f,0,SEEK_SET);

    char*p=malloc(*pN);
    if(p==0){
        *pN=-2;
        fclose(f);
        return 0;
    }
    size_t r = fread(p,1,*pN,f);
    if(r!=*pN){
        *pN=-3;
        fclose(f);
        free(p);
        return 0;
    }
    fclose(f);
    return p;
}

readfile.h

#ifndef __READFILE_H
#define __READFILE_H

#include <stdio.h>
#include <stdlib.h>
unsigned char* readfile(char* filename, long* pN);

#endif /* __READFILE_H */
c linux struct
3个回答
0
投票

使用qsort的标准程序,不要更改其签名。如评论中所述,使用strcmp。您必须弄清楚结构如何排序的逻辑。以下示例按record::name排序,如果name相同,则按顺序测试value

int nuvu(const void * a_, const void * b_)
{
    const record* a = a_;
    const record* b = b_;
    if(strcmp(a->name, b->name) == 0)
        return a->value > b->value;
    return strcmp(a->name, b->name);
}

数据作为字节读入p,它必须转换为“记录数组”record* arr = (record*)p;。如果一切按计划进行,则数组中的项目数应为filesize/sizeof(record)

int main(void)
{
    long filesize = 0;
    unsigned char* p = readfile("d.bin", &filesize);
    if(!p)
        return 0;

    int count = filesize / sizeof(record);
    record* arr = (record*)p;

    qsort(arr, count, sizeof(record), nuvu);

    for(int i = 0; i < count; i++)
        printf("%s %f\n", arr[i].name, arr[i].value);

    free(p);
    return 0;
}

1
投票

您似乎遇到的最大困惑是“我如何阅读我的结构阵列?”

unsigned char* p = readfile( "d.bin", &N );

没办法开始。将记录从二进制文件读取到struct数组中的概念是将sizeof (struct record)字节从文件读入存储类型struct record。 (这将暂时忽略数据的序列化,填充和可移植性问题,以及我们使用typedef的事实)。

了解文件大小并了解sizeof (struct record)后,您可以(1)验证您将从文件中读取的记录数,例如: (nbytes / sizeof (struct record))和(2)确定是否有任何杂散字节剩余不会成为读取的一部分(例如if (nbytes / sizeof (struct record) != 0)),如果存在,你至少应该警告。

根据您必须读取的记录数以及是否存在该数字的上限,将确定您是否可以使用固定大小的数组(或VLA),或者是否需要动态分配(和重新分配)以解决未知数记录或防止StackOverflow ..无论您如何处理为您的记录创建存储 - 由您来确保您不要超出您创建的存储的范围。

下面,我们将简单地使用100记录数组。在适合堆栈的内容和需要动态分配的内容之间的分界线将取决于编译器,但是每当您开始考虑成千上万条记录时,您需要查阅编译器文档并开始考虑动态分配。

fread提供了一种从文件中读取二进制记录的简单方法,并验证您实际读取了要读取的记录数。例如,如果在100中声明了rec记录数组,您可以执行以下操作:

enum { MAXC = 32, MAXS = 100 }; /* if you need constants, define them */
...
    record rec[MAXS] = {{ .name = "" }};    /* array of 100 records */
    ...
    nrec = nbytes / sizeof *rec;   /* number of records based on file size */

    /* read / validate nrec records from file */
    if (fread (rec, sizeof *rec, nrec, fp) != nrec) {
        perror (fn);
        return 1;
    }

从您的文件成功读取您的记录后,使用qsort对记录进行排序(通过q​​azxswpoi或name),您需要了解在比较函数中要比较的value指针将指向rec,因此您必须提供适当的在比较函数中强制转换以访问和比较值。例如,要在const void *上执行字符串比较,您可以执行类似于以下操作:

name

除此之外,您的代码缺少的其余部分是对流程中每个步骤的验证。始终,始终验证您使用的任何功能的返回并处理您遇到的任何错误。一个最小的例子,没有在单独的源文件之间拆分代码可能类似于以下内容。拆分成单独的源文件留给您。

/** record string comparison on name */
int reccmpname (const void *a, const void *b)
{
    const record *ra = a,
                 *rb = b;
    return strcmp (ra->name, rb->name);
}

注意:使用的数据文件只包含100个结构记录,字典单词为#include <stdio.h> #include <stdlib.h> #include <string.h> enum { MAXC = 32, MAXS = 100 }; /* if you need constants, define them */ typedef struct { char name[MAXC]; double value; } record; /** record string comparison on name */ int reccmpname (const void *a, const void *b) { const record *ra = a, *rb = b; return strcmp (ra->name, rb->name); } int main (int argc, char **argv) { record rec[MAXS] = {{ .name = "" }}; /* array of 100 records */ size_t nrec = 0; /* number of records from file */ long nbytes = 0; /* number of bytes in file */ char *fn = argc > 1 ? argv[1] : "dat/records.bin"; FILE *fp = fopen (fn, "rb"); if (!fp) { /* validate file open for reading */ fprintf (stderr, "error: file open failed '%s'.\n", argv[1]); return 1; } if (fseek (fp, 0, SEEK_END) == -1) { /* validate seek to end */ perror ("fseek"); return 1; } nbytes = ftell (fp); /* number of bytes in file */ if (nbytes == -1) { perror ("ftell"); return 1; } if (fseek (fp, 0, SEEK_SET) == -1) { /* validate seek to start */ perror ("fseek"); return 1; } if (nbytes % sizeof *rec != 0) /* does file contain even no. or records? */ fprintf (stderr, "warning: file size not multiple of record size.\n"); nrec = nbytes / sizeof *rec; /* number of records based on file size */ /* read / validate nrec records from file */ if (fread (rec, sizeof *rec, nrec, fp) != nrec) { perror (fn); return 1; } fclose (fp); /* close file */ printf ("\n=== unsorted records ===\n\n"); /* output unsorted */ for (size_t i = 0; i < nrec; i++) printf ("%-32s %g\n", rec[i].name, rec[i].value); qsort (rec, nrec, sizeof *rec, reccmpname); /* qsort records */ printf ("\n=== sorted records ===\n\n"); /* output sorted */ for (size_t i = 0; i < nrec; i++) printf ("%-32s %g\n", rec[i].name, rec[i].value); return 0; } ,随机值为name,在写入文件之前进行了混洗。

示例使用/输出

value

如果您有任何疑问,请告诉我。


0
投票

您可以将[]运算符与指针一起使用:

$ ./bin/struct_rd_name_val_recs

=== unsorted records ===

Abscess                           4.15871e+08
Abject                            3.5743e+08
Abo                               6.87659e+08
Aboard                            2.02028e+09
Abase                             3.34319e+08
...
=== sorted records ===

A                                 3.66907e+08
Aaa                               5.59224e+07
Aaas                              1.45617e+09
Aardvark                          1.72828e+09
Aarhus                            1.95723e+09
© www.soinside.com 2019 - 2024. All rights reserved.