{"id":6908,"date":"2011-05-18T12:18:29","date_gmt":"2011-05-18T10:18:29","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=6908"},"modified":"2011-10-05T12:25:48","modified_gmt":"2011-10-05T10:25:48","slug":"14-i-puntatori-la-gestione-dinamica-della-memoria-parte-3","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/14-i-puntatori-la-gestione-dinamica-della-memoria-parte-3\/","title":{"rendered":"14. I Puntatori &#8211; La gestione dinamica della memoria &#8211; parte 3"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/05\/corso-completo-c-i-puntatori-parte-2-gestione-dinamica-della-memoria-00.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/05\/corso-completo-c-i-puntatori-parte-2-gestione-dinamica-della-memoria-00.jpg\" alt=\"corso-completo-c-i-puntatori-parte-2-gestione-dinamica-della-memoria-00\" width=\"200\" height=\"100\" class=\"alignleft size-full wp-image-6931\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/05\/corso-completo-c-i-puntatori-parte-2-gestione-dinamica-della-memoria-00.jpg 200w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/05\/corso-completo-c-i-puntatori-parte-2-gestione-dinamica-della-memoria-00-150x75.jpg 150w\" sizes=\"auto, (max-width: 200px) 100vw, 200px\" \/><\/a> Ciao a tutti, eccoci giunti alla quattordicesima lezione del nostro corso completo di programmazione in C. Anche oggi parleremo dei puntatori e nello specifico approfondiremo alcuni aspetti legati alla gestione dinamica della memoria, prima di partire, per\u00f2, facciamo un p\u00f2 il punto di quello che abbiamo detto e visto fino ad ora sui puntatori:<!--more--><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>Sono un tipo di variabile<\/li>\n<li>Devono essere tipizzati (int, char etc.)<\/li>\n<li>Possono essere usati con l&#8217;operatore di dereferenziazione ( * ) per accedere al contenuto della cella di memoria puntata<\/li>\n<li>L&#8217;operatore di indirizzamento ( &amp; ) restituisce l&#8217;indirizzo al quale una variabile \u00e8 memorizzata, quindi pu\u00f2 essere considerato il duale dell&#8217;operatore &#8221; * &#8220;. (Cosa succede ad esempio scrivento  &#8221; *(&amp;nome_variabile)  &#8221; ??<\/li>\n<li>Possono essere inseriti tra i parametri delle funzioni, riuscendo cos\u00ec a superare il problema del passaggio dati per valore.<\/li>\n<li>Sono alla base della creazione di strutture statiche come array, matrici e matrici multidimensionali.<\/li>\n<li>Con l&#8217;aritmetica dei puntatori possiamo modificare la cella di memoria puntata dal puntatore per muoverci agevolmente su di essa.<\/li>\n<\/ul>\n<p>Ma se dovessi scegliere un solo motivo per il quale sono stati inventati i puntatori, sceglierei proprio quello di cui parleremo in questa lezione: l&#8217;<strong>allocazione dinamica della memoria<\/strong>.<\/p>\n<p>Negli esempi che abbiamo scritto nella precedente lezione, quando abbiamo parlato di strutture dati come array e matrici, abbiamo detto che per dichiarare un array di 10 elementi (indicizzati da 0 a 9) bisogna scrivere:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nint nomeArray[10];\r\n<\/pre>\n<p>in questo modo il compilatore riserver\u00e0 ad ogni esecuzione del nostro programma 10 * (dimensione di un intero) byte in memoria per questa variabile e sar\u00e0 accessibile tramite:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nnomeArray[n]; \/\/n compreso tra 0 e 9\r\n<\/pre>\n<p>Questo approccio ha il difetto di allocare sempre lo spazio per 10 interi in memoria, il che pu\u00f2 andar bene se il valore &#8220;10&#8221; \u00e8 fisso e indipendente dall\u2019esecuzione, ma supponiamo che quel parametro dipenda dalle scelte dell\u2019utente, come potremmo fare?<\/p>\n<p>Supponiamo per esempio di voler realizzare un programma che calcoli alcuni valori statistici su un numero di campioni scelti dall\u2019utente memorizzandoli in un array. (in questo esempio calcolo solo la somma)<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\n#include \r\n\r\nint somma(int *array, int size){\r\n\r\n  int i; \/\/variabile utilizzata per i cicli.\r\n\r\n  int somma = 0;        \/\/variabile per memorizzare la somma.\r\n\r\n  for (i = 0; i &lt; size; i++){\r\n\r\n    somma = somma + array[i]; \/\/aggiungo alla somma parziale il valore dell&#039;array in posizione i\r\n\r\n  }\r\n\r\n  return somma; \/\/restituisco il valore della somma.\r\n\r\n}\r\n\r\nint main (int argc, const char * argv[]) {\r\n\r\n  int qt_numeri;\r\n\r\n  int numero;\r\n\r\n  int i;\r\n\r\n  int arrayDiNumeri[255];  \/\/array dove memorizzare i numeri insiti dall&#039;utente.\r\n\r\n  printf(&quot;Inserisci la quanti\u00e0 di numeri: &quot;);\r\n\r\n  scanf(&quot;%d&quot;,&amp;qt_numeri);\r\n\r\n  printf(&quot;Dovrai inserire %d numeri:&quot;,qt_numeri);\r\n\r\n  for (i = 0 ; i &lt; qt_numeri ; i++ ) {\r\n\r\n    scanf(&quot;%d&quot;,&amp;numero);\r\n\r\n    arrayDiNumeri[i] = numero;\r\n\r\n   }\r\n\r\n  printf(&quot;la somma \u00e8: %d&quot;, somma(arrayDiNumeri, qt_numeri));\r\n\r\n  return 0;\r\n\r\n}\r\n<\/pre>\n<p>A questo punto del corso non dovreste avere grosse difficolt\u00e0 a capire questo codice, ma come potete ben notare c&#8217;\u00e8 un problema enorme: siamo costretti a dichiarare un array di dimensione 255 perch\u00e9 non sappiamo in anticipo quanti numeri l&#8217;utente decider\u00e0 di inserire&#8230; quindi adremo ad occupare 255 * (dimensione di un intero) ciascuna volta che l&#8217;utente eseguir\u00e0 il programma&#8230;certo occupare circa 1000 byte (1 kb) pu\u00f2 non sembrare un grosso spreco, vista la quantit\u00e0 in gigabyte di memoria che hanno a disposizione i nostri computer, ma per realizzare un programma efficiente bisogna essere come accaniti risparmiatori, intenti a rosicchiare byte dove \u00e8 possibile! Ma c&#8217;\u00e8 un errore ancora pi\u00f9 grave, cosa succede se l&#8217;utente decide di inserire 256 numeri? all&#8217;interno del ciclo for tenteremmo di scrivere nell&#8217;allocazione arrayDiNumeri[255] ma l&#8217;ultima allocazione effettivamente utilizzabile \u00e8 arrayDiNumeri[254] come si vede in questa immagine:<\/p>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/05\/corso-completo-c-i-puntatori-parte-2-gestione-dinamica-della-memoria-01.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/05\/corso-completo-c-i-puntatori-parte-2-gestione-dinamica-della-memoria-01.jpg\" alt=\"corso-completo-c-i-puntatori-parte-2-gestione-dinamica-della-memoria-01\" width=\"550\" height=\"507\" class=\"aligncenter size-full wp-image-6930\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/05\/corso-completo-c-i-puntatori-parte-2-gestione-dinamica-della-memoria-01.jpg 550w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/05\/corso-completo-c-i-puntatori-parte-2-gestione-dinamica-della-memoria-01-300x276.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><\/p>\n<p>e questo \u00e8 un errore gravissimo, perch\u00e9 non abbiamo idea di che cosa sia memorizzato in quella allocazione di memoria, magari stiamo sovrascrivendo un dato importante, infatti molto spesso un errore di questo tipo porta al crash dell&#8217;intero programma.<\/p>\n<p>Sottolineo il termine molto spesso e non ho detto sempre! Come abbiamo avuto modo di notare pi\u00f9 volte il linguaggio C suppone che il programmatore  sappia quello che sta facendo, quindi si limita ad &#8220;eseguire gli ordini&#8221; senza fare troppi controlli, e purtroppo l&#8217;errore di scrivere in un&#8217;allocazione di memoria errata pu\u00f2 alcune volte passare inosservata anche agli sguardi molto attenti. Per darvi un&#8217;idea anche una vecchia versione di SSH era afflitta da un errore simile, con le conseguenze del caso.<\/p>\n<p>Torniamo al problema originario, come facciamo ad allocare un&#8217;array di dimensione variabile a seconda delle scelte dell&#8217;utente? In C esiste l&#8217;allocazione dinamica della memoria che permette proprio di fare quanto richiesto.<\/p>\n<p>\u00c8 d&#8217;obbligo fare una digressione su come viene gestita la memoria all&#8217;interno del computer, ma ci accontentiamo di sapere che viene divisa in due parti, lo <strong>stack<\/strong> dove vengono allocate le variabili statiche ovvero tutte quelle dichiarate fino ad adesso e l&#8217;<strong>heap<\/strong> dove vengono allocate le variabili allocate dinamicamente.  La differenza sostanziale \u00e8 che lo stack \u00e8 gestito come una <strong>pila<\/strong>, tutte le variabili vengono messe una sull&#8217;altra, quando una funzione viene invocata nello stack vengono allocate tutte le variabili che appartengono a quella funzione, quando una funzione termina la parte di stack viene svuotata e cos\u00ec viene liberata la memoria. L&#8217;heap invece ha una funzionalit\u00e0 diversa, per ottenere dello spazio nell&#8217;heap bisogna utilizzare delle funzioni particolari (che vedremo tra un attimo) questo spazio, per\u00f2, non viene rilasciato quando la variabile esce dallo scope, dovremmo invece rilasciarla esplicitamente.<\/p>\n<p>La funzione principale da utilizzare per ottenere dello spazio nell&#8217;heap \u00e8 la <strong>malloc<\/strong>, il cui prototipo \u00e8 il seguente:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nvoid *malloc(size_t size);\r\n<\/pre>\n<p>e la pagina di manuale recita:<\/p>\n<blockquote><p>\nThe malloc() function allocates size bytes of memory and returns a pointer to the allocated memory.<\/p><\/blockquote>\n<p>La funzione \u00e8 dichiarata dentro la libreria stdlib.h, quindi ricordiamoci di inserire la direttiva #include  in cima ai nostri programmi se intendiamo utilizzarla.<\/p>\n<p>Ma che tipo di parametro richiede? \u00e8 la prima volta che incontriamo il tipo di dato size_t ma niente paura \u00e8 semplicemente un tipo di dato come un altro e si usa quando ci si riferisce alla dimensione in byte di un oggetto in memoria. Difficilmente per\u00f2 ci troveremo a dichiarare delle variabili di tipo size_t, pi\u00f9 probabilmente utilizzeremo la funzione sizeof() che restituisce proprio la dimensione dell&#8217;argomento espressa in size_t.<\/p>\n<p>Con un esempio tutto risulter\u00e0 pi\u00f9 chiaro: dichiariamo un puntatore e facciamolo puntare ad un&#8217;allocazione di memoria dell&#8217;heap in grado di ospitare 10 interi<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nint *array;\r\n\r\narray = malloc( 10 * sizeof(int) );\r\n<\/pre>\n<p>Dichiariamo un array nell&#8217;heap in grado di contenere 5 caratteri:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar *array;\r\n\r\narray = malloc(5 * sizeof(char));\r\n<\/pre>\n<p>A questo punto le strutture possono essere utilizzare come dei normali array statici, accedento alle singole variabili tramite array[n]<\/p>\n<p>Ci sono due cose da non dimenticare quando si ha a che fare con l&#8217;allocazione dinamica della memoria:<\/p>\n<ol>\n<li>Controllare il valore di ritorno della funzione malloc<\/li>\n<li>Ricordarsi di liberare esplicitamente la memoria allocata quando non pi\u00f9 necesaria.<\/li>\n<\/ol>\n<p>La funzione malloc restituisce NULL se non c&#8217;\u00e8 sufficiente memoria disponibile per essere allocata, questo non succede molto spesso, ma in alcuni casi potrebbe accadere, quindi \u00e8 buona norma assicurarsi sempre che il puntatore restituito dalla malloc sia diverso da NULL.<\/p>\n<p>Per liberare lo spazio allocato tramite la funzione malloc bisogna richiamare la funzione free() passandole come parametro proprio il puntatore restituito dalla malloc. Da notare che per liberare lo spazio abbiamo bisogno del puntatore, quindi lo spazio va liberato mentre si \u00e8 nello scope della variabile, usciti dallo scope si ha quello che si chiama &#8220;memory leak&#8221; (<a href=\"http:\/\/it.wikipedia.org\/wiki\/Memory_leak\" target=\"_blank\">link<\/a>) ovvero della memoria allocata, inutilizzabile e non pi\u00f9 liberabile.<\/p>\n<p>Vediamo quindi il precedente esempio come viene modificato utilizzando la gestione dinamica della memoria:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\n#include \r\n\r\n#include \r\n\r\nint somma(int *array, int size){\r\n\r\n  int i;\r\n\r\n  int somma = 0;\r\n\r\n  for (i = 0; i &lt; size; i++){\r\n\r\n    somma = somma + array[i];\r\n\r\n  }\r\n\r\n  return somma;\r\n\r\n}\r\n\r\nint main (int argc, const char * argv[]) {\r\n\r\n  int qt_numeri;\r\n\r\n  int numero;\r\n\r\n  int i;\r\n\r\n  int *arrayDiNumeri; \/\/dichiariamo come semplice puntatore\r\n\r\n  printf(&quot;Inserisci la quanti\u00e0 di numeri: &quot;);\r\n\r\n  scanf(&quot;%d&quot;,&amp;qt_numeri);\r\n\r\n  printf(&quot;Dovrai inserire %d numeri:&quot;,qt_numeri);\r\n\r\n\/\/alloco dinamicamente la memoria  \r\n\r\narrayDiNumeri = malloc(qt_numeri * sizeof(int));\r\n\r\n\/\/verifico che il puntatore non sia null,\r\n\r\n\/\/ la condizione \u00e8 pi\u00f9 spesso abbreviata in questo modo &quot;if (! arrayDiNumeri)&quot;\r\n\r\nif (arrayDinumeri == NULL) {\r\n\r\n\/\/esco dal programma riportando un errore.\r\n\r\nreturn -1;\r\n\r\n}\r\n\r\n  for (i = 0 ; i &lt; qt_numeri ; i++ ) {\r\n\r\n    scanf(&quot;%d&quot;,&amp;numero);\r\n\r\n    arrayDiNumeri[i] = numero;\r\n\r\n   }\r\n\r\n  printf(&quot;la somma \u00e8: %d&quot;, somma(arrayDiNumeri, qt_numeri));\r\n\r\n\/\/libero la memoria allocata  \r\n\r\nfree(arrayDiNumeri);\r\n\r\n  return 0;\r\n\r\n}\r\n<\/pre>\n<p>Per tutti coloro che hanno gi\u00e0 avuto a che fare con la programmazione in objective-c, vorrei far notare che la dichiarazione di un nuovo oggetto, ad esempio tramite l&#8217;istruzione<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nNSString *myName = [[NSString alloc] init];\r\n<\/pre>\n<p>praticamente \u00e8 la verione &#8220;evoluta&#8221; della malloc che abbiamo appena visto, viene riservato infatti nell&#8217;heap lo spazio sufficiente a memorizzare un oggetto di tipo NSString. Addirittura per conformit\u00e0 con il linguaggio hanno mantenuto il simbolo &#8221; * &#8221; davanti al nome della variabile, proprio ad indicare che si tratta di un puntatore.<\/p>\n<h4>Una variante sul tema<\/h4>\n<p>Vorrei precisare che la funzione malloc non \u00e8 l&#8217;unica in grado di allocare della memoria nell&#8217;heap, una valida alternativa \u00e8 la funzione:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nvoid * calloc(size_t count, size_t size);\r\n<\/pre>\n<p>La sintassi \u00e8 molto simile, ma questa prevede due parametri separati, in pratica per dichiarare un array da 10 interi bisogna scrivere:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nint *array;\r\n\r\narray = calloc(10, sizeof(int));\r\n<\/pre>\n<p>Un&#8217;ulteriore differenza \u00e8 che la calloc restituisce la zona di memoria gi\u00e0 azzerata, mentre la malloc restituisce la memoria cos\u00ec com&#8217;\u00e8.<\/p>\n<p>Esiste poi la funzione realloc() il cui prototipo \u00e8 il seguente:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nvoid *realloc(void *ptr, int dim_totale)\r\n<\/pre>\n<p>Il suo scopo \u00e8 quello di modificare la dimensione di un blocco di memoria puntato da ptr per farlo diventare di  dim_totale bytes.<\/p>\n<p>Se dim_totale \u00e8 0, l\u2019invocazione \u00e8 equivalente ad una free(ptr). Naturalmente il valore di ptr deve provenire da una precedente invocazione di malloc() o calloc() o realloc()<\/p>\n<p>Come ormai consueto vi lascio con qualche esercizio, alla prossima!!<\/p>\n<h4>Esercizi<\/h4>\n<ol>\n<li>Scrivere una funzione che scambi il valore di due variabili, passate come parametro. (hint: utlizzare i puntatori come parametro non servono array)<\/li>\n<li>Scrivere una funzione che chieda all&#8217;utente quanti numeri inserire, quindi allochi dinamicamente un&#8217;array della dimensione corretta e prenda in input tutti i valori, al termine dell&#8217;inserimento calcoli la media dei valori inseriti.<\/li>\n<li>Scrivere una funzione che presi in input due valori ne restituisca un terzo lungo il doppio ottenuto dalla concatenazione dei due array in input.<\/li>\n<li>Scrivere una funzione che preso in inut un array lo restituisca in ordine inverso.<\/li>\n<li>Scrivere un programma che allochi dinamicamente lo spazio per una matrice 10&#215;10.<\/li>\n<\/ol>\n<h4>Letture consigliate:<\/h4>\n<p><a href=\"http:\/\/www.amazon.it\/gp\/search\/ref=as_li_qf_sp_sr_il_tl?ie=UTF8&#038;keywords=887192200X&#038;tag=de0d-21&#038;index=aps&#038;linkCode=as2&#038;camp=3370&#038;creative=23322\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/03\/C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP.jpg\" alt=\"C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP\" title=\"C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP\" width=\"54\" height=\"75\" class=\"alignleft size-full wp-image-7803\" \/><\/a> <a href=\"http:\/\/www.amazon.it\/gp\/search\/ref=as_li_qf_sp_sr_il_tl?ie=UTF8&#038;keywords=887192200X&#038;tag=de0d-21&#038;index=aps&#038;linkCode=as2&#038;camp=3370&#038;creative=23322\" target=\"_blank\"><strong>Il linguaggio C. Principi di programmazione e manuale di riferimento (Accademica) <\/strong><\/a><br \/>\n<em>Brian W. Kernighan &#8211; Dennis M. Ritchie<\/em><br \/>\n<strong>Editore:<\/strong> Pearson | <strong>Lingua:<\/strong> Italiano | <strong>Brossura:<\/strong> 313 pagine<br \/>\n<strong>Prezzo Listino:<\/strong> <del datetime=\"2011-09-03T10:00:08+00:00\">EUR 27,00<\/del><br \/>\n<strong>Prezzo Promozione:<\/strong> EUR 22,95 con Spedizione gratuita<\/p>\n<p><a href=\"http:\/\/www.amazon.it\/gp\/product\/8850329547\/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&#038;tag=de0d-21&#038;linkCode=as2&#038;camp=3370&#038;creative=23322&#038;creativeASIN=8850329547\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/09\/C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP.jpg\" alt=\"C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP\" title=\"C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP\" width=\"54\" height=\"75\" class=\"alignleft size-full wp-image-7550\" \/><\/a> <a href=\"http:\/\/www.amazon.it\/gp\/product\/8850329547\/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&#038;tag=de0d-21&#038;linkCode=as2&#038;camp=3370&#038;creative=23322&#038;creativeASIN=8850329547\" target=\"_blank\"><strong>C. Corso completo di programmazione<\/strong><\/a><br \/>\n<em>Paul J. Deitel &#8211; Harvey M. Deitel<\/em><br \/>\n<strong>Editore:<\/strong> Apogeo | <strong>Lingua:<\/strong> Italiano | <strong>Brossura:<\/strong> 640 pagine<br \/>\n<strong>Prezzo Listino:<\/strong> <del datetime=\"2011-09-03T10:00:08+00:00\">EUR 39,00<\/del><br \/>\n<strong>Prezzo Promozione:<\/strong> EUR 33,15 con Spedizione gratuita<\/p>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/supporto-applicazioni\/le-applicazioni-dei-nostri-autori\/parole-vietate-di-ignazio-calo\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/02\/bannerIgnazioc.png\" alt=\"\" width=\"480\" height=\"100\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ciao a tutti, eccoci giunti alla quattordicesima lezione del nostro corso completo di programmazione in C. Anche&#8230;<\/p>\n","protected":false},"author":53,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[569],"tags":[593,588,724,723,743,737,241],"class_list":["post-6908","post","type-post","status-publish","format-standard","hentry","category-corso-completo-di-c","tag-corso-completo-di-c-2","tag-corso-di-c","tag-esempi-codice-programmazione-c","tag-esercizi-programmazione-c","tag-gestione-dinamica-della-memoria-in-c","tag-i-puntatori-in-c","tag-ignazio-calo"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/6908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=6908"}],"version-history":[{"count":14,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/6908\/revisions"}],"predecessor-version":[{"id":7818,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/6908\/revisions\/7818"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=6908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=6908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=6908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}