{"id":363,"date":"2012-05-29T22:07:38","date_gmt":"2012-05-29T21:07:38","guid":{"rendered":"http:\/\/www.jbahillo.com\/?p=363"},"modified":"2012-06-11T09:34:51","modified_gmt":"2012-06-11T08:34:51","slug":"punteros-consejos-y-errores-comunes","status":"publish","type":"post","link":"https:\/\/www.jbahillo.com\/?p=363","title":{"rendered":"Punteros: Consejos y errores comunes"},"content":{"rendered":"<p>Este texto no es m\u00edo, lo he encontrado buscando una informaci\u00f3n y me ha parecido muy interesante compartirlo. La fuente original es <a href=\"http:\/\/www.chuidiang.com\/clinux\/funciones\/punteros.php\" title=\"Conceptos y Consejos pr\u00e1cticos para el uso correcto de punteros\">http:\/\/www.chuidiang.com\/clinux\/funciones\/punteros.php<\/a>, y si bien est\u00e1 pensado para C es perfecta y f\u00e1cilmente extrapolable a cualquier otro lenguaje.<\/p>\n<p>Una cosa es lo que nos cuentan los libros de C sobre punteros y otra los problemas pr\u00e1cticos que se nos plantean cuando nos ponemos a programarlos. Los punteros son adem\u00e1s una cosa muy delicada, cualquier peque\u00f1o despiste con ellos puede hacer que nuestro programa se \u00abcaiga\u00bb inesperadamente o de resultados muy extra\u00f1os.<\/p>\n<p>Aunque en los ejemplos de c\u00f3digo que pongo a continuaci\u00f3n, al ir las l\u00edneas seguidas, se ve claramente el error (al menos, esa es la intenci\u00f3n), lo habitual es que estas l\u00edneas erroneas est\u00e9n separadas en el c\u00f3digo, incluso en funciones distintas, con lo que no es tan evidente el verlas.<\/p>\n<p>Todo lo que se dice aqu\u00ed, aunque est\u00e9 explicado para C con las funciones malloc() y free(), se puede aplicar a C++, usando new y delete. Donde hablamos de estructuras, podemos hablar de clases.<\/p>\n<p><strong>Concepto de puntero y primeros errores<br \/>\n<\/strong><br \/>\nPodemos imaginar un puntero como una flecha. Esa flecha apunta a una direcci\u00f3n de memoria. Por ejemplo, si declaramos en C el puntero<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">char *puntero;\n<\/pre>\n<p>tenemos declarada una \u00abflecha\u00bb que apunta a una direcci\u00f3n de memoria. \u00bfA cual?. Aqu\u00ed se nos presenta el primer problema pr\u00e1ctico con los punteros. Tal cual est\u00e1 declarado, esa flecha apunta a cualquier direcci\u00f3n de memoria, al azar. Lo habitual es que sea la direcci\u00f3n de memoria 0 (cero), pero puede ser cualquiera.<\/p>\n<p>Si inmediatamente despu\u00e9s de declararlo intentamos guardar algo en la direcci\u00f3n de memoria a la que apunta, como por ejemplo<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">*puntero = &#039;A&#039;;\n<\/pre>\n<p>pueden pasarnos dos cosas:<\/p>\n<p>Que la direcci\u00f3n aleatoria a la que apunta puntero pertenezca a nuestro programa. En ese caso se meter\u00e1 la &#8216;A&#8217; en la direcci\u00f3n y aparentemente no ha pasado nada. Lo que realmente pasa es que estamos metiendo un byte 65 (c\u00f3digo ascii de la &#8216;A&#8217;) en alg\u00fan sitio de nuestro programa (c\u00f3digo, zona de variables, etc). El error puede presentarse en cualquier otro lada de nuestro programa, en un sitio aparentemente correcto.<br \/>\nQue la direcci\u00f3n aleatoria a la que apunta puntero no pertenezca a nuestro programa. Esto es lo mejor que nos puede pasar. En el momento de la asignaci\u00f3n nuestro programa se \u00abcaer\u00e1\u00bb y dar\u00e1 un error de violaci\u00f3n de memoria o similar. Al ser en el momento de la asignaci\u00f3n, podremos corregirlo m\u00e1s f\u00e1cilmente, ya que sabemos en qu\u00e9 l\u00ednea se ha producdo el fallo.<br \/>\n Por ello, como primer consejo pr\u00e1ctico:<br \/>\nInicializar todos los punteros al declararlos, por ejemplo, a NULL <\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">char *puntero = NULL;\n<\/pre>\n<p>Si nos olvidamos de hacerle apuntar a una direcci\u00f3n de memoria adecuada, nos dar\u00e1 error en el momento de utilizarlo, y  no despu\u00e9s, en otro lado del programa. En general, casi todos los consejos que doy van orientados a poder depurar el programa con m\u00e1s facilidad. Se trata de conseguir que el programa se \u00abcaiga\u00bb en la instrucci\u00f3n incorrecta y no que d\u00e9 resultados erroneos o se \u00abcaiga\u00bb en otro sitio que no tiene nada que ver.<\/p>\n<p><strong>Apuntar un puntero a una direcci\u00f3n de memoria<br \/>\n<\/strong><br \/>\nDe lo comentado anteriormente, vemos que siempre debemos hacer que un puntero apunte a una direcci\u00f3n de memoria v\u00e1lida antes de utilizarlo. Para ello tenemos dos posibilidades:<\/p>\n<p>Apuntarlo a una direcci\u00f3n de memoria ya reservada para nuestro programa. Para ello basta asignarlo a la direcci\u00f3n de cualquier variable que tengamos declarada o igualarlo a otro puntero que ya est\u00e9 apuntando a una direcci\u00f3n adecuada. Por ejemplo<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">char unCaracter; \nchar *puntero = NULL; \n... \npuntero = &amp;unCaracter;<\/pre>\n<p>Ahora puntero apunta a la direcci\u00f3n de memoria en la que est\u00e1 unCaracter. Podemos utilizar con seguridad la memoria a la que apunta puntero, sabiendo que lo que pongamos ah\u00ed tambi\u00e9n se est\u00e1 poniendo en unCaracter.<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">*puntero = &#039;A&#039;;  \/* Ahora unCaracter tambi\u00e9n tiene una &#039;A&#039; *\/\n<\/pre>\n<p>Reservar una zona de memoria espec\u00edfica para nuestro puntero y hacer que apunte a ella. Para ello tenemos la funci\u00f3n malloc(). La funci\u00f3n malloc() nos reserva una zona de memoria del tama\u00f1o que le indiquemos y nos devuelve su direcci\u00f3n. Podemos hacer que nuestro puntero apunte a esa direcci\u00f3n<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">puntero = malloc(...);  \/* No pongo los par\u00e1metros ... *\/ \n... \n*puntero = &#039;A&#039;;\n<\/pre>\n<p>Una vez reservada la zona de memoria, podemos utilizarla con seguridad. Si no queremos que nuestro programa consuma m\u00e1s memoria de la cuenta, debemos acordarnos de liberarla cuando no la necesitemos m\u00e1s. Para ello est\u00e1 la funci\u00f3n free() a la que se le pasa la direcci\u00f3n de memoria que queremos liberar.<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">free (puntero);\n<\/pre>\n<p>Todo esto es muy bonito y es b\u00e1sicamente lo que nos puede contar cualquier libro de C. Sin embargo, hay varios \u00abproblemas\u00bb que se nos pueden presentar.<\/p>\n<p>Si hacemos que nuestro puntero apunte a una variable local, cuando la variable desaparezca, nuestro puntero queda apuntando a una direcci\u00f3n de memoria que ya no es v\u00e1lida. Por ejemplo<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">char * funcion () \n{ \n    char resultado; \n    char *puntero; \n  \n  \n    resultado = algun_valor;\n\n    puntero = &amp;resultado;\n    return puntero; \n}<\/pre>\n<p>Esto es una fuente segura de problemas. La variable resultado tiene sentido dentro de la funci\u00f3n, pero al terminar la funci\u00f3n, desaparece la variable, puntero apunta a la direcci\u00f3n de memoria que ocupaba esa variable. Cuando intentemos usar el puntero devuelto por la funci\u00f3n, esa memoria ya est\u00e1 libre y es posible que alguien la sobre-escriba, haciendo que su valor sea aleatorio.<\/p>\n<p>Cualquier variante de esa funci\u00f3n tambi\u00e9n da problemas. Por ejemplo, es igual de incorrecto este c\u00f3digo<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">char * funcion () \n{ \n    char resultado; \n    \/* Aqui rellenamos resultado con el valor deseado *\/ \n    return &amp;resultado; \n}<\/pre>\n<p>Al salir de la funci\u00f3n, la direcci\u00f3n que estamos devolviendo ya no tiene sentido.<br \/>\nAdem\u00e1s, esto nunca nos dar\u00e1 un error de violaci\u00f3n de memoria, ya que esa zona de memoria pertenec\u00eda a nuestro programa. Nuestro programa no se \u00abcaer\u00e1\u00bb, simplemente dar\u00e1 resultados incorrectos.<\/p>\n<p>No devolver nunca punteros a variables locales a una funci\u00f3n.<\/p>\n<p>Al liberar una zona de memoria con free() nuestro puntero queda apuntando a una direcci\u00f3n que ya no es correcta, free() no lo hace apuntar a NULL autom\u00e1ticamente. Utilizarla posteriormente dar\u00e1 problemas. Por ejemplo:<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">char *puntero = NULL; \npuntero = malloc(); \nfree (puntero); \n*puntero = &#039;A&#039;;<\/pre>\n<p>Esto no dar\u00e1 ning\u00fan problema de violaci\u00f3n de memoria, puesto que la memoria a la que apunta puntero era nuestra. Sin embargo, alguien puede posteriormente sobre-escribir en esa direcci\u00f3n de memoria. Este problema se agrava si no lo hacemos todos seguido. Imaginemos que hemos liberado puntero y que en otra funci\u00f3n o m\u00e1s adelante en el c\u00f3digo intentamos usarlo.<br \/>\nApuntar a NULL los punteros despu\u00e9s de liberarlos <\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">free (puntero); \npuntero = NULL;<\/pre>\n<p>Si lo apuntamos a NULL despu\u00e9s de hacer el free(), cuando lo intentemos utilizar de forma incorrecta, el programa se caer\u00e1 inmediatamente, con lo que ser\u00e1 m\u00e1s sencillo de depurar.<\/p>\n<p>Liberar dos veces la misma zona de memoria puede dar montones de problemas. Cuando liberamos por segunda vez, el programa no da ning\u00fan error, pero deja \u00abcorrupto\u00bb al gestor de memoria. Lo m\u00e1s probable, al menos en solaris (unix de sun), es que posteriormente el programa nos d\u00e9 fallo en otro malloc(). Por ejemplo:<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">char *puntero1 = NULL; \nchar *puntero2 = NULL;\n\npuntero1 = malloc(); \npuntero2 = puntero1;\n\nfree (puntero1); \npuntero1 = NULL;\n\nfree (puntero2); \npuntero2 = NULL;<\/pre>\n<p>Al liberar puntero1,  liberamos nuestro espacio de memoria. Sobra la liberaci\u00f3n de puntero2, ya que el espacio de memoria al que apunta ya est\u00e1 liberado. Esto no dar\u00e1 ning\u00fan error en la ejecuci\u00f3n del programa, pero m\u00e1s adelante tendremos problemas en alg\u00fan malloc() o free().<\/p>\n<p>Es bastante habitual hacer que una funci\u00f3n reserve un espacio de memoria y lo devuelva. Luego nuestro c\u00f3digo usar\u00e1 ese resultado en varios sitios e, inadvertidamente, podemos liberarlo en dos sitios distintos o dejarlo sin liberar. Es necesario, cuando hacemos un malloc(), tener claro qui\u00e9n va a liberar esa memoria y d\u00f3nde, para evitar este tipo de problemas.<\/p>\n<p>Por cada malloc(), hacer un \u00fanico free().<br \/>\nCuando reservemos memoria con malloc(), decidir claramente qui\u00e9n la va a liberar y cu\u00e1ndo.<\/p>\n<p><strong>Punteros dentro de estructuras<br \/>\n<\/strong><br \/>\nLos punteros dentro de estructuras, si se utilizan descuidadamente, son fuente de problemas. Pongamos por ejemplo una estructura como la siguiente<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">struct Datos \n{ \n    char *nombre; \n    int otroCampo; \n}<\/pre>\n<p>Todo lo dicho hasta ahora para punteros, vale para el que est\u00e1 dentro de la estructura. Si declaramos una variable de tipo Datos, el puntero nombre est\u00e1 sin inicializar.<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">struct Datos unNombre; \nunNombre.nombre = NULL;<\/pre>\n<p>y antes de usarlo reservar espacio para \u00e9l<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">unNombre.nombre = malloc();\n<\/pre>\n<p>o bien asignarlo a alguna variable adecuada.<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">unNombre.nombre = &amp;algunaVariableAdecuada;\n<\/pre>\n<p>El problema principal con las estructuras surge cuando las copiamos o asignamos. Supongamos el siguiente c\u00f3digo<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">struct Datos unNombre; \nunNombre.nombre = NULL; \nstruct Datos otroNombre; \notroNombre.nombre = NULL; \n... \nunNombre.nombre = malloc(); \n... \notroNombre = unNombre;<\/pre>\n<p>La \u00faltima asignaci\u00f3n copia todos los campos de la estructura unNombre en otroNombre, incluido el puntero interno. Ambos punteros van a apuntar a la misma direcci\u00f3n de memoria. Cambiar el contenido de uno de ellos implica cambiar el contenido del otro. El problema se presenta si liberamos uno de ellos<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">free (unNombre.nombre); \nunNombre.nombre = NULL;\n<\/pre>\n<p>Con esta acci\u00f3n tambi\u00e9n hemos liberado la memoria a la que apunta otroNombre.nombre, por lo que su contenido puede no ser v\u00e1lido. Utilizar o liberar  posteriormente otroNombre.nombre nos dar\u00e1 los problemas que ya hemos mencionado.<\/p>\n<p>En C++, si utilizamos clases con alg\u00fan atributo puntero, tenemos algunos trucos que podemos utilizar. Uno de ellos consiste en definir el operator = () y constructores copia para que hagan una copia de los datos a los que apunta el puntero, y  no s\u00f3lo del puntero. Por ejemplo<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">class Datos \n{ \n    protected: \n        char *nombre; \n};<\/pre>\n<p>funciona exactamente igual que una estructura, con los mismos problemas al hacer asignaciones. Sin embargo<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">class Datos \n{ \n    public: \n        \/* Constructor defecto *\/ \n        Datos() \n        { \n            nombre = NULL; \n        }\n\n        \/* Constructor copia *\/ \n        Datos (Datos &amp;original) \n        { \n            *this = original;  \/\/ Llama al operador de asignaci\u00f3n, m\u00e1s abajo. \n        }\n\n        \/* Destructor, Libera nombre si no es NULL *\/ \n        ~Datos() \n        { \n            if (nombre != NULL) \n            { \n                delete [ ] nombre; \n                nombre = NULL; \n            } \n        }\n\n        \/* Asignaci\u00f3n entre instancias de la clase *\/ \n        Datos &amp;operator = (Datos &amp;original) \n        { \n            \/* Se deber\u00eda verificar si original.nombre tiene o no contenido antes de hacer la copia. \n            por simplicidad no no hago *\/ \n            nombre = new char[strlen (original.nombre)+1]; \n            strcpy (nombre, original.nombre); \n            return *this; \n        }\n\n    protected: \n        char *nombre; \n};<\/pre>\n<p>Esto as\u00ed es mucho m\u00e1s seguro. Cada instancia de la clase hace su propio new[] y delete[] y tiene su propia zona de memoria reservada, con lo que es m\u00e1s dif\u00edcil \u00abequivocarse\u00bb. La pega de esto es la \u00abineficiencia\u00bb. El mismo dato estar\u00e1 repetido en varias clases, con el consiguiente consumo de memoria. De todas formas, salvo para datos excesivamente grandes o aplicaciones muy cr\u00edticas en memoria, es mejor evitarse problemas definiendo constructores copia y operator = ()<\/p>\n<p>En C no tenemos esta facilidad, pero podemos hacer funciones del tipo copiaEstructura (estructuraOrigen, estructuraDestino) o liberaEstructura (estructura) que se encargen de hacer estas copias de los punteros y de liberarlos correctamente. La otra opci\u00f3n es ser muy cuidadosos al programar.<\/p>\n<p>Para punteros dentro de estructuras o clases, hacer funciones o m\u00e9todos<br \/>\nadecuados para su tratamiento.<\/p>\n<p><strong>Paso de punteros par\u00e1metro<br \/>\n<\/strong><br \/>\nEn C, aunque no lo parezca, todos los par\u00e1metros se pasan siempre por copia. Para hacer que tanto fuera de una funci\u00f3n como dentro se pueda acceder a la misma variable, hay que pasar un puntero a esa variable. Sin embargo, el puntero en s\u00ed mismo se est\u00e1 pasando por copia. Veamos esto en un ejemplo:<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">void funcion1 (char *p1) \n{ \n    *p1 = &#039;B&#039;; \n}\n\nvoid funcion2 () \n{ \n    char *p2 = NULL; \n    char unaVariable = &#039;A&#039;; \n    p2 = &amp;unaVariable; \n    ... \n    funcion1 (p2); \n}<\/pre>\n<p>En este ejemplo p2 apunta a la variable unaVariable. Llamamos a funcion1() pas\u00e1ndole el puntero p2 y dentro actuamos sobre su contenido. Tanto p1 como p2 apuntan a la misma direcci\u00f3n de memoria (unaVariable), por lo que *p1=&#8217;B&#8217; afecta a unaVariable y *p2. por<\/p>\n<p>Sin embargo, p1 y p2 son punteros distintos. Si dentro de funcion1() hacemos que p1 apunte a otro sitio, por ejemplo, con  cualquiera de las siguientes cosas:<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">p1 = NULL; \np1 = malloc(); \np1 = &amp;otraVariable;<\/pre>\n<p>s\u00f3lo estamos tocando p1. El puntero p2 permanece inalterado, sigue apuntando a unaVariable.<\/p>\n<p>Esto tan simple suele dar lugar a errores. Es habitual tratar de devolver alg\u00fan puntero pas\u00e1ndolo como par\u00e1metro. Por ejemplo, se podr\u00eda pretender que funcion1() creara la memoria con malloc() y luego intentar usarla con p2<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">void funcion1 (char *p1) \n{ \n    p1 = malloc(...); \n    strcpy (p1, &quot;Hola mundo\\n&quot;); \n} \n\nvoid funcion2 () \n{ \n    char *p2 = NULL; \n    funcion1 (p2); \n    printf (&quot;%s&quot;, p2); \n}<\/pre>\n<p>Cuando salimos de funcion1(), p2 sigue apuntando al mismo sitio, a NULL. El programa fallar\u00e1 en el printf().<\/p>\n<p>Si queremos pasar por par\u00e1metro un puntero y que la funci\u00f3n nos lo altere (el puntero, no su contenido), debemos pasar un puntero al puntero. La sintaxis es un poco m\u00e1s liada, pero ser\u00eda algo as\u00ed como esto:<\/p>\n<pre class=\"brush: c; gutter: true; first-line: 1; highlight: []; html-script: false\">void funcion1 (char **p1) \n{ \n    *p1 = malloc( ...); \n    strcpy (*p1, &quot;Hola mundo\\n&quot;); \n}\n\nvoid funcion2 () \n{ \n    char *p2 = NULL; \n    funcion1 (&amp;p2);        \/* Advertir el &amp; delante de p2 *\/ \n    printf (&quot;%s&quot;, p2); \n}<\/pre>\n<p>Esto s\u00ed funciona correctamente.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Este texto no es m\u00edo, lo he encontrado buscando una informaci\u00f3n y me ha parecido muy interesante compartirlo. La fuente original es http:\/\/www.chuidiang.com\/clinux\/funciones\/punteros.php, y si bien est\u00e1 pensado para C es perfecta y f\u00e1cilmente extrapolable a cualquier otro lenguaje. Una&hellip;<\/p>\n<p class=\"more-link-p\"><a class=\"more-link\" href=\"https:\/\/www.jbahillo.com\/?p=363\">Read more &rarr;<\/a><\/p>\n","protected":false},"author":21,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ep_exclude_from_search":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[33,10],"tags":[76,79,78,75,77],"class_list":["post-363","post","type-post","status-publish","format-standard","hentry","category-android","category-gnulinux","tag-c","tag-consejos","tag-errores","tag-programacion","tag-punteros"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p74T96-5R","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.jbahillo.com\/index.php?rest_route=\/wp\/v2\/posts\/363","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jbahillo.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jbahillo.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jbahillo.com\/index.php?rest_route=\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jbahillo.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=363"}],"version-history":[{"count":4,"href":"https:\/\/www.jbahillo.com\/index.php?rest_route=\/wp\/v2\/posts\/363\/revisions"}],"predecessor-version":[{"id":431,"href":"https:\/\/www.jbahillo.com\/index.php?rest_route=\/wp\/v2\/posts\/363\/revisions\/431"}],"wp:attachment":[{"href":"https:\/\/www.jbahillo.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=363"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jbahillo.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=363"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jbahillo.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=363"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}