我试图创建一个指向单个库存结构(一个记录)的函数,并将其内容复制到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;
}
答案 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
(选项的顺序并不重要,只需记住您必须在依赖库中代码的源文件之前包含任何所需的库。)
这应该允许您编译和链接您的代码(从命令行或在代码块中)。如果再次卡住,请告诉我。