簡體   English   中英

如何將結構從函數返回到結構指針?

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

我正在為代碼創建一個函數,該代碼使用輸出到文件指針的函數,例如,

number *base6 = intToNumber(50, 6); 

這是我到目前為止的代碼:

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

}

您開始按照正確的theNumbers思考,但是您對theNumbers分配的處理(您已發表評論)只是第一步。 當您分配theNumbers ,會創建指針theNumbers->sNum - 但它是一個未初始化的指針,它持有一個不確定的地址作為其值。 (例如,它無處指向您有任何能力利用)。 想想你的結構( 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 */

當您為其中之一分配時,您將分配 2 個整數值和 1 個具有自動存儲類型且可以賦值的字符指針。 雖然iNumbase是整數值並且可以分配立即值,例如506 ,但sNum相比之下是一個指針,只能分配一個有效的內存地址來存儲其他內容。

通常,要使用指針,您需要分配一個新的內存塊,用該類型所需的任何內容填充該內存,然后將該新內存塊的起始地址分配給您的指針(此處為sNum )。 所以現在您的指針將保存(例如指向)包含該對象類型可用值的有效內存塊的地址。 char* ,指向char*的指針,此處)

你的intToNumber函數只接受int nnumint nbase作為參數,所以在為你的struct分配之后,你只能初始化theNumbers->iNum = nnum; theNumbers->base = nbase; ,但沒有任何大小或初始化sNum (因此應設置為NULL )。

所以你接近你的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 */
}

現在如何處理sNum 好吧,這取決於您,但是例如,您可以創建一個單獨的函數,將分配的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) */
}

(我懷疑你會用你的 base6 轉換來填充它——但這留給你)

除了在完成后釋放內存之外,剩下的就是一個簡短的示例,展示如何完全放置它。 你可以做一些簡單的事情,比如:

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

示例使用/輸出

如果你把這個例子放在一起,你會得到:

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

內存使用/錯誤檢查

在你寫的,可動態分配內存的任何代碼,您有任何關於分配的內存任何塊2個職責:(1)始終保持一個指針的起始地址的存儲器中,以便塊,(2),當它是沒有它可以被釋放不再需要。

您必須使用內存錯誤檢查程序來確保您不會嘗試訪問內存或寫入超出/超出分配塊的邊界,嘗試讀取或基於未初始化值的條件跳轉,最后,確認你釋放了你分配的所有內存。

對於 Linux valgrind是正常的選擇。 每個平台都有類似的內存檢查器。 它們都易於使用,只需通過它運行您的程序即可。

$ 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)

始終確認您已釋放所有分配的內存並且沒有內存錯誤。

使用的完整示例是:

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

假設實際問題正是標題中提出的問題:

如何將結構從函數返回到結構指針?

答案是,雖然函數可以返回一個結構,它不能做這樣一個struct指針 在任何情況下都不能將結構分配給任何指針類型的對象。 您可以擁有指向結構的指針,也可以擁有包含指針的結構,但沒有結構本身就是指針。

另一方面,如果問題是關於如何返回結構指針,那么答案將是“通過使用return語句”,與返回任何其他類型的值的方式相同。 為了使之有用,您返回的指針應該是有效的,但這是一個單獨的問題。

為什么不在函數中傳遞指向結構的指針,使簽名看起來像void intToNumber(number *n) 然后你的實現看起來像

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

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

    // Do some more stuff...
}

由於您指向堆棧上的變量Numbers ,您可以在函數intToNumber操作這些變量,並使它們在main函數的其余部分(或您決定調用它的任何范圍內)可用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM