Küsimus:
Funktsiooni int massiivi tagastamine
Dat Ha
2016-10-14 23:36:07 UTC
view on stackexchange narkive permalink

Mul on funktsioon, mis peab tagastama 3 int-väärtust. Praegu kasutan globaalses ulatuses deklareeritud massiivi ja palun funktsioonil nendesse kirjutada. Kas on võimalik panna funktsioon massiivi tagastama?

Siin on see, mida ma tahan teha:

  int function () {int array [3]; array [ 0] = 19; // need on lihtsalt juhuslikud arvudray [1] = 7; massiiv [2] = 69; return massiiv []; // kas see on võimalik ??}  
See ei tööta või vähemalt mitte usaldusväärselt: mällu saab tagasi tuua ainult osuti, mida enam ei eraldata (halb). Saate massiivi tagastada struktuuri sisse põimituna. Kuna see on ainult 3 inti, peaks see korras olema.
See vastas tegelikult minu küsimusele. Te oleksite pidanud selle vastuseks panema, ma aktsepteerin seda.
Kolm vastused:
Edgar Bonet
2016-10-15 01:36:51 UTC
view on stackexchange narkive permalink

Soovitud eesmärgi saavutamiseks on mitu võimalust:

viis, mis ei tööta

Kas proovisite koostada küsimuses antud koodi? Siis ilmselt märkasite, et see ei koosta. Proovisin ja sain: "error: eeldatav esmane-avaldis enne ']' märki", mis tähendab, et koostaja ootas return massiiv [some_index]; .

Peaaegu töötav viis

Eemaldage sulgud ja tagastage lihtsalt array:

  int * function () {int array [3]; massiiv [0] = 19; massiiv [1] = 7; massiiv [2] = 69; return array;}  

Sõltuvalt ümbritsevast koodist võib see toimida või mitte selles, kuidas optimeerija teie programmi töötleb ja kui õnne teil testimise ajal on. Seda nimetatakse määratlemata käitumiseks ja seda peaksite alati vältima.

Nii juhtub: C-s (ja C ++) ei saa massiivi tagastada. Identifikaator array laguneb selle esimesele elemendile osutava osuti juurde. Siis return array on põhimõtteliselt samaväärne väärtusega return &array [0] . Probleem on selles, et kuna massiiv on eraldatud funktsiooni virnaraamis, siis funktsiooni naastes lakkab see olemast, nii et callergetid osutavad mälupiirkonnale, mida enam ei eraldata. Eeldatav on tõenäoliselt mälu rikkumine. Koostaja hoiatas mind, kui proovisin todot, et: "hoiatus: kohaliku muutuja" massiivi "aadress saadeti tagasi". See on väga tõsine hoiatus, mida ei tohiks kunagi ignoreerida.

Lihtsaim lahendus: massiivi muutmine staatiliseks

Nagu Chris Stratton kommentaaris soovitas, saate massiivi muuta staatiliseks, nii et see eraldada kogu programmi eluks:

  int * function () {static int array [3]; massiiv [0] = 19; massiiv [1] = 7; massiiv [2] = 69; return array;}  

Ainus takistus on see, et funktsioon pole nüüd reentrant , mis tähendab, et iga kord, kui seda nimetate, varjab sama massiivi, mille ta eelmisel korral tagastas kõned. Sõltuvalt teie kasutusjuhtumist ei pruugi see probleem olla, kuid see on midagi, mida peate teadma.

Las helistaja haldab jaotust

Turvalisem (uuesti sisenev) viis on lasta helistajal pakkuda massiivi jaoks vajalikku mälu. See on C-s väga levinud meetod ja seda pakuvad nii Harper Shelby vastus kui ka Chris Strattoni kommentaar:

  int * funktsioon (int massiiv [3]) {array [0] = 19; massiiv [1] = 7; massiiv [2] = 69; return array;}  

Helistaja saab eraldada staatilises mälus või oma virna raamis või kuhja peal ... aga see ei huvita, eraldamine on nüüd helistaja probleem .

Siinkohal tuleb märkida paar asja:

  • Prototüüp on samaväärne funktsiooniga int * (int * array) : funktsioon saab ainult osuti. massiivi [3] kirjutamine * array asemel on ainsana dokumenteerimine see, et funktsioon eeldab, et kursor osutab kuhugi, kus on ruumi 3 väärtusele . Selle võiksite dokumenteerida hoopis kommentaaris.
  • Funktsioon võib tagastada void , kuna helistaja teab arvatavasti aadressi, mille ta teile annab. Sama aadressi tagastamine on lihtsalt ebamugavus, kuna see võib aidata teil kette kutsuda nagu another_function (function (array)) .

Massiivi tagastamine struktuuris

Võib imestada: miks me ei saaks massiivi üldse tagastada. Ma ei tea kindlalt, miks keele autorid selle valiku tegid, kuid üks võimalik seletus on see, et suure massiivse väärtuse tagastamine on kallis, kuna see hõlmab kogu selle kopeerimist. Kui nüüd on teie massiiv tegelikult ainult kolm inti, siis see argument ei kehti ja võite põhjendatult soovida kogu massiivi väärtuse järgi tagastada. See võib hõlbustada, kinnistades selle struktuuri:

  // Struct definition.struct Array3 {int array [3];}; Array3 function () {Array3 a; a.array [0] = 19; a.array [1] = 7; a.array [2] = 69; tagastage a;}  
Kes neist kasutaks vähem võimalikku mälu?
Massiivi muutmine globaalseks ja mõlema funktsiooni (helistaja ja kutsutud) * eeldamine * selle massiivi kasutamine eeldab ruumi vaid 3-le (6-baidisele), kuid need jäävad kogu programmi käivitamiseks reserveeritud, olenemata sellest, kas need on kasutusel või mitte. Teine võimalus on, et helistaja eraldaks massiivimälu oma virnas ja edastaks kutsutud funktsiooni sellele osuti. See ei kasuta mitte ainult kolme inti, vaid ka mälu ka kursori jaoks (kui kompilaator ei otsusta kursorit registrites edastada - kuid lubab halvimal juhul eeldada, et see edastatakse virna mälus). ...
... Siis on kursori lisamälu (veel kaks baiti), kuid osuti mälu on reserveeritud ainult siis, kui kutsutud funktsioon töötab. Massiiv ise on reserveeritud ainult siis, kui helistaja (ja seega kutsutud) funktsioon on aktiivne. Kui helistaja naaseb * oma * helistaja juurde, muutub massiiviruum vabaks. Mis siis kasutab vähem mälu? See sõltub sellest, millal te vaatate!
Nick Gammon
2016-10-15 08:35:44 UTC
view on stackexchange narkive permalink

Mul on funktsioon, mis peab tagastama 3 int-väärtust.

Täielikkuse huvides soovitan mõnda muud meetodit. Oletame, et vajate tõesti 3 väärtust, mitte 300.

  void foo (int & a, int & b, int & c) {a = 19; // need on lihtsalt juhuslikud arvud b = 7; c = 69;} tühine seadistamine () {jada algus (115200); int x, y, z; foo (x, y, z); Serial.println (x); Serial.println (y); Serial.println (z);} void loop () {}  

See võtab arvatavasti vähem mälu, sest kompilaator suudab optimeerida kõiki kolme väärtust registriteks. Tegelikult on see konkreetne näide optimeerinud kogu funktsioonikõne:

  000000be <setup>: public: inline HardwareSerial (volatile uint8_t * ubrrh, volatile uint8_t * ubrrl, lenduv uint8_t * ucsra, lenduv uint8_t * ucsrb, lenduv uint8_t * ucsrc, lenduv uint8_t * udr); void begin (allkirjastamata pikk baud) {begin (baud, SERIAL_8N1); } olema: 26 e0 ldi r18, 0x06; 6 c0: 40 e0 ldi r20, 0x00; 0 c2: 52 ec ldi r21, 0xC2; 194 c4: 61 e0 ldi r22, 0x01; 1 c6: 70 e0 ldi r23, 0x00; 0 c8: 82 e2 ldi r24, 0x22; 34 ca: 91 e0 ldi r25, 0x01; 1 cc: 0e 94 64 01 helista 0x2c8; 0x2c8 <_ZN14HardwareSerial5beginEmh> d0: 4a e0 ldi r20, 0x0A; 10 d2: 50 e0 ldi r21, 0x00; 0 d4: 63 e1 ldi r22, 0x13; 19 < ---------- x d6: 70 e0 ldi r23, 0x00; 0 d8: 82 e2 ldi r24, 0x22; 34 da: 91 e0 ldi r25, 0x01; 1 pp: 0e 94 4d 03 kõne 0x69a; 0x69a <_ZN5Print7printlnEii> e0: 4a e0 ldi r20, 0x0A; 10 e2: 50 e0 ldi r21, 0x00; 0
e4: 67 e0 ldi r22, 0x07; 7 < ---------- y e6: 70 e0 ldi r23, 0x00; 0 e8: 82 e2 ldi r24, 0x22; 34 ea: 91 e0 ldi r25, 0x01; 1 ec: 0e 94 4d 03 kõne 0x69a; 0x69a <_ZN5Print7printlnEii> f0: 4a e0 ldi r20, 0x0A; 10 f2: 50 e0 ldi r21, 0x00; 0 f4: 65 e4 ldi r22, 0x45; 69 < ---------- z f6: 70 e0 ldi r23, 0x00; 0 f8: 82 e2 ldi r24, 0x22; 34 fa: 91 e0 ldi r25, 0x01; 1 fc: 0c 94 4d 03 jmp 0x69a; 0x69a <_ZN5Print7printlnEii>00000100 <loop>: 100: 08 95 ret  
Harper Shelby
2016-10-14 23:53:06 UTC
view on stackexchange narkive permalink

C-s soovitud toiminguteks on kaks võimalust. Üks tugineb funktsiooni helistaja mälu haldamisel, teine ​​mälu haldaval "raamatukogu" koodil. Kui kasutate helistaja hallatavat mälu, aktsepteerib teie funktsioon puhvrit ja täidab selle. "Raamatukogu" hallatava mälu jaoks pakute täiendavaid funktsioone puhvri eraldamiseks ja vabastamiseks, millele helistaja seejärel helistab. ja võimaldab juurdepääsu andmetele.

Kui kavatsete funktsioonis / meetodis mälu eraldada, tehke seda kindlasti * kestvalt * - näiteks virnale pandud miski ei ela enam üle funktsioonikõne tagasitulekut - see võib siiski olla, kuid ainult ebausaldusväärselt . Isiklikult kasutaksin kas staatilist jaotust või helistaja virna, kuna kestev käitamisajaotus toob sisse tõrke režiimid ja eraldamise jälgimiseks läheb vaja umbes sama palju ruumi kui 6 baiti, mida 3 Arduino int tegelikult tarbiks.
Täiesti tõsi - ma ei laskunud üksikasjadesse, vaid osutasin põhistrateegiatele. Arduino keskkonnas ei ole teie mainitud põhjustel tõenäoliselt eraldiste jälgimine (ja enamikul juhtudel ka dünaamiline eraldamine).


See küsimus ja vastus tõlgiti automaatselt inglise keelest.Algne sisu on saadaval stackexchange-is, mida täname cc by-sa 3.0-litsentsi eest, mille all seda levitatakse.
Loading...