指向结构的指针的函数,并在没有memcpy的情况下复制它的内容

时间:2016-07-24 17:45:24

标签: c function pointers struct structure

我试图创建一个指向单个库存结构(一个记录)的函数,并将其内容复制到inventory.c中定义的gobal数组中的元素。我想按成员复制成员,如果副本失败则返回整数-1。在我的主要功能中,我想迭代我的示例数据并为sampleData数组中的每个元素调用invSetRecord函数。我迷失了该怎么做,需要一些帮助。我更新了inventory.c文件。我对我的功能很困惑。我正在自己编译它。我不明白如何获取productName进行复制。有什么建议?此外,我很难设置库存记录的计数器。

这是我老师的指示,

使用为Lab 9(第2部分)创建的petstore文件来完成此分配。

将以下示例数据复制到petstore_main.c文件中:

# define SAMPLE_SZ 5

struct inventory_s sampleData[SAMPLE_SZ] = {
    { 1000, 1.49, 3.79, 10, 0, "Fish Food" },
    { 2000, 0.29, 1.59, 100, 1, "Angelfish" },
    { 2001, 0.09, 0.79, 200, 1, "Guppy" },
    { 5000, 2.40, 5.95, 10, 0, "Dog Collar, Large" },
    { 6000, 49.99, 129.99, 3, 1, "Dalmation Puppy" }
};

inventory.c文件中定义一个具有以下原型的函数(将原型放在inventory.h文件中)

int invSetRecord(struct inventory_s *ipx);

此函数将获取指向单个库存结构(记录)的指针,并将其内容复制到inventory.c中定义的全局数组中的元素。目标位置(全局数组元素)将由数组的当前大小确定,如果数组为空则将记录复制到元素0中,如果当前大小为1则将其复制到元素1中,等等。意味着您需要在inventory.c中定义一个跟踪数组中元素数量的全局计数器。在invSetRecord函数中,您需要使用适合于该类型的方法按成员复制结构成员,例如原始数据类型的简单赋值,字符串数据类型的strcpy()。该函数返回一个整数值:如果复制操作失败(例如全局库存数组已满),则该函数返回-1,否则返回0.

petstore_main.c的主函数中,您需要创建一个循环,该循环遍历示例数据并为sampleData数组中的每个元素调用invSetRecord。对于每次调用invSetRecord,您需要检查函数的返回值,如果操作失败或成功,则打印错误,以及相应的记录号。例如,如果所有5个样本数据记录的操作成功,则这是从主函数打印的输出:

record #1 set successfully
record #2 set successfully
record #3 set successfully
record #4 set successfully
record #5 set successfully

如果对invSetRecord的调用失败(函数返回-1),则打印以下消息:

error: could not set record 1

如果发生错误,您必须在此时退出循环。

这是我到目前为止所需要的一些帮助。我整个星期都在试着想出这个。提前感谢您的帮助。

//inventory.c    
#include <stdio.h>

#include "inventory.h"
int i;
#define invSetRecord main

struct inventory_s inventory[MAX_INVENTORY];
int i;

int invSetRecord(struct inventory_s *ipx)
{

    int result;
    i = sizeof(MAX_INVENTORY)/sizeof(inventory[0]);

    if (i > MAX_INVENTORY)
    {
    result = -1;
    printf("%i", i);
    }
    if (i < MAX_INVENTORY)
    {
        result = 0;
        printf("%i", i);
        inventory[i].productNumber = ipx->productNumber;
        inventory[i].mfrPrice = ipx->mfrPrice;
        inventory[i].retailPrice = ipx->retailPrice;
        inventory[i].numInStock = ipx->numInStock;
        inventory[i].liveInv = ipx->liveInv;
        //inventory[i].productName= (ipx->productName);


        i++;
    }
    return result;



}

继承我的inventory.h文件...

#ifndef _INVENTORY_H_ //ensures that inventory.h does not run more than once
#define _INVENTORY_H_

#define  PRODUCTNAME_SZ 20
#define MAX_INVENTORY 50


struct inventory_s
{
    int productNumber;
    float mfrPrice;
    float retailPrice;
    int numInStock;
    char liveInv;
    char productName[PRODUCTNAME_SZ];
};

int invSetRecord(struct inventory_s *ipx);

#endif //_INVENTORY_H_

继承我的main()文件......

//main.c
#include <stdio.h>
#include <stdlib.h>

#include "inventory.h"

#define SAMPLE_SZ 5

extern struct inventory_s inventory[MAX_INVENTORY]; 

struct inventory_s sampleData[SAMPLE_SZ]={

    { 1000, 1.49, 3.79, 10, 0, "Fish Food" },
    { 2000, 0.29, 1.59, 100, 1, "Angelfish" },
    { 2001, 0.09, 0.79, 200, 1, "Guppy" },
    { 5000, 2.40, 5.95, 10, 0, "Dog Collar, Large" },
    { 6000, 49.99, 129.99, 3, 1, "Dalmation Puppy"}
};

int main()
{
    int i;

    for(i = 0; i < SAMPLE_SZ; i++);
    invSetRecord(sampleData);

    printf("The product number is %i for sampleData element[]", sampleData[0].productNumber);
    return 0;
}

1 个答案:

答案 0 :(得分:1)

让我们从编译器抛出错误和警告的简单问题开始:

#include "inventory.h"
int i;
#define invSetRecord main

struct inventory_s inventory[MAX_INVENTORY];
int i;

您需要多少次声明i#define invSetRecord main没有理由。请注意,在声明全局时,建议使用比常见i更独特的名称。

invSetRecord中,(idx使用i(索引),为什么不简单地执行:

/* inventory.c */
#include <stdio.h>
#include <string.h>

#include "inventory.h"

int idx;

struct inventory_s inventory[MAX_INVENTORY];

int invSetRecord (struct inventory_s *ipx)
{
    if (idx == MAX_INVENTORY) return -1;

    inventory[idx].productNumber = ipx->productNumber;
    inventory[idx].mfrPrice      = ipx->mfrPrice;
    inventory[idx].retailPrice   = ipx->retailPrice;
    inventory[idx].numInStock    = ipx->numInStock;
    inventory[idx].liveInv       = ipx->liveInv;
    strcpy (inventory[idx].productName, ipx->productName);
    idx++;

    return 0;
}

注意,您的编译器会告诉您无法简单地将ipx->productName分配给inventory[idx].productName,因为它是一个字符数组(转换后char *})。您必须使用strcpy(或strncpy)或简单地遍历(ipx->productName)[],直到达到 nul-terminatedating 字符,将char-by-char复制到{{1 }}

以下内容毫无意义:

inventory[idx].productName[]

(您只能使用 i = sizeof(MAX_INVENTORY)/sizeof(inventory[0]); 在声明数组的范围内获取数组中的元素数( not pointer 。你在上面与正确使用没有任何相似之处。)

sizeof array/sizeof array[0]的剩余部分似乎很好。但是,第一行不inventory.h,它确保标题文件//ensures that inventory.h does not run more than once不会包含多次。

你的inventory.h是 - 创意......至少可以说。您要完成的是将 main()地址(例如sampleData[i])传递给&sampleData[i](例如指向结构的指针,而不是结构本身)

此外,此代码会发生什么?

invSetRecord

回答:什么都没有。 for(i = 0; i < SAMPLE_SZ; i++); 只是更改i的值而不影响任何其他代码。为什么?循环后面的0 - SAMPLE_SZ与:

相同
;

e.g。 - 一个空块。删除循环的 for(i = 0; i < SAMPLE_SZ; i++) {} 以对以下行进行操作。

目前还不清楚你最后要打印什么。假设您希望每个元素都有;,您可以执行以下操作:

productNumber

完全放弃,编译和运行代码将产生以下结果:

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

#include "inventory.h"

#define SAMPLE_SZ 5

extern struct inventory_s inventory[MAX_INVENTORY]; 

struct inventory_s sampleData[] = {
    { 1000, 1.49, 3.79, 10, 0, "Fish Food" },
    { 2000, 0.29, 1.59, 100, 1, "Angelfish" },
    { 2001, 0.09, 0.79, 200, 1, "Guppy" },
    { 5000, 2.40, 5.95, 10, 0, "Dog Collar, Large" },
    { 6000, 49.99, 129.99, 3, 1, "Dalmation Puppy" }
};

int main (void)
{
    int i;

    for (i = 0; i < SAMPLE_SZ; i++)
        if (invSetRecord (&sampleData[i]) == 0)
            printf ("record #%d set successfully.\n", i);
        else {
            fprintf (stderr, "error: could not set record %d.\n", i);
            break;
        }
    putchar ('\n');     /* tidy up output formatting */

    for (i = 0; i < SAMPLE_SZ; i++)
        printf ("sampleData[%2d] : %d\n", i, sampleData[i].productNumber);

    return 0;
}

全神贯注,如果您有任何疑问,请告诉我。只需减慢速度并思考代码的每一行。此外,如果您在三个不同源文件之间分配代码时遇到困难,您可能只想使用单个源文件进行初始开发,然后在完全有意义时将其分成单个文件。这样,您最初只消除了所有代码问题。

有关使用IDE的说明

为了完整起见,您的$ ./bin/main record #0 set successfully. record #1 set successfully. record #2 set successfully. record #3 set successfully. record #4 set successfully. sampleData[ 0] : 1000 sampleData[ 1] : 2000 sampleData[ 2] : 2001 sampleData[ 3] : 5000 sampleData[ 4] : 6000 可能会被遗忘。我做了一些更改(除了个人偏好,例如inventory.h以实际定义#define _INVENTORY_H_ 1的值而不是让它默认值)。我使用了以下内容:

_INVENTORY_H_

如评论中所述,我只是通过命令行中的#ifndef _INVENTORY_H_ #define _INVENTORY_H_ 1 #define PRODUCTNAME_SZ 20 #define MAX_INVENTORY 50 struct inventory_s { int productNumber; float mfrPrice; float retailPrice; int numInStock; char liveInv; char productName[PRODUCTNAME_SZ]; }; int invSetRecord (struct inventory_s *ipx); #endif 调用编译和构建项目。具体来说,我用过:

gcc

所需的基本最小编译字符串是:

$ gcc -Wall -Wextra -pedantic -std=gnu11 -Ofast inventory.c -o main main.c

只是说编译$ gcc inventory.c -o main main.c main.c在名为-o main的文件中输出生成的可执行文件(它可以是你想要的任何内容,main就此而言)最后bananas这告诉编译器除了inventory.c之外,还必须编译并链接main.c中的代码以生成可运行的可执行文件。您可以使用以下命令从命令行运行代码:

inventory.c

其余选项只启用所有编译器警告(因此您可以在考虑代码可靠之前修复它们),$ ./main (or ./bananas if you went that route) 启用所有编译器优化(此处不重要),并设置具有gnu扩展名的C11语言标准。我将在下面进一步解释。

-Ofast只需启用所有编译器警告即可。 (在每个项目中至少使用-Wall -Wextra -pedantic并在您认为代码可靠之前修复所有警告)对于 Codeblocks ,请查看-Wall -Wextra(然后检查Project->Build options...->Compiler Flags的框以及Enable all common compiler warnings ... [-Wall]的下一个框)您还可以检查-Wextra选项,但这会添加另一层微妙的警告,这些警告会在杂草中略微下降以进行初始学习

-pedantic只是告诉编译器使用-std=gnu11(以及C11)进行构建。默认情况下,您可以省略此标志并构建为gnu extensions。 (没关系)

C89只启用所有编译器优化。 -Ofast及更高版本适用于-Ofast优化,否则它们仅为gcc 4.6(即-O0),表示无优化。 Oh zero-O1-O2级别只允许编译器进行越来越积极的优化以加快代码速度 - 例如消除死代码,优化循环等)

对于-O3版本,通常不会启用Debug优化,但在Linux上,请包含-Ofast以生成用于-g调试器的调试符号。 (我认为Codeblocks会自动为您执行此操作)

如果您想首先将gdb零碎地编译为目标文件,然后将目标文件与inventory.c链接以使main.c功能可用于invSetRecord,那么可以这样做:

main

只有这样,将$ gcc -Wall -Wextra -c -o inventory.obj inventory.c 编译到目标文件inventory.c。最后,您只需编译inventory.obj链接main.c以创建最终的可执行文件:

inventory.obj

(选项的顺序并不重要,只需记住您必须在依赖库中代码的源文件之前包含任何所需的。)

这应该允许您编译和链接您的代码(从命令行或在代码块中)。如果再次卡住,请告诉我。