Hola y bienvenido de nuevo.
En esta conferencia, quiero hablar sobre el uso de punteros y
estructuras, cómo se relacionan.
Podemos hacer que los elementos dentro de una
estructura sean un puntero, y luego también podemos hacer que nuestras propias estructuras sean punteros.
Dos conceptos muy útiles.
Entonces la estructura es importante aquí c permite punteros dos estructuras.
Entonces, cuando creamos una variable de estructura de tipo, podemos
crearla como un puntero.
Los indicadores de estructuras son más fáciles de manipular que las estructuras mismas.
Así que, de nuevo, es una especie de notación,
hace las cosas mucho más fáciles y también es más eficiente.
En algunas implementaciones más antiguas del lenguaje
c, una estructura
no se puede pasar como argumento a una función,
pero sabemos que un puntero sí. Entonces, esta es otra razón
por la que desea que una estructura sea un puntero
cuando la declare, porque luego puede pasarla en versiones anteriores de
c, puede pasarla como un argumento a una función.
Incluso si puede pasar una estructura como argumento, pasar
un puntero es más eficiente.
Sabemos que eso es más eficiente. Hemos hablado de esto en el pasado
sobre cómo pasar lo importante puede ser más eficiente.
En este caso, es incluso más
eficiente porque si está pasando una estructura completa, si la estructura
es grande y contiene muchos elementos, está copiando
todos los elementos de la estructura a ese parámetro.
Si está pasando un puntero simplemente copiando la dirección.
Así que es aún más importante
con punteros como argumentos estructurados porque las estructuras pueden ser grandes.
Muchas representaciones de datos utilizan estructuras que contienen punteros
a otras estructuras.
Verá esto mucho en todas las estructuras
de sus programas c que son punteros y por las razones que mencionamos.
El hecho de que puede pasarlos como parámetros en versiones anteriores para
ver y también es más eficiente porque hacemos todo
pasando por valor, lo que es mucho más
eficiente para copiar una dirección que
copiar todos los elementos de esta gran estructura.
Por lo tanto, declarar una estructura como puntero es bastante sencillo.
Cuando define una variable para que sea un puntero para tachar, simplemente use ese asterisco
después del tipo de datos.
Y dijimos que las estructuras son realmente un tipo nuevo.
En este caso, nuestra siempre importante estructura de fechas.
Simplemente decimos struct date y luego usamos el puntero de fecha
de asterisco, y probablemente querrá inicializarlo en nulo.
Porque recuerde, cuando dice estructura fecha puntero fecha estructura
fecha fecha puntero, que no asigna memoria,
crea memoria para almacenar el puntero real.
No crea memoria para los datos que contiene.
Por lo tanto,
podría asignar a este punto de fecha o la dirección de
otra fecha de estructura o podría asignar una memoria para él
en otro lugar o también podría inicializarlo
con algunos datos de esa manera.
Entonces, el puntero de fecha variable se puede asignar al igual que otros punteros,
puede configurarlo para que apunte a la fecha de hoy con
la declaración de asignación, por lo que si ya teníamos una declaración de la fecha de hoy.
Solo usaríamos el ampersand para obtener la dirección.
Entonces creamos una estructura de fecha normal y es la fecha de hoy.
Entonces eso crearía memoria para los tres elementos.
Y luego creamos nuestro puntero y simplemente le asignamos
la dirección de la otra fecha.
Muy claro. Lo hemos hecho con tipos de datos
regulares, no es diferente cuando lo haces con estructuras.
A continuación, puede acceder indirectamente a cualquiera de los miembros de la estructura de datos señalados por el puntero de fecha.
Entonces tendríamos que hacer algo como esto.
Si quisiera acceder al elemento de la
estructura del puntero del día, primero tendría que eliminar la referencia.
Y probablemente sería útil ponerlo entre paréntesis para que sea muy sencillo.
Debe quitar la referencia al puntero de fecha para obtener el valor
de lo que apunta la fecha
de hoy, el valor de la dirección de la fecha de
hoy a la que apunta para establecer valores particulares.
Por lo tanto, lo eliminaría de la
referencia y luego el día del punto es igual a 21 y eso asignaría 21 a
su puntero de día.
Ahora lo anterior solo dice a lo que apunta la fecha de hoy,
queremos acceder a ese valor y establecer el día en 21.
En este caso, los paréntesis son obligatorios porque el
punto tiene mayor precedencia que el asterisco.
Si no colocó los paréntesis allí, se estropea porque intentaría hacer el punto primero
antes de que realmente llevara el puntero al puntero, para
apuntar a los datos.
Por lo tanto, intentaría acceder a los datos con un puntero nulo esencialmente.
Y así, al eliminar las referencias, obtienes el valor.
Ahora, cuando usamos estructuras a punteros.
Si quisiéramos probar el valor de los meses almacenados en la estructura de fecha señalada por el puntero de
fecha, podríamos hacer algo como esto.
Eliminamos la referencia al puntero, lo ponemos entre paréntesis, por lo que tiene prioridad sobre el punto y luego decimos
que el mes del punto es igual a 12.
Es una sintaxis perfectamente válida.
Pero es un poco engorroso.
Entonces, c tiene su propia sintaxis, por lo que no es necesario quitar la
referencia a todo y ponerlo entre paréntesis para las estructuras.
Cuando desee acceder a lo que apunta la estructura, no tiene que
quitar la referencia de esta manera.
Hay un operador especial que existe en c para estructuras de punteros, y
es el guión mayor que.
Es un guión seguido del signo mayor que.
Y esto le permite no tener que quitar la referencia al puntero.
Entonces, en lugar de hacer una estrella x entre paréntesis y luego un
punto y, puede decir x un guión mayor que y.
Debido a que x es un puntero, no tiene que hacer referencia a él y desea
acceder al elemento dentro de esa estructura, sea lo que sea que esté apuntando.
Entonces verás esta sintaxis por todas partes. No verá los
paréntesis y la referencia d. Es perfectamente válido, pero estás escribiendo más caracteres.
Es mucho más eficiente decir simplemente x raya mayor que y.
Entonces, la declaración if anterior aquí en lugar de eliminar la referencia entre paréntesis, todo lo que tiene que
hacer es decir si el puntero de fecha es mayor que el mes.
Y es algo intuitivo porque el guión más grande que dice que está apuntando a algo.
Y así, la fecha es mayor que el mes.
Entonces, el puntero de fecha es un puntero y es por eso que usa el guión mayor que.
Ahora, si esa fuera una estructura anidada, haría
el guión más grande que la estructura y luego tendría que hacer un
punto después de eso para acceder a los elementos de la estructura anidada.
Pero debido a que el puntero de día es un puntero, debe usar el guión igual o
el guión mayor que.
Así que aquí hay un ejemplo, estamos creando nuestra fecha de estructura,
tenemos tres elementos, luego estamos creando nuestro puntero de fecha de puntero y estamos creando solo
una variable regular hoy. Asignamos a nuestro
puntero la dirección de hoy y luego asignamos elementos reales
de la estructura, solo usamos ese guión mayor que y luego podemos imprimirlo.
Así que veamos esto en bloques de código para ver cómo funciona.
Así que voy a poner este ejemplo aquí.
Y, por lo general, cuando define estructuras,
las define fuera de una función porque luego puede usarlas en cualquier función.
Es una especie de global. Pero recuerde que
cuando define la estructura, en realidad no está creando ningún recuerdo.
De modo que aún crea las variables como variables locales o punteros, pero
la definición real está fuera de la función.
Entonces, si quieres usarlo, puedes usarlo en cualquier función.
Así que aquí en la parte superior, hemos creado una nueva estructura de tipo
fecha o nombre hasta la fecha y contiene tres enteros, la terminamos con un punto y coma.
Luego creamos un par de variables dentro de main.
Uno que es solo una fecha de estructura variable normal hoy
y luego uno que es un puntero. Sabemos que es un puntero porque tiene un asterisco antes.
Sabemos que un puntero cuando crea un puntero que solo crea asigna memoria para
almacenar esa dirección para ese valor de ese puntero.
Así que tendríamos que asignarle una dirección, lo que hacemos con ampersand hoy porque
eso en realidad crea un informe de memoria.
Así que ahora el puntero de fecha apuntará a lo que
sea hoy con la dirección de hoy.
Entonces podemos comenzar a asignarle datos usando este guión más que muy útil y simplemente
asignar un dato como cualquier otra persona, simplemente use el operador de asignación.
Y luego, cuando lo imprimimos,
notará que no tenemos que quitar la referencia para imprimirlo.
Para imprimirlo,
podemos simplemente decir los tipos de datos para los especificadores de formato aquí porcentaje mayor
d igual para enteros y luego solo usamos el gradador de guiones porque eso
en realidad está haciendo el recuerdo de desreferencia.
Ahora podríamos cambiar esto y esto sería válido.
Tenemos que poner entre paréntesis y luego tenemos que decir el mes del punto.
De cualquier manera está bien, pero acostúmbrese al guión que más grande porque tiene una mejor sintaxis.
Y ahora, cuando creamos esto,
verá que imprime los valores de los punteros de
fecha y todos están configurados en 9 25 y 2015.
Entonces dice que la fecha de hoy es 9 25 15. Fue formateado para imprimir de esa manera.
Cosas bastante sencillas.
Solo recuerde ese guión mayor que, esa es una
nueva sintaxis para punteros a estructuras.
Pero todo lo demás aquí es normal.
Sabemos que los punteros deben tener direcciones de tienda, por lo
que sabemos que tenemos que asignar memoria dinámica o tenemos que asignarle una estructura existente.
Regresemos y hablemos más sobre estructuras y punteros.
Ahora hablemos de estructuras que contienen punteros.
Sabemos cómo crear un puntero para una estructura.
Podríamos asignar memoria para ese puntero si no quisiéramos asignar
una dirección existente de un puntero existente.
Pero también puede tener elementos dentro de una estructura
que sea un puntero en sí. Por tanto, un puntero también podría ser miembro de una estructura.
No tenemos que usar esa matriz de caracteres.
Entonces podríamos decir estructura,
podríamos nombrarla en punteros y luego podríamos usar aquí en este ejemplo tenemos dos
enteros, dos punteros enteros p1 y p2, sintaxis perfectamente válida para hacer eso.
Entonces, una estructura llamada punteros se define para contener dos punteros enteros.
El primero se llama p1 y el segundo se llama p2.
Puede definir una variable de tipo struct en punteros como
normal, struct, int punteros, punteros.
Los punteros variables ahora se pueden usar como otras estructuras.
Pointers no es un puntero.
Son punteros int. Contiene dos elementos dentro de su marcado
que son punteros, pero los punteros en sí no son un puntero real.
Así que presta atención a eso. Es una variable de estructura que tiene dos punteros como
miembros, eso es diferente.
Entonces, si queremos acceder a los elementos dentro de
la variable de punteros que está en punteros,
no usamos el guión mayor que porque punteros no es un puntero, es una estructura.
Usaríamos el punto para
acceder a p1 y acceder a p2.
Entonces, en este ejemplo, creamos nuestra estructura,
creamos una variable. No es un puntero llamado punteros.
Y luego creamos dos enteros, i1
igual a 100 e i2 que no está inicializado.
Ahora p1 y p2 son punteros.
Por lo tanto, deben contener direcciones de memoria válidas donde las direcciones se
hayan asignado en memoria.
Y eso es lo que está haciendo en i1 e i2.
Cuando declaras las variables enteras, se asigna memoria para esos enteros.
Y así, al asignar la dirección i1 e i2 a p1 y p2, está perfectamente bien porque
i1 e i2 tienen memoria asignada porque son números enteros.
Ahora bien, si los punteros a números enteros no fueran punteros a números enteros sino
a caracteres, entonces tendría que asignar memoria dinámica.
Así que ahora solo estamos usando números enteros, por lo que asignamos las direcciones de los dos números enteros a p1 y p2.
Ahora podemos decir punteros de estrellas. p2 es igual a 97,
97 negativo.
¿Por qué tenemos que desreferenciarlo
allí porque punteros. p2 es lo que estamos haciendo referencia.
Punteros. pt p2 es un puntero.
No estamos accediendo a un elemento de una estructura.
Estamos eliminando las referencias a todos los punteros. p2.
Y vamos a asignarle el valor de lo que sea que apunta a 97 negativo.
Así que note la diferencia allí.
No estamos creando un puntero de estructura.
Estamos creando un puntero de variable regular, pero
contiene dos elementos que son punteros.
Entonces, si queremos asignar a esos dos elementos dentro de la estructura, tenemos que
desreferenciarlos usando el operador de indirección, y eso es lo
que hacemos allí.
Y luego en nuestras dos declaraciones impresas.
Nuevamente, queremos imprimir los valores de lo que apunta p1, por
lo que lo quitamos de referencia
con p2 y luego también queremos
imprimir nuevamente los valores a los que apuntan los punteros.
Entonces, en el primero, estamos diciendo que i1 es igual
al porcentaje de punteros de coma. p1 es igual al
porcentaje I.
Entonces, el primero dentro de las comillas dobles es simplemente imprimir ese texto real,
no está quitando la referencia a nada después de que la coma es donde estamos quitando la referencia.
Primero imprimimos i1, que es 100 y luego
imprimimos los punteros p1, que serían 100.
I2 en realidad será
97 negativo después de asignarlo a p2.
Entonces, ¿qué pasa con las matrices de caracteres o los punteros de caracteres? En la lección anterior, hablamos sobre
cómo se puede crear una matriz de caracteres como un elemento
dentro de un puntero. Pero, ¿qué pasa con los
punteros de carácter? ¿Deberíamos
hacer algo como primero y último
tener matrices de caracteres o deberíamos hacer algo como primero y
último con punteros de carácter como elementos? Cuál es la mejor opción.
Bueno, ya veremos. Es realmente una cosa de notación, pero hay ventajas al usar los punteros.
Entonces, cuando creamos punteros a personajes dentro de nuestros elementos, generalmente
es un poco mejor.
Pero debe comprender lo que está sucediendo aquí cuando crea una
matriz de caracteres de elementos de matriz como un elemento o un puntero como un elemento,
ambos son válidos. Pero hay una gran diferencia.
Entonces, si decimos nombres de estructuras
veep o vp y decimos Talia y Summers y luego decimos
nombre de puntero de estructura. Así que recuerde, los nombres de estructuras contienen las matrices de caracteres.
Los nombres de punteros de estructura contienen los punteros.
Y aquí estamos inicializando los punteros igual a Brad y Fallingjaw.
Y luego los imprimimos, imprimiremos el primer elemento, que es
un carácter ay vp y luego el
primer elemento de Treas, que es un puntero al primero.
Entonces, la estructura nombra la variable veep.
Lo que sucede aquí es que las cadenas se almacenan dentro de la estructura.
La estructura ha asignado un total de 40 bytes para contener los dos nombres,
son matrices de caracteres.
Eso es lo que sucede cuando creamos matrices de caracteres dentro de un puntero.
Estamos asignando 40 bytes para contener esos dos
nombres, 20 y 20.
Para los nombres de puntero variable Treas, ya sea que tengamos dos punteros primero y último,
estas son cadenas que se almacenan donde el compilador almacena las constantes de cadena.
La estructura contiene las dos
direcciones porque son punteros. Los punteros contienen, qué, valores que son direcciones.
Entonces, todo lo que va a hacer es asignar dos punteros dentro de esa estructura.
Eso es 16 bytes para la mayoría de los sistemas, punteros usualmente 8 bytes o 4 bytes.
La estructura de nombre struct p no asigna espacio para almacenar las
cadenas porque solo asigna espacio para los punteros.
Los punteros tienen valores que son direcciones.
La dirección a la que apunta no hay memoria asignada para eso.
Entonces, cuando crea esos dos punteros, no hay memoria asignada para esos dos punteros.
No asigna espacio.
Por lo tanto, solo se puede usar con cadenas a las que se les ha asignado espacio en otro lugar.
Siempre que tenga punteros dentro de una estructura, debe
usar malloc o calloc.
De lo contrario, podrían almacenarse donde se almacenen las constantes de cadena.
Y esa es la gran diferencia. Por lo tanto, los punteros y la estructura
del nombre p deben usarse solo para administrar cadenas que se crearon y asignaron en otra parte del programa.
No desea asignar datos
a eso a menos que los haya asignado dinámicamente o que se hayan
asignado en otro lugar, tal vez
por una estructura existente o algo así. Pero, por lo general, querrá mallocalizar esos punteros.
De nuevo, muy diferente.
Está asignando 40 bytes para estas dos matrices de caracteres dentro de la estructura de nombre.
Para la estructura de nombre p, tiene dos punteros.
No hay memoria asignada para eso cuando crea una variable de ese tipo.
Simplemente crea memoria para los dos punteros de caracteres, que son ocho bytes cada uno.
Para asignar memoria a lo que apuntan el primero y el último, debe hacer un malloc.
Entonces, una instancia en la que tiene sentido usar un puntero y una
estructura es manejar
cadenas es si está asignando dinámicamente esa memoria.
Por lo general, es entonces
cuando lo usa porque otros tipos de datos permitidos le asignarán automáticamente la memoria.
Entonces desea usar un puntero para almacenar la dirección.
Esto tiene la ventaja de que puede pedirle a malloc que asigne solo la cantidad de espacio
que se necesita para una cadena. Hablamos sobre las ventajas de la asignación dinámica de memoria.
Cuando crea cosas estáticamente en tiempo de compilación, solo va
a crear una cantidad específica de bytes.
¿Qué pasa si necesitas más bytes, estás jodido, tu programa no va a funcionar?
Tienes que volver y volver a compilar. Con cadenas asignadas dinámicamente,
puede reajustar, puede crear tanta memoria como necesite, lo que lo hace
mucho más eficiente en el programa.
Entonces, usará malloc en cualquier puntero creado dentro de una estructura.
Entonces, en este caso, tiene una estructura llamada name count.
Tiene dos punteros, punteros de carácter fname y apellido.
Y luego tienes un int, letras.
Las dos cadenas de aquí dentro no se almacenan en la estructura.
Solo creamos memoria para los punteros, que contienen direcciones.
Queremos crear memoria para fname y lname para lo que apuntan los punteros.
Entonces queremos almacenar eso en un fragmento administrado por la ubicación de memoria dinámica, que está usando malloc.
La dirección de las dos cadenas es lo que está almacenado, no a lo que apuntan.
Entonces, las direcciones son con lo que suelen trabajar las funciones de manejo de
cadenas, lo cual es bueno y es por eso que desea
usar punteros allí porque entonces no tiene que hacerlo, entonces puede pasarlos mucho más fácilmente.
Así que aquí tienes un ejemplo. Tenemos una función llamada obtener información.
Se necesita un puntero.
Y podemos pasar ese puntero muy fácilmente.
Ahora también vamos a crear otro
o para nuestra matriz de punteros
que le estamos pasando, vamos a
asignarle memoria.
Entonces verá que creamos un carácter llamado temp y
luego almacenamos algunos datos en ese temp.
Le pedimos al usuario que obtenga algo. No estamos familiarizados con los sgets, pero es lo mismo que el escaneo se guarda un poco.
Luego asignamos memoria para fname dentro de ese puntero y lo hacemos al igual que
asignamos memoria para cualquier carácter. Llamamos malloc, pasamos
el número de bytes.
En este caso, la longitud str de 10 más 1 para el terminador nulo.
Y luego recuerda, malloc se convierte en una estrella del vacío, así que se lo lanzamos a una estrella de personaje.
Pero esto es fundamental aquí mismo. Esta llamada malloc es necesaria para cualquier estructura que contenga punteros.
Ahora pasamos este puntero y el puntero nunca tuvo una memoria
asignada.
Así que estamos asignando memoria aquí. Entonces podemos hacer nuestra copia muy fácilmente.
Podemos copiar temp a fname de nuestra estructura pst que se
pasó como parámetro.
Y luego podemos hacer que ingresen su apellido, podemos malloc más memoria para el
apellido y luego almacenarlo en la variable de estructura de apellido.
Esto es lo que tendrás que hacer cuando tengas punteros a personajes
dentro de tus estructuras, tienes que hacer el malloc.
Porque nuevamente, esos punteros solo almacenan la dirección.
Asignan suficiente memoria para almacenar una dirección, pero no
suficiente memoria para almacenar una cadena.
Entonces, sea lo que sea que apunte esa dirección, debe asignar memoria para eso y
hacerlo como de costumbre con el malloc,
la única diferencia es que aquí usa el signo de guión mayor que para
acceder al elemento real dentro de esa estructura, que es un puntero de carácter, por lo que
puede asignárselo y eso está haciendo la eliminación de referencias.
Entonces querrás jugar con estas cosas. Esto es muy común
para los punteros de caracteres dentro de estructuras.
Tendremos un desafío en el que tendrás que hacer esto. Pero juegue con este código, ingrese
a los bloques de código, comience a asignar memoria para cadenas
o punteros de caracteres dentro de estructuras y vea
cómo puede usar la copia de str para poner datos allí, pero primero
debe asignar la memoria antes de asignar .
Si está haciendo constantes como en el ejemplo anterior, quién sabe dónde está asignada esa memoria.
De nuevo, se presentan muchos conceptos importantes en esta conferencia.
Esta idea de una estructura que es un puntero en
esta nueva sintaxis
donde puede usar el guión luego mayor que en lugar de usar
el operador de indirección, muy agradable.
Y luego tener elementos como punteros y cómo hay
que asignar memoria para punteros de caracteres. Gracias.