简体   繁体   English

如何将结构从函数返回到结构指针?

[英]How do I return a struct from a function to a struct pointer?

I am creating a function for a code and the code uses the function that outputs to a file pointer like for example,我正在为代码创建一个函数,该代码使用输出到文件指针的函数,例如,

number *base6 = intToNumber(50, 6); 

Here is the code I have so far:这是我到目前为止的代码:

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

typedef struct {
  int iNum;
  int base;
  char* sNum;
} number;

number * intToNumber(int nnum, int nbase) {
  number * theNumbers;

  //theNumbers= (number*)malloc(10*sizeof(number));

  if (theNumbers = NULL) {
    printf("\n\nNo\n\n");
    exit(1);
  }

  theNumbers->iNum = nnum;
  theNumbers->base = nbase;

}

You are beginning to think along the correct lines, but your handling of allocation for your theNumbers (you have commented) is just step one.您开始按照正确的theNumbers思考,但是您对theNumbers分配的处理(您已发表评论)只是第一步。 When you allocate theNumbers , the pointer theNumbers->sNum is created -- but it is an Uninitialized Pointer that holds an indeterminate address as its value.当您分配theNumbers ,会创建指针theNumbers->sNum - 但它是一个未初始化的指针,它持有一个不确定的地址作为其值。 (eg it points nowhere you have any ability to make use of). (例如,它无处指向您有任何能力利用)。 Think about your struct ( typedef )想想你的结构( typedef

typedef struct {
    int iNum;   /* automatic storage types */
    int base;
    char *sNum; /* a pointer - hold address to something else  */
} number;       /*             must point to valid memory addr */

When you allocate for one of those, you allocate 2 integer values and one character pointer that have automatic storage type and can be assigned values.当您为其中之一分配时,您将分配 2 个整数值和 1 个具有自动存储类型且可以赋值的字符指针。 While iNum and base are integer values and can be assigned immediate values like 50 and 6 , sNum by contrast is a pointer and can only be assigned a valid memory address where something else is stored.虽然iNumbase是整数值并且可以分配立即值,例如506 ,但sNum相比之下是一个指针,只能分配一个有效的内存地址来存储其他内容。

Normally, to make use of a pointer, you allocate a new block of memory, fill that memory with whatever is needed for the type, and then assign the starting address for that new block of memory to your pointer ( sNum here).通常,要使用指针,您需要分配一个新的内存块,用该类型所需的任何内容填充该内存,然后将该新内存块的起始地址分配给您的指针(此处为sNum )。 So now your pointer will hold the address of (eg point to) a valid block of memory containing values usable by that object type.所以现在您的指针将保存(例如指向)包含该对象类型可用值的有效内存块的地址。 ( char* , a pointer to a char, here) char* ,指向char*的指针,此处)

Your intToNumber function takes only int nnum and int nbase as parameters, so after allocating for your struct , you can only initialize theNumbers->iNum = nnum;你的intToNumber函数只接受int nnumint nbase作为参数,所以在为你的struct分配之后,你只能初始化theNumbers->iNum = nnum; and theNumbers->base = nbase;theNumbers->base = nbase; , but have nothing to size or initialize sNum with (it should therefore be set to NULL ). ,但没有任何大小或初始化sNum (因此应设置为NULL )。

So you are close on your intToNumber , and all you need to do is return the pointer intToNumber after you have allocated storage for it (because following allocation it has allocated storage type which survives for the life of the program -- or until it is freed), eg所以你接近你的intToNumber ,你需要做的就是在你为它分配存储后返回指针intToNumber (因为在分配之后它分配了在程序生命周期中存活的存储类型- 或者直到它被释放),例如

number *intToNumber (int nnum, int nbase) {

    number *theNumbers;

    theNumbers= malloc (sizeof *theNumbers);    /* allocate */

    if (theNumbers == NULL) {                   /* validate */
        perror ("malloc-theNumbers");
        return NULL;
    }

    theNumbers->iNum = nnum;    /* initialize values */
    theNumbers->base = nbase;
    theNumbers->sNum = NULL;

    return theNumbers;          /* return pointer */
}

Now what to do about sNum ?现在如何处理sNum Well, it's up to you, but for example, you could create a separate function that takes your allocated struct and a character string as parameters, allocate for length + 1 bytes to hold the string (plus the nul-terminating character) assigning the starting address for the new bock to sNum , and then copying the string to the new block of memory, eg好吧,这取决于您,但是例如,您可以创建一个单独的函数,将分配的struct和字符串作为参数,分配length + 1个字节来保存字符串(加上空终止字符)分配起始新块的地址到sNum ,然后将字符串复制到新的内存块,例如

/* allocate/set sNum member of n to s */
char *setsNum (number *n, const char *s)
{
    if (!n) {   /* validate n not NULL, return NULL on failure */
        fputs ("error: struct parameter 'n' NULL.\n", stderr);
        return NULL;
    }
    size_t len = strlen (s);        /* get length */

    n->sNum = malloc (len + 1);     /* allocate storage (+1 byte) */

    if (!n->sNum) {                 /* validate allocation */
        perror ("malloc-sNum");
        return NULL;
    }

    memcpy (n->sNum, s, len + 1);   /* copy s to new block of memory */

    return n->sNum;                 /* return pointer (convenience) */
}

(I suspect you will be filling it with your base6 conversion -- but that is left to you) (我怀疑你会用你的 base6 转换来填充它——但这留给你)

Other than freeing the memory when you are done with it, all that remains is a short example showing how to put it altogether.除了在完成后释放内存之外,剩下的就是一个简短的示例,展示如何完全放置它。 That you can do with something simple like:你可以做一些简单的事情,比如:

int main (void) {

    number *mynum = intToNumber (50, 6);    /* declare/initialize mynum */

    if (!mynum)     /* validate succeeded */
        return 1;

    /* allocate/validate mynum->sNum, copy string */
    if (!setsNum (mynum, "created with intToNumber (50, 6)")) {
        free (mynum);
        return 1;
    }
    /* output values held in mynum */
    printf ("succeeded:\n iNum: %d\n base: %d\n str : %s\n",
            mynum->iNum, mynum->base, mynum->sNum);

    free (mynum->sNum); /* free allocated string */
    free (mynum);       /* free struct */
}

Example Use/Output示例使用/输出

If you put the example together, you would get:如果你把这个例子放在一起,你会得到:

$ ./bin/struct_alloc_member
succeeded:
 iNum: 50
 base: 6
 str : created with intToNumber (50, 6)

Memory Use/Error Check内存使用/错误检查

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.在你写的,可动态分配内存的任何代码,您有任何关于分配的内存任何块2个职责:(1)始终保持一个指针的起始地址的存储器中,以便块,(2),当它是没有它可以被释放不再需要。

It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出分配块的边界,尝试读取或基于未初始化值的条件跳转,最后,确认你释放了你分配的所有内存。

For Linux valgrind is the normal choice.对于 Linux valgrind是正常的选择。 There are similar memory checkers for every platform.每个平台都有类似的内存检查器。 They are all simple to use, just run your program through it.它们都易于使用,只需通过它运行您的程序即可。

$ valgrind ./bin/struct_alloc_member
==15553== Memcheck, a memory error detector
==15553== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==15553== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==15553== Command: ./bin/struct_alloc_member
==15553==
succeeded:
 iNum: 50
 base: 6
 str : created with intToNumber (50, 6)
==15553==
==15553== HEAP SUMMARY:
==15553==     in use at exit: 0 bytes in 0 blocks
==15553==   total heap usage: 2 allocs, 2 frees, 49 bytes allocated
==15553==
==15553== All heap blocks were freed -- no leaks are possible
==15553==
==15553== For counts of detected and suppressed errors, rerun with: -v
==15553== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Always confirm that you have freed all memory you have allocated and that there are no memory errors.始终确认您已释放所有分配的内存并且没有内存错误。

The full example used was:使用的完整示例是:

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

typedef struct {
    int iNum;   /* automatic storage types */
    int base;
    char *sNum; /* a pointer - hold address to something else  */
} number;       /*             must point to valid memory addr */

number *intToNumber (int nnum, int nbase) {

    number *theNumbers;

    theNumbers= malloc (sizeof *theNumbers);    /* allocate */

    if (theNumbers == NULL) {                   /* validate */
        perror ("malloc-theNumbers");
        return NULL;
    }

    theNumbers->iNum = nnum;    /* initialize values */
    theNumbers->base = nbase;
    theNumbers->sNum = NULL;

    return theNumbers;          /* return pointer */
}

/* allocate/set sNum member of n to s */
char *setsNum (number *n, const char *s)
{
    if (!n) {   /* validate n not NULL, return NULL on failure */
        fputs ("error: struct parameter 'n' NULL.\n", stderr);
        return NULL;
    }
    size_t len = strlen (s);        /* get length */

    n->sNum = malloc (len + 1);     /* allocate storage (+1 byte) */

    if (!n->sNum) {                 /* validate allocation */
        perror ("malloc-sNum");
        return NULL;
    }

    memcpy (n->sNum, s, len + 1);   /* copy s to new block of memory */

    return n->sNum;                 /* return pointer (convenience) */
}

int main (void) {

    number *mynum = intToNumber (50, 6);    /* declare/initialize mynum */

    if (!mynum)     /* validate succeeded */
        return 1;

    /* allocate/validate mynum->sNum, copy string */
    if (!setsNum (mynum, "created with intToNumber (50, 6)")) {
        free (mynum);
        return 1;
    }
    /* output values held in mynum */
    printf ("succeeded:\n iNum: %d\n base: %d\n str : %s\n",
            mynum->iNum, mynum->base, mynum->sNum);

    free (mynum->sNum); /* free allocated string */
    free (mynum);       /* free struct */
}

Supposing that the actual question is exactly what is presented in the title:假设实际问题正是标题中提出的问题:

How do I return a struct from a function to a struct pointer?如何将结构从函数返回到结构指针?

The answer is that although a function can return a struct, it cannot do so to a struct pointer .答案是,虽然函数可以返回一个结构,它不能做这样一个struct指针 Under no circumstance can you assign a struct to an object of of any pointer type.在任何情况下都不能将结构分配给任何指针类型的对象。 You can have a pointer to a struct, and you can have a struct that contains a pointer, but no struct is itself a pointer.您可以拥有指向结构的指针,也可以拥有包含指针的结构,但没有结构本身就是指针。

If, on the other hand, the question were about how to return a struct pointer then the answer would be "by using a return statement", the same way you return a value of any other type.另一方面,如果问题是关于如何返回结构指针,那么答案将是“通过使用return语句”,与返回任何其他类型的值的方式相同。 For that to be useful, the pointer you return ought to be a valid one, but that's a separate question.为了使之有用,您返回的指针应该是有效的,但这是一个单独的问题。

Why don't you pass in a pointer to the structure in the function such that the signature looks like void intToNumber(number *n) ?为什么不在函数中传递指向结构的指针,使签名看起来像void intToNumber(number *n) And then you would have the implementation look something like然后你的实现看起来像

int main ()
{
    number Numbers = {.sNum = malloc (25) };

    // Do stuff here...
    intToNumber(&Numbers);

    // Do some more stuff...
}

Since you are pointing to the variable Numbers on the stack, you can manipulate those variable in the function intToNumber and have them available in the rest of the main function (or in whatever scope you decide to call it).由于您指向堆栈上的变量Numbers ,您可以在函数intToNumber操作这些变量,并使它们在main函数的其余部分(或您决定调用它的任何范围内)可用。

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

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