简体   繁体   English

用于构造和复制内容的指针的函数,无需memcpy

[英]function for a pointer to structure and copy it content without memcpy

I'm trying to make a function that points to a single inventory structure(one record) and copies its content to an element in the gobal array defined in inventory.c. 我正在尝试制作一个指向单个清单结构(一个记录)并将其内容复制到清单.c中定义的全局数组中的元素的函数。 I would like to copy them member by member and return an integer -1 if the copies fails. 我想逐个成员复制它们,如果复制失败,则返回整数-1。 In my main fuctionm, I would like to iterate through my sample data and call the invSetRecord function for each element in the sampleData Array. 在我的主要功能中,我想遍历示例数据并为sampleData数组中的每个元素调用invSetRecord函数。 I'm lost on what to do and need some help on this. 我不知道该怎么办,在这方面需要一些帮助。 I updated my inventory.c file. 我更新了清单.c文件。 Im confused on my function. 我对我的功能感到困惑。 I was compiling it by itself. 我是自己编译的。 I dont understand how to get the productName to copy. 我不明白如何获取productName复制。 Any suggestions? 有什么建议么? Also I'm having a hard time set up the counter for the inventory records. 我也很难为库存记录设置计数器。

Here's my instructions from my teacher, 这是我老师的指示,

Use the petstore files created for Lab 9 (Part 2) to complete this assignment. 使用为实验9(第2部分)创建的petstore文件完成此任务。

Copy the following sample data into the petstore_main.c file: 将以下样本数据复制到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" }
};

Define a function in the inventory.c file which has the following prototype (put the prototype in the inventory.h file) inventory.c文件中定义一个具有以下原型的函数(将原型放入inventory.h文件中)

int invSetRecord(struct inventory_s *ipx);

This function will take a pointer to a single inventory structure (a record) and copy its contents to an element in the global array defined in inventory.c . 此函数将使用一个指向单个清单结构(记录)的指针,并将其内容复制到inventory.c .c中定义的全局数组中的元素。 The target location (global array element) will be determined by the current size of the array, if the array is empty then the record is copied into element 0, if the current size is 1 it will be copied into element 1, etc. This means you need to define a global counter in inventory.c which tracks the number of elements in the array. 目标位置(全局数组元素)将由数组的当前大小确定,如果数组为空,则将记录复制到元素0中;如果当前大小为1,则将记录复制到元素1中,依此类推。意味着你需要定义在全局计数器inventory.c其跟踪在阵列中元件的数量。 In the invSetRecord function you will need to copy the structure member by member using a method appropriate to the type, eg simple assignment for the primitive data types, and strcpy() for the string data type. 在invSetRecord函数中,您将需要使用适合于该类型的方法逐个成员复制结构成员,例如,简单分配原始数据类型,并strcpy()分配字符串数据类型。 The function returns an integer value: if the copy operation fails (eg the global inventory array is full), the function returns -1, otherwise it returns 0. 该函数返回一个整数值:如果复制操作失败(例如,全局清单数组已满),则该函数返回-1,否则返回0。

In your main function in petstore_main.c , you will need to create a loop which iterates through the sample data and calls invSetRecord for each element in the sampleData array. petstore_main.c的主要函数中,您需要创建一个循环,循环访问示例数据,并为sampleData数组中的每个元素调用invSetRecord。 For each call to invSetRecord you need to check the return value of the function and print an error if the operation failed or succeeded, and the corresponding record number. 对于每次invSetRecord的调用,您都需要检查函数的返回值并在操作失败或成功的情况下打印错误,以及相应的记录号。 For instance, if the operation succeeds for all 5 sample data records, this is the output printed from your main function: 例如,如果所有5个样本数据记录的操作均成功,则这是从主函数打印的输出:

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

If a call to invSetRecord fails (the function returns -1), the following message is printed: 如果对invSetRecord的调用失败(函数返回-1),则会显示以下消息:

error: could not set record 1

If an error occurs, you must break out of the loop at that point. 如果发生错误,则必须在此时中断循环。

here's what i got so far I need some help. 到目前为止,这是我需要的帮助。 I been pulling my hair out all week trying to figure this one out. 我整周都在拔头发,试图弄清楚这一点。 Thanks in advance for any help. 在此先感谢您的帮助。

//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;



}

heres my inventory.h file... 这是我的清单.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_

heres my main() file... 这是我的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;
}

Let's start with the simple issues where your compiler is throwing errors and warnings: 让我们从编译器抛出错误和警告的简单问题开始:

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

struct inventory_s inventory[MAX_INVENTORY];
int i;

How many times do you need to declare i ? 多少次,你需要声明i There is no reason for #define invSetRecord main . #define invSetRecord main没有理由。 As a note, when declaring a global, a more distinctive name than the very common i is advisable. 作为一个说明,声明全局的时候,更与众不同的名字不是很常见的i是可取的。

In invSetRecord , (using idx (index) for your i ), why not simply do: invSetRecord ,(将i用作idx (索引)),为什么不简单地做一下:

/* 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;
}

Note, your compiler will be telling you you cannot simply assign ipx->productName to inventory[idx].productName since it is a character array (well char * after conversion). 注意,您的编译器会告诉您,您不能简单地将ipx->productName分配给ipx->productName inventory[idx].productName因为它是一个字符数组(转换后为char * )。 You must use strcpy (or strncpy ) or simply iterate over (ipx->productName)[] until the nul-terminating character is reached copying char-by-char to inventory[idx].productName[] . 您必须使用strcpy (或strncpy )或简单地遍历(ipx->productName)[]直到达到nul终止字符为止,将逐个字符复制到inventory[idx].productName[]

The following makes no sense at all: 以下内容完全没有意义:

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

(you can only get the number of elements in an array ( not pointer ) in the scope where the array is declared by using sizeof array/sizeof array[0] . What you have above has no resemblance to the proper use.) (您只能通过使用sizeof array/sizeof array[0] 在声明数组的范围内的数组中的元素数量( 而不是指针 )。上面的内容与正确使用并不相似。)

The remainder of your inventory.h seems fine. 您的inventory.h剩余部分。 However the first line does NOT //ensures that inventory.h does not run more than once it insures that the header file inventory.h is not included more than once. 但是第一行并不能//ensures that inventory.h does not run more than once而是确保头文件inventory.h .h不被包含多次。

Your main() is -- creative... to say the least. 至少可以说,您的main()很有创意。 What you are trying to accomplish is passing the address of sampleData[i] (eg &sampleData[i] ) to invSetRecord (eg a pointer to the struct, not the struct itself). 您要完成的工作是将sampleData[i] (例如&sampleData[i] )的地址传递给invSetRecord (例如,指向结构的指针,而不是结构本身)。

Further, what happens with this code? 此外,此代码会发生什么?

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

answer : nothing. :没事。 i simply changes value from 0 - SAMPLE_SZ without effecting any other code. i只是将值从0 - SAMPLE_SZ更改为0 - SAMPLE_SZ而不会影响任何其他代码。 Why? 为什么? The ; ; following the loop is the same as: 循环如下:

    for(i = 0; i < SAMPLE_SZ; i++) {}

eg -- an empty block. 例如-一个空块。 Remove the ; 删除; for the loop to operate on the following line. 使循环在下一行运行。

It is unclear what you are trying to print at the end. 目前尚不清楚最后要打印什么。 Presuming you want the productNumber for every element, you could do something like the following: 假设您需要每个元素的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;
}

Putting it altogether, compiling and running the code will produce the following: 综上所述,编译并运行代码将产生以下结果:

$ ./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

Look it all over and let me know if you have any questions. 仔细看一遍,如果您有任何疑问,请告诉我。 Just slow down and think through each line of the code. 放慢速度,仔细考虑代码的每一行。 Also, if you are having difficulty with the code split between three different source files, you may want to simply use a single source file for initial development, then separate into the individual files when it all makes sense. 另外,如果您难以在三个不同的源文件之间分割代码,则可能只想使用单个源文件进行初始开发,然后在需要时将其分成单独的文件。 That way, you eliminate all but just the code issues initially. 这样,您可以消除最初的所有代码问题,而不仅仅是代码问题。


Notes about using the IDE 有关使用IDE的注意事项

For sake of completeness, your inventory.h could be left pretty much as you have it. 为了完整起见,您的inventory.h可能会保留得差不多。 I made few changes (other than personal preference, eg #define _INVENTORY_H_ 1 to actually define a value for _INVENTORY_H_ rather than letting it default). 我进行了一些更改(除了个人喜好,例如, #define _INVENTORY_H_ 1 define #define _INVENTORY_H_ 1实际上为_INVENTORY_H_定义了一个值,而不是默认设置)。 I used the following: 我使用了以下内容:

#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

As noted in the comments, I simply compiled and built the project with a single call to gcc from the command line. 如注释中所述,我仅通过从命令行调用gcc即可简单地编译和构建了项目。 Specifically I used: 我特别使用了:

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

The basic, minimum compile string required is: 所需的基本最小编译字符串为:

$ gcc inventory.c -o main main.c

Which just says compile main.c , -o main outputting the resulting executable in a file named main (it can be whatever you want, bananas for that matter) and finally inventory.c which is what tells the compiler that in addition to main.c it must compile and link the code in inventory.c in order to produce a working executable. 上面只说了编译main.c-o main将生成的可执行文件输出到名为main的文件中(它可以是您想要的任何东西, bananas就可以了),最后是inventory.c ,它告诉编译器除main.c它必须编译和链接代码inventory.c以产生一个工作可执行文件。 You run the code from the command line with: 您可以使用以下命令从命令行运行代码:

$ ./main     (or ./bananas if you went that route)

The remaining options just enable all compiler warnings (so you can fix them before considering your code reliable), -Ofast enable all compiler optimizations (not that critical here), and sets the language standard to C11 with gnu extensions. 其余的选项仅启用所有编译器警告 (因此您可以在考虑代码可靠之前对其进行修复),- -Ofast启用所有编译器优化(此处并不重要),并将语言标准设置为具有gnu扩展的C11。 I'll explain a bit further below. 我将在下面进一步解释。

-Wall -Wextra -pedantic simply enable all compiler warnings . -Wall -Wextra -pedantic只需启用所有编译器警告 (use at minimum -Wall -Wextra with every project and fix all warnings before you consider your code reliable) For Codeblocks look in Project->Build options...->Compiler Flags (then check the box for Enable all common compiler warnings ... [-Wall] , and the next box for -Wextra ) You can also check the -pedantic option, but that adds another layer of subtle warnings that get a bit down in the weeds for initial learning. (至少使用-Wall -Wextra与每一个项目和解决所有的警告你认为你的代码可靠前) 代码块的样子在Project->Build options...->Compiler Flags (然后勾选为Enable all common compiler warnings ... [-Wall]以及-Wextra的下一个框)您还可以选中-pedantic选项,但是这又添加了一层细微的警告,这些杂草对初次学习的杂草有所影响。

The -std=gnu11 just tells the compiler to build with C11 (and the gnu extensions ). -std=gnu11只是告诉编译器使用C11 (和gnu extensions )进行编译。 You can omit this flag and build to C89 by default. 您可以忽略此标志,默认情况下构建到C89 (which is fine) (很好)

The -Ofast just enables all compiler optimizations. -Ofast仅启用所有编译器优化。 The -Ofast optimization is available for gcc 4.6 and above, otherwise they are just -O0 (that's Oh zero ) meaning no optimization. -Ofast优化可用于gcc 4.6及更高版本,否则它们只是-O0 (即Oh zero ),意味着没有优化。 The -O1 or -O2 and -O3 levels just allow the compiler to make increasingly aggressive optimization to speed the code up -- like eliminating dead code, optimizing loops, etc) -O1-O2-O3级别仅允许编译器进行更具侵略性的优化以加快代码的速度-例如消除无效代码,优化循环等)

For your Debug builds, you will generally not enable -Ofast optimization, but on Linux, include -g instead to generate debugging symbols for use with the gdb debugger. 对于Debug构建,通常不会启用-Ofast优化,但是在Linux上,请包括-g来生成调试符号以与gdb调试器一起使用。 (I think Codeblocks does this for you automatically) (我认为Codeblocks会自动为您完成此操作)

If you want to piecemeal compile to inventory.c to an object file first and then link the object file with main.c to make the invSetRecord function available to main , you could do: 如果你想零碎编译成inventory.c第一个目标文件,然后链接与目标文件main.c ,使invSetRecord功能提供给main ,你可以这样做:

$ gcc -Wall -Wextra -c -o inventory.obj inventory.c

Which does just that, compile inventory.c to the object file inventory.obj . 这做到了这一点,编译inventory.c到目标文件inventory.obj Finally, you would just compile main.c linking inventory.obj to create the final executable: 最后,您只需编译main.c链接inventory.obj main.c以创建最终的可执行文件:

$ gcc -Wall -Wextra -o main inventory.obj main.c

(the order of the options isn't that important, just remember you must include any needed libraries before the source files that rely on code from the library.) (选项的顺序并不重要,只要记住您必须依赖于从库中代码的源文件之前,任何需要的 )。

That should allow you to compile and link your code (either from the command line or in codeblocks). 那应该允许您编译和链接代码(从命令行或在代码块中)。 If you get stuck again, let me know. 如果您再次卡住,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM