Retourneer een` struct “van een functie in C

Vandaag leerde ik een paar vrienden om C structS te gebruiken. Een van hen heeft gevraagd of u een structvan een functie zou kunnen retourneren, waarvan ik antwoordde: “Nee! U zou aanwijzingen terugkeren naar dynamisch mallocED structS in plaats daarvan. “

Afkomstig van iemand die voornamelijk C++ doet, verwachtte ik niet in staat om structs door waarden te retourneren. In C++ kunt u de operator =voor uw objecten overbelasten en volledig logisch vindt om een ​​functie te hebben om uw object per waarde te retourneren. In C heb je echter niet die optie en dus kreeg het me aan het denken wat de compiler daadwerkelijk doet. Overweeg het volgende:

struct MyObj{
    double x, y;
};
struct MyObj foo(){
    struct MyObj a;
    a.x = 10;
    a.y = 10;
    return a;
}        
int main () {
    struct MyObj a;
    a = foo();    // This DOES work
    struct b = a; // This does not work
    return 0;
}    

Ik begrijp waarom struct b = a;MOET NIET WERKEN – U kunt niet overbelasten operator =voor uw gegevenstype. Hoe is het dat a = foo();compiles boete? Betekent het iets anders dan struct b = a;? Misschien is de vraag om te stellen: wat doet precies de returnverklaring in combinatie met =teken doen?


Antwoord 1, Autoriteit 100%

Je kunt zonder problemen een structuur van een functie retourneren (of de operator =gebruiken). Het is een goed gedefinieerd deel van de taal. Het enige probleem met struct b = ais dat je geen volledig type hebt opgegeven. struct MyObj b = awerkt prima. U kunt ook structuren aan-functies doorgeven – een structuur is precies hetzelfde als elk ingebouwd type voor het doorgeven van parameters, retourwaarden en toewijzing.

Hier is een eenvoudig demonstratieprogramma dat alle drie doet – een structuur doorgeeft als parameter, een structuur retourneert van een functie en structuren gebruikt in toewijzingsinstructies:

#include <stdio.h>
struct a {
   int i;
};
struct a f(struct a x)
{
   struct a r = x;
   return r;
}
int main(void)
{
   struct a x = { 12 };
   struct a y = f(x);
   printf("%d\n", y.i);
   return 0;
}

Het volgende voorbeeld is vrijwel exact hetzelfde, maar gebruikt het ingebouwde type intvoor demonstratiedoeleinden. De twee programma’s hebben hetzelfde gedrag met betrekking tot pass-by-waarde voor het doorgeven van parameters, toewijzing, enz.:

#include <stdio.h>
int f(int x) 
{
  int r = x;
  return r;
}
int main(void)
{
  int x = 12;
  int y = f(x);
  printf("%d\n", y);
  return 0;
}

Antwoord 2, autoriteit 16%

Bij een aanroep zoals a = foo();, kan de compiler het adresvan de resultaatstructuur op de stapel duwen en het doorgeven als een “verborgen ” aanwijzer naar de functie foo(). In feite zou het zoiets kunnen worden als:

void foo(MyObj *r) {
    struct MyObj a;
    // ...
    *r = a;
}
foo(&a);

De exacte implementatie hiervan is echter afhankelijk van de compiler en / of platform. Zoals Carl Norum opmerkt, als de structuur klein genoeg is, kan het zelfs volledig in een register worden teruggegeven.


Antwoord 3, Autoriteit 7%

De struct bLijn werkt niet omdat het een syntaxisfout is. Als u het uitbreidt om het type op te nemen dat het prima werkt

struct MyObj b = a;  // Runs fine

Wat het hier is, is in wezen een memcpyvan de bronstruct naar de bestemming. Dit geldt voor zowel toewijzing als teruggave van structwaarden (en echt elke andere waarde in c)


Antwoord 4, Autoriteit 4%

Voor zover ik kan herinneren, mogen de eerste versies van C alleen een waarde die alleen terugsturen
kan in een processorregister passen, wat betekent dat u alleen een aanwijzer kunt retourneren
een struct. Dezelfde beperking toegepast op functieargumenten.

Meer recente versies laten toe om grotere gegevensobjecten zoals structuren door te geven.
Ik denk dat deze functie al vaak voorkomt tijdens de jaren tachtig of begin jaren negentig.

Arrays kunnen echter nog steeds worden doorgegeven en alleen als aanwijzers geretourneerd.


Antwoord 5, Autoriteit 4%

Ja, het is mogelijk dat we ook structuur en retourstructuur kunnen passeren. Je had gelijk, maar je hebt het gegevenstype daadwerkelijk niet gepasseerd, wat als deze struct Myobj B = A zou moeten zijn.

Eigenlijk kwam ik ook weten wanneer ik probeerde een betere oplossing te vinden om meer dan één waarden voor functie te retourneren zonder aanwijzer of globale variabele te gebruiken.

Nu hieronder is het voorbeeld voor hetzelfde, dat de afwijking van een studentenmarkeringen over het gemiddelde berekent.

#include<stdio.h>
struct marks{
    int maths;
    int physics;
    int chem;
};
struct marks deviation(struct marks student1 , struct marks student2 );
int main(){
    struct marks student;
    student.maths= 87;
    student.chem = 67;
    student.physics=96;
    struct marks avg;
    avg.maths= 55;
    avg.chem = 45;
    avg.physics=34;
    //struct marks dev;
    struct marks dev= deviation(student, avg );
    printf("%d %d %d" ,dev.maths,dev.chem,dev.physics);
    return 0;
 }
struct marks deviation(struct marks student , struct marks student2 ){
    struct marks dev;
    dev.maths = student.maths-student2.maths;
    dev.chem = student.chem-student2.chem;
    dev.physics = student.physics-student2.physics; 
    return dev;
}

Antwoord 6, Autoriteit 3%

Er is geen probleem bij het passeren van een struct. Het wordt gepasseerd door waarde

Maar, wat als de struct een lid bevat dat een adres heeft van een lokale variabele

struct emp {
    int id;
    char *name;
};
struct emp get() {
    char *name = "John";
    struct emp e1 = {100, name};
    return (e1);
}
int main() {
    struct emp e2 = get();
    printf("%s\n", e2.name);
}

Nu, hier e1.nameBevat een geheugenadres lokaal in de functie get().
Eenmaal get()Retourneren, het lokale adres voor naam zou zijn vrijgemaakt.
Dus in de beller als we proberen toegang te krijgen tot dat adres, kan het een segmentatiefout veroorzaken, omdat we een vrijgesteld adres proberen. Dat is slecht ..

Indien de e1.idperfect geldig zal zijn als zijn waarde wordt gekopieerd naar e2.id

Dus moeten we altijd proberen om lokale geheugenadressen van een functie te retourneren.

Alles malloced kan worden geretourneerd als en wanneer gewenst


Antwoord 7, Autoriteit 2%

U kuntstructs toewijzen in C. a = b;is een geldige syntaxis.

Je hebt gewoon een deel van het type – de struct-tag – in je regel weggelaten die niet werkt.


Antwoord 8

struct emp {
    int id;
    char *name;
};
struct emp get() {
    char *name = "John";
    struct emp e1 = {100, name};
    return (e1);
}
int main() {
    struct emp e2 = get();
    printf("%s\n", e2.name);
}

werkt prima met nieuwere versies van compilers.
Net als id wordt de inhoud van de naam gekopieerd naar de toegewezen structuurvariabele.


Antwoord 9

struct var e2-adres gepusht als arg naar callee-stack en waarden worden daar toegewezen. In feite retourneert get() het adres van e2 in eax reg. Dit werkt als call by reference.

Other episodes