【问题标题】:Copy an array of structs using a function in C使用 C 中的函数复制结构数组
【发布时间】:2015-07-31 06:27:41
【问题描述】:

我有一个名为Record 的结构,它有与之关联的数据,在我的程序中,我有一个由这些Records 组成的数组。结构如下:

#define MAX_RECORDS 1024

typedef struct
{
    char    title[80];
    char    artist[80];
    int     year;
    char    genre[80];
    char    label[80];
    double  price;
} Record;

Record record_inventory[MAX_RECORDS];

由于我正在编写的程序需要将record_inventory 的不同字段排序到Record 的新数组中,但实际上并没有更改与原始数组关联的数据,我想我需要一个简单的方法来复制一个数组到另一个。

我在网上查了一下,在stackoverflow上发现了一个帖子说要这样布局:

void copy_record(Record (*copy_to)[MAX_RECORDS], Record (*copy_from)[MAX_RECORDS])
{
    memcpy(copy_from, copy_to, sizeof *copy_from);
}

现在,在排序方法中,我有一个这样的函数原型:

Record* sort_by_title()
{
    Record ret[MAX_RECORDS];
    copy_record(&ret, record_inventory); // compilation error saying incorrect pointer type
    // do sorting here
    return ret;
}

上面的评论给了我一个不正确的指针类型错误。但是执行以下所有操作也不起作用:

copy_record(&ret, &record_inventory);
copy_record(&ret, *record_inventory);
copy_record(ret, record_inventory);
copy_record(ret, &record_inventory);
copy_record(*ret, *record_inventory);

那么我应该如何将一个结构数组复制到另一个数组并返回呢?我什至返回正确的类型(我想要的类型)?我想我只是对实际需要传递的内容感到困惑,所以现在我只是想让一些东西起作用。

【问题讨论】:

  • 你能给出你从编译器得到的确切错误吗?
  • copy_record(&ret, &record_inventory) 应该可以工作。请注意,您返回的是本地数组的地址,它将引用客户端代码中的无效内存。
  • @MOehm 这很有道理(第二部分)。我应该怎么做才能避免这种情况?只需将其声明为静态?
  • "memcpy(from, to, size);" ?有没有搞错? “memcpy(dest,src,大小);”是原型。
  • 如果你复制record_inventory只是为了排序,可能会浪费内存。排序后的数组可以是指向Record的指针数组:数据只在原始数组中,没有重复,并且指针根据您需要的字段进行排序。

标签: c arrays struct memcpy


【解决方案1】:

由于某种原因,您的函数声明声明它需要指向指针的指针。应该是:

void copy_record(Record *copy_to, Record *copy_from)
{
    memcpy(copy_to, copy_from, sizeof(*copy_from) * MAX_RECORDS);
}

然后调用它就像copy_record(ret, record_inventory);

【讨论】:

  • 原始文件并没有错(除了交换tofrom),事实上它提高了类型安全性,因为它强制调用者传递正确大小的数组。您的版本引入了错误的可能性,因为有人可能传入大小不是 MAX_RECORDS 的数组
  • 另外原文不带指针指向指针。它需要指向数组的指针。
  • 对不起,我错了。如果目标是让人们认为这段代码是错误的,而实际上并非如此——我想这是一条可行的路。它肯定让我着迷。
【解决方案2】:

您的复制函数具有正确的签名,您可以通过以下方式调用它:

copy_record(&ret, &record_inventory);

但是你把memcpy 的论点弄错了;目的地是第一位的。应该是:

memcpy(copy_to, copy_from, sizeof *copy_from);

但是您的sort_by_title() 函数存在设计缺陷。 ret 是该函数的本地数组。当函数返回时,它将被销毁。如果您确实成功返回了指向它的指针,则该指针将悬空。

相反,您可以让sort_by_title 接受输入和输出参数,并返回void


避免必须使用指向数组语法的另一种方法是将数组包装在结构中:

struct RecordInventory
{
    Record records[MAX_RECORDS];
};

然后您可以使用具有值语义的该类型的对象,例如按值返回。

【讨论】:

    【解决方案3】:

    声明变量时,请注意括号可能有特殊含义。 Record *x 是指向 Record 的指针,但 Record (*x)() 是指向返回 Record 作为结果的函数的指针。你让编译器很难弄清楚你想要从中得到什么。

    另外,Record *x 等价于Record x[]Record *x[](正如你所做的那样)等价于Record **x(指向指针的指针),这与Record *x 不同,这就是为什么你的编译器无法识别类型。

    此外,memcpy() 首先获取目标地址,因此您的参数被反转,并且您还从数组中复制单个元素而不是整个数组,如 keltar pointed out in his answer

    【讨论】:

    • Record (*x)[]Record (*x)()Record *x[] 都不同(他没有这样做)
    • @MattMcNabb 可能。我不确定Record (*x)[] 是什么意思。
    【解决方案4】:

    事实上,通过简单地将数组本身作为参数来对数组进行排序是不可能的。因为在c中,如果你写一个类似

    的函数
    void func(int arr[100]);
    

    参数arr 实际上是一个指针而不是一个数组。也就是说,以下几行没有什么不同。

    void func(int *arr);
    void func(int arr[]);
    void func(int arr[100]);
    

    因此,当您尝试 sizeofarr 时,您只需获得指向 int 的指针的大小。你得到的是sizeof(int *)

    如果一个函数想要接收一个数组,数组的长度必须作为参数给出:

    void func(int arr[], size_t length);
    

    复制Record数组的函数应该是

    void copy_array(Record dest[], Record from[], size_t length)
    {
        memcpy(dest, from, sizeof(Record) * length);
    }
    

    您的代码无法编译,因为您混淆了 指针指向数组的指针 的概念。
    在您的代码中,Record (*copy_to)[MAX_RECORDS]copy_to 是指向 Records 数组的指针。并且指向数组的长度是固定的(MAX_RECORDS)。

    此外,大型对象的就地排序相当慢。您应该考虑创建一个指针(或索引)数组并对指针进行排序。

    非常抱歉英语不好。

    【讨论】:

    • Record (*copy_to)[MAX_RECORDS] 是一个指针,而不是一个数组。除了 memcpy 参数的顺序之外,复制功能很好。数组大小不会丢失,函数可以看到大小。他没有像您的任何funcs 那样的代码。
    【解决方案5】:

    修改您的代码,如下所示。

    void copy_record(Record (*copy_to), Record (*copy_from))
    {
        memcpy(copy_from, copy_to, sizeof(*copy_from) * MAX_RECORDS);
    }
    
    Record* sort_by_title()
    {
        Record ret[MAX_RECORDS];
        copy_record(ret, record_inventory); 
        return ret;
    }
    

    【讨论】:

    • 这只会复制一条记录,并且您返回一个悬空指针
    猜你喜欢
    • 1970-01-01
    • 2015-10-15
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 2019-04-13
    相关资源
    最近更新 更多