F编写通过引用传递的动态结构

时间:2018-11-25 20:47:41

标签: c

不确定我的标题是否有意义,但是我想做的是从动态结构到文件的fwrite操作,但是使这种操作更困难的是我的结构是通过引用传递的,而且我不知道第一个参数的方式fwrite应该看起来像。这是代码的一部分:

void editData(FILE* fPtr, Car* carPtr[], int* size)
{
int number = 0;
printData(carPtr, size);

while(1)
{
    if ((scanf("%d", &number) == 1) && (getchar() == '\n'))
    {
        if ((number > 0) && (number <= *size))
        {
            char make[15] = "", model[15] = "";
            int year = 0;
            double price = 0;

            if (getUserInput(make, model, &year, &price) == 1)
            {
                strcpy((*carPtr+number-1)->make, make);
                strcpy((*carPtr+number-1)->model, model);
                (*carPtr+number-1)->year = year;
                (*carPtr+number-1)->price = price;

                fseek(fPtr, sizeof(Car) * number-1, SEEK_SET);
                fwrite(**&carPtr[number-1]**, sizeof(Car), 1, fPtr);
            }

这就是我从main调用此函数的方式:

FILE* db = NULL;
int choice = 0;
db = openDatabase(db);

Car* cr = NULL;
int size = 0;
loadData(db, &cr, &size);
while((choice = menuChoice()) != 5)
    {
        switch (choice)
        {
            case 1:
                insertData(db, &cr, &size);
                break;
            case 2:
                **editData(db, &cr, &size);**
                break;
            case 4:
                printData(&cr, &size);
                break;
        }
    }
    free(cr);
    fclose(db);
}

对结构的内存分配发生在不同的功能中。

如果结构是局部的,则在fwrite中我将写为第一个参数

&carPtr[number-1]

但是对于我来说,这是行不通的。

汽车申报单:

struct car
{
    char make[15];
    char model[15];
    int year;
    double price;
};

3 个答案:

答案 0 :(得分:1)

fwrite需要指向要写入的字节缓冲区的指针。

如果您有局部变量(包括结构),则需要使用&运算符获取其地址,如下所示:

Car myCar;
fwrite(&myCar, sizeof(Car), 1, fout);

但是,如果您已经有一个指针,则不需要&运算符:

Car *myCar;
fwrite(myCar, sizeof(Car), 1, fout);

如果您有一个指向结构的指针数组,也会发生同样的事情:

Car* cars[];
fwrite(cars[i], sizeof(Car), 1, fout);

由于cars[i]已具有地址fwrite的地址,因此不需要任何运算符。

要注意的一件事是C编译器填充结构-它们可以在字段之间插入未使用的字节,以确保每个字段都在边界上开始(取决于系统字的对齐方式,通常为4)。

因此,这15个char数组可能附加一个额外的字节以舍入为16。 如果将整个结构写入文件,这些字节也将被写入。

这就是为什么通常建议单独编写每个字段的原因,但是如果这只是一个练习,可能没关系。

答案 1 :(得分:0)

Car *pnt

这是指向Car的指针。

表达式*(...)...取消引用到对象中。

表达式a[b]等于*(a + b)

Car* carPtr[]
函数参数列表中的

(即function(... Car *carPtr[] ....)中的等于:

Car **carPtr

这是指向Car的指针。

&carPtr[x]

等于:

carPtr + x

这不是您想要的。您有一个指向汽车数组的指针,而不是指向汽车数组的指针。您要先取消引用carPtr,然后递增。您想要:

&(*carPtr)[x]

等于:

((*carPtr) + x)

所以尝试:

fwrite(&(*carPtr)[number-1], sizeof(Car), 1, fPtr);

我还要重写

(*carPtr+number-1)->

进入

(*carPtr)[number - 1].

表示您正在处理指向数组的指针。

但实际上,我将重写api以处理更好的抽象:

struct cars_s {
     Car *cars;
     size_t carslen;
};

int main() {
    struct cars_s cars;

    insertData(db, &cars);
     ...
    editData(db, &cars);
}

当您执行editData(FILE *db, struct cars_s *cars)cars->cars[x].year = year而不是Cars *cars[], int *size(*carPtr)[x].year = year时,这将使您的代码更具可读性。

答案 2 :(得分:0)

问题不是fwrite,而是毕竟fseek。 这个:

fseek(fPtr, sizeof(Car) * number-1, SEEK_SET);

必须更改为此:

fseek(fPtr, sizeof(Car) * (number-1), SEEK_SET);

我设法省略了括号,由于这个原因,fwrite会写到错误的地方。然后,Fread读取的内容超出了分配的内存,这就是为什么我认为随机发生的事情。

关于写fwrite的正确方法:

fwrite(&(*carPtr)[number-1], sizeof(Car), 1, fPtr);

这很好用