Estructuras y uniones

Tutoriales de Programaciones

Si conoces el uso de arrays en C, aprender como se usan estructuras y uniones te será de lo más sencillo. Visto por encima, una estructura es un array que tiene la capacidad de almacenar variables con distintos tipos y nombres. Una unión es similar a una estructura, pero solo podrá tener un valor a la vez. Si quieres aprender a usarlas, lee este tutorial.

Estructuras

Definición

Como ya se ha dicho, una estructura es un grupo de variables, y estas últimas pueden adoptar distintos valores, tipos y nombres.

Por norma general, una estructura se define:

struct {
   int edad;
   float velocidad;
   double micoche;
} nombre_estructura;

Analicemos la situación. En primer lugar, en la primera línea, hay un "struct {". Struct es la palabra clave para definir una estructura en C; el corchete está para englobar el contenido de la misma. Después, hay tres variables corrientes, dentro de la estructura. Por último, un corchete cierra la estructura. Nombre_estructura; es el identificador para llamar a la estructura posteriormente.

Cabe destacar que las variables NO se pueden inicializar en el momento de la definición. Veamos un ejemplo:

struct {
   int edad = 43;
   char* nombre = "juanito";
   float estatura = 10.2;
} persona;

Este ejemplo dará error. Para que funcione tendremos que quitar las inicializaciones y hacer esta acción posteriormente:

struct {
   int edad;
   char* nombre;
   float estatura;
} persona;
 
persona.edad = 24;
persona.nombre = "charles";
persona.estatura = 1.32;

Como has podido observar en el último ejemplo, para acceder a uno de los elementos de una estructura se hace del siguiente modo:

struct {
...
   int nomvariable;
...
} nomstruct;
 
...
nomstruct.nomvariable = 5;
...

Simple, ¿no?

A continuación hay un ejemplo que muestra el funcionamiento de una estructura dentro de un programa:

#include <stdio.h>
 
int main(){
   struct{
      int edad;
      float estatura;
      char* nombre;
   } persona;
 
   printf( "Hola! Voy a hacerte unas preguntas:");
   printf( "\nComo te llamas? : ");
   scanf( "%s", persona.nombre );
 
   printf( "\nCuantos anios tienes? : ");
   scanf( "%d", &persona.edad );
 
   printf( "\nCuanto mides? : ");
   scanf( "%f", &persona.estatura );
 
   printf( "Te llamas %s tienes %d anios y mides %.2f", persona.nombre, persona.edad, persona.estatura );
 
   return 0;
   getchar();
}

Observa que se usan como cualquier otro tipo de variables normales y corrientes, pero almacenadas dentro de un grupo.

Además, una estructura puede contener a otra:

struct{
   int edad;
   char* nombre;
 
   struct{
      int numero;
      char* direccion;
      int telefono;
   } vivienda;
 
} persona;

Para acceder a la dirección, por ejemplo, habría que escribir "persona.casa.direccion;"

Aunque ya te habrás dado cuenta, he de reconocer que las estructuras apenas tienen ningún misterio pero son muy útiles, pues permite tener datos mejor agrupados y organizados. Además, una estructura no se limita a lo visto anteriormente, podemos definir arrays de estructuras y un typedef de las mismas, siendo esta parte la más interesante.

Arrays de estructuras

struct{
   int edad;
   char* nombre;
 
   struct{
      int numero;
      char* direccion;
      int telefono;
   } vivienda;
 
} persona[10];

Ese ejemplo es el anterior, pero hemos creado 10 personas con los mismos datos. Para acceder, por ejemplo al número 3 habría que escribir:

persona[2].nombre;

Por si no ha quedado del todo claro, a continuación hay una versión modificada del último ejemplo:

/*De P22 Para Scenebeta
Este programa aplica las normas de copia propias de scenebeta*/
#include <stdio.h>
 
int main(){
 
   int npersonas;
   int i = 1;
 
   struct{
      int edad;
      float estatura;
      char* nombre;
   } persona[9];
 
   printf( "Hola! Voy a hacerte unas preguntas:");
   printf( "Cuantas personas participaran?" );
   scanf( "%i", &npersonas );
 
   for( i = 0; i < 10 ; i++ )
   {
      printf( "\nComo te llamas? : ");
      scanf( "%s", &persona[i].nombre );
 
      printf( "\nCuantos anios tienes? : ");
      scanf( "%d", &persona[i].edad );
 
      printf( "\nCuanto mides? : ");
      scanf( "%f", &persona[i].estatura );
 
      printf( "Te llamas %s tienes %d anios y mides %.2f", &persona[i].nombre, persona[i].edad, persona[i].estatura );
   }
 
   return 0;
   getchar();
}

Podrás observar que es similar a cualquier tipo de array, pero aplicando las normas de estructuras.

Copia de estructuras

C permite la copia de estructuras de una manera muy simple:

estructura1 = estructura2;

En primer lugar, para poder realizar eso, es necesario que ambas estructuras tengan la misma composicion de variables. Por ejemplo:

//BIEN
struct{
   int a;
} estructura[1];
 
estructura[0].a = 2;
 
estructura[1] = estructura[0];
 
//MAL
struct{
   int a;
}estructura1;
 
struct{
   int j;
   float y;
} estructura2;
 
estructura1.a = 0;
 
estructura2 = estructura1;

La copia de estructuras es algo sencillo, pero que puede darnos quebraderos de cabeza irresolvibles. Hasta ahora, todo lo que hemos visto es muy simple, pero ¿qué pasa si creo una estructura dentro de una función y la uso de return?

#include <stdio.h>
 
typedef struct{
   int edad;
   float peso;
   char* nombre;
   int* puntero;
} persona;
 
int main(){
 
   persona copiaestructuras();
 
   persona a;
   a.edad = 45;
   a.peso = 54.6;
   a.nombre = "juan pedro";
   a.puntero = &a.edad;
 
   a = copiaestructuras();
 
   printf("La edad de %s es %i", a.nombre, a.puntero);
 
   getchar();
   return 0;
}
 
persona copiaestructuras(){
   persona b;
   b.edad = 14;
   b.peso = 84.3;
   b.nombre = "pepito";
   b.puntero = &b.edad;
 
   return b;
}

Estamos creando una estructura de tipo auto, por lo que en cuanto se termine su ámbito, se borrará por completo, lo cual quiere decir que el puntero también, y estaremos asignando el valor de una dirección no correspondiente al programa a un puntero. Esto como mucho (al menos en windows, desconozco en otros OS) nos causará la típica ventanita con un circulito rojo y una cruz, o en el mejor de los casos un valor no esperado sin error, pero son errores de los más difíciles de encontrar.

Además, he adelantado una cosa de más adelante. Se trata del typedef

Typedef con estructuras

Typedef lo que hace básicamente es asignar un código encerrado entre el identificador y el typedef en cuestión para evitar partes confusas, repeticiones y demás (siempre que sea en un lugar válido). Así, el ejemplo siguiente sería lo más básico de tyedef:

//Sin typedef
int funcion(){
   float peso;
   float altura;
}
 
//Con typedef
int funcion(){
   typedef float decimal;
   decimal peso;
   decimal altura;
}

Se entiende mejor la última, ¿verdad? Pues esto no se queda ahí. Con estructuras, podemos hacer algo similar, ahorrando trabajo:

//sin typedef
int funcion(){
   struct {
      int edad;
      float peso;
   } a, b;
   return 0;
}
 
//Con typedef
int funcion(){
   typedef struct {
      int edad;
      float peso;
   } persona;
 
   persona a, b;
 
   return 0;
}

Así en un programa corto, puede parecer aparatoso, pero si nos fijamos en uno mayor como puede ser el último ejemplo del apartado de copia de estructuras, será más sencillo y nos ahorrará líneas. Cabe destacar que el typedef se puede usar en cualquier parte del programa.

Uniones

Definición

Si sabes como funciona una estructura, esto será de lo más fácil de explicar. Una unión es un tipo de estructura que tiene una característica especial: Sólo puede tener en uso una variable a la vez. Así, se consigue ahorrar espacio en la memoria, es decir:

//Estrucutra
struct{
   int a;
   float b;
   char c;
   double d;
} estructura;
 
/*El tamaño de la estructura será (depende del compilador):
2 (int) + 4 (float) + 2 (char) + 8 (double) = 16 bytes de memoria*/
 
//Unión
union{
   int a;
   float b;
   char c;
   double d;
} nombre_union;
 
/*El tamaño de la unión será (depende del compilador):
8 (double)*/

Y pensarás: "Y esto por qué" muy simple: sólo puede tener un valor, por lo que toma el tamaño de la variable más grande, pudiendo tener el valor de cualquiera de ellas.

Por norma general, una unión se define:

union {
   int a;
   float b;
   char** j;
} nombre_union;

Un ejemplo aclarará este embrollo.

#include <stdio.h>
 
int main(){
 
   unsigned short int selector;
 
   union {
      short int largo;
      short int ancho;
      } piscina;
 
   piscina.largo = 40;
   piscina.ancho = 30;
 
   printf("Que quieres saber acerca de mi piscina?: \n   (1) Ancho\n   (2)Largo\n   ");
   scanf("%d", &selector);
 
   if( selector == 1 ) printf( "Ancho = %i", piscina.ancho );
   else printf( "Largo = %i", piscina.largo );
 
   return 0;
   getchar();
}

De momento esto es todo lo que has de saber acerca de uniones y estructuras. Sobre las uniones, cabe destacar que todo lo dicho acerca de estructuras se aplica a estas (adaptado), y que una unión puede contener estructuras y viceversa.

Recuerda, si quieres aprender, debes practicar con programas que aunque en un principio puedan parecer patéticos, lo agradecerás en un futuro.

4.64706
Tu voto: Ninguno Votos totales: 4.6 (34 votos)

Anuncios Google

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de Dioni0396

Tengo una duda, pero mejor la expreso en codigo

struct{
  int x;
} J1;
struct{
  int x;
} J2;
//Esto se podria hacer, tener dos X declaradas de la misma forma??

Imagen de joserc87

Por supuesto.

Tendrías dos variables del mismo tipo.

Aunque si vas a hacer eso, es más lógico hacerlo así:

struct MyStruct{
  int x;
};
struct MyStruct J1, J2, J3,...;

Es decir, la estructura la declaras una vez y la usas tantas veces como tu quieras.


Be pointer my friend...

Dennis Ritchie. Padre de C y cocreador de UNIX.

R.I.P.

 

Imagen de Dioni0396

Gracias ;)

:)

Imagen de ALCales

que funcion hace el '*' de

que funcion hace el '*' de char* nombre_variable???

puede ser que sea lo mismo que char nombre_variable[]??

saludos y gracias! ;)

Imagen de Loopin

Cuando pones un * entre el

Cuando pones un * entre el tipo y el nombre de la variable, significa que estas declarando un puntero de tipo char. Es decir, es una variable (el puntero) que va almacenar la direccion de una variable (la zona de memoria a la que apunta) de tipo char. Por otro lado, con esa misma declaracion puedes instanciar un array dinamico de tipo char, con lo que la variable almacenara la direccion de la primera posicion del array en memoria dinamica.

Un saludo.


El ejemplo: /*De P22 Para

El ejemplo:

/*De P22 Para Scenebeta
Este programa aplica las normas de copia propias de scenebeta*/
#include <stdio.h>
 
int main(){
 
   int npersonas;
   int i = 1;
 
   struct{
      int edad;
      float estatura;
      char* nombre;
   } persona[9];
 
   printf( "Hola! Voy a hacerte unas preguntas:");
   printf( "Cuantas personas participaran?" );
   scanf( "%i", &npersonas );
 
   for( i = 0; i < 10 ; i++ )
   {
      printf( "\nComo te llamas? : ");
      scanf( "%s", &persona[i].nombre );
 
      printf( "\nCuantos anios tienes? : ");
      scanf( "%d", &persona[i].edad );
 
      printf( "\nCuanto mides? : ");
      scanf( "%f", &persona[i].estatura );
 
      printf( "Te llamas %s tienes %d anios y mides %.2f", &persona[i].nombre, persona[i].edad, persona[i].estatura );
   }
 
   return 0;
   getchar();
}

Tendría de ser algo así, digo para que funcione correctamente ;)
#include <stdio.h>
 
int main(){
 
   int npersonas;
   int i = 1;
 
   struct{
      int edad;
      float estatura;
      char* nombre;
   } persona[npersonas];
 
   printf( "Hola! Voy a hacerte unas preguntas:");
   printf( "\nCuantas personas participaran? " );
   scanf( "%i", &npersonas );
 
   for( i = 0; i < npersonas ; i++ )
   {
      printf( "\nComo te llamas? : ");
      scanf( "%s", &persona[i].nombre );
 
      printf( "\nCuantos anios tienes? : ");
      scanf( "%d", &persona[i].edad );
 
      printf( "\nCuanto mides? : ");
      scanf( "%f", &persona[i].estatura );
 
      printf( "Te llamas %s tienes %d anios y mides %.2f", &persona[i].nombre, persona[i].edad, persona[i].estatura );
   }
   return 0;
   getchar();
}

Imagen de P22

En parte llevas razón

Y digo en parte, porque he localizado un error en tu código, y es que defines un array de estructuras con un índice de una variable que no ha sido inicializada, lo cual es extremadamente peligroso pues no sabes que saldrá. Eso no se debe hacer nunca, ya que provocaría desde resultados inesperados hasta un crasheo del programa. Solo te aviso para que tengas más cuidad lo próxima vez.

Un saludo, y feliz navidad.

PD: Siento no haberte respondido antes, pero no lo he leído hasta hoy :S


¡Iníciate en Linux fácilmente! Sólo entra aquí y comprueba que distribución se adapta mejor a tí.

Mi review: iPod Touch 4G

Imagen de Loopin

Tengo entendido que no es

Tengo entendido que no es necesario el typedef, sino:

struct persona {

.....

} p1, p2;

Siendo "persona" el tipo de estructura, y p1 y p2 las variables.

PD: Buente tuto ;)


Imagen de P22

Claro que no

Es que en ningún momento he dicho lo contrario :P Simplemente, que si quieres definir estructuras similares en distintas funciones, haces un typedef global y te ahorras definir dos veces :D

PD: Gracias ;-)


¡Iníciate en Linux fácilmente! Sólo entra aquí y comprueba que distribución se adapta mejor a tí.

Mi review: iPod Touch 4G

Imagen de joserc87

No te acostaras sin saber algo nuevo...

Tantos años programando y me acabo de enterar del truquillo del typedef cuando se usa con struct. Para aclarar un poco, las estructuras se declaran por defecto como:

struct NombreEstructura{
  int a;
  float b;
};
// y luego defines la variable
int main (){
  struct NombreEstructura estr;
  estr.a=0;
}

pero para evitar tener que definir las variables poniendo la palabra struct, podemos definir la estructura con typedef:

 

typedef struct{
  int a;
  float b;
} NombreEstructura;
// y luego defines la variable
int main (){
  NombreEstructura estr; // Sin la palabra struct
  estr.a=0;
}

Es decir que si ponemos la palabra typedef, luego nos ahorramos la palabra struct al definir la variable "estr". No es más que un truquillo, que hace lo mismo. La explicación científica es que crea un tipo NombreEstructura que significa literalmente "struct{int a;float b}", por lo que la declaración:

NombreEstructura estr;  se transforma en la fase de precompilación en:

struct {int a; float b;} estr;  ;).

Es curioso, porque como casi siempre trabajo en C++, nunca me había puesto a pensar sobre esto, ya que en C++ no hace falta poner la palabra struct al declarar las variables.

Buen tutorial P22! A mi por lo menos me ha servido para reflexionar...


Be pointer my friend...

Dennis Ritchie. Padre de C y cocreador de UNIX.

R.I.P.

 

Imagen de exterminator

Corrígeme si me equivoco

pero el primer ejemplo de estructura definida como un array cometes un error, y es que creas la estructura persona[10], o sea, un array unidimensional de 10 componentes, e indicas que es de 11 componentes. Y, que yo recuerde, al declarar cualquier array el número entre corchetes siempre indicará el tamaño sin contar el 0 (oséase, que se declaran indicando el número de elementos, no el número del elemento último).

Y otra cosa, que es que si algo no tiene solución es irresoluble, no insolvible :P.

Por lo demás muy interesante el tutorial, aunque me parece que no usaba bien el typedef hasta ahora (curioso, puesto que nunca me ha dado ni error ni problemas).

Un saludo.


Para recibir ayuda por parte de otros usuarios más rápidamente, recomendamos que pongas títulos descriptivos y no utilices abreviaturas (estilo MSN) en tus post de los foros. Recuerda que accediendo al Manual del perfecto forero y las Normas de la Comunidad aprenderás trucos para resolver tus dudas antes.

Imagen de P22

Gracias por corregirme el

Gracias por corregirme el error, esa parte la hice cuando aún creía que las definiciones empezaban por 0 :P

Lo de insolvible, no lo encuentro en el tutorial :S

El typedef, podrías decirme como lo usas? Es solo por saberlo, a lo mejor se puede de varias maneras


¡Iníciate en Linux fácilmente! Sólo entra aquí y comprueba que distribución se adapta mejor a tí.

Mi review: iPod Touch 4G

Imagen de exterminator

En el apartado

de copiar estructuras, justo debajo del primer código de dicho apartado, pones "dolores de cabeza irresolvibles".

Respecto al typedef, lo uso tal que así:

typedef struct
{
       u8 a;
       int b;
       u16 c;
} estructura1;
 
estructura1 nombrestructura[7];

Renombro siempre a la estructura, me parece que si no me daba error (aquí no puedo saberlo)

Salu2


Para recibir ayuda por parte de otros usuarios más rápidamente, recomendamos que pongas títulos descriptivos y no utilices abreviaturas (estilo MSN) en tus post de los foros. Recuerda que accediendo al Manual del perfecto forero y las Normas de la Comunidad aprenderás trucos para resolver tus dudas antes.

Imagen de P22

¿?

Vale, lo primero ya está localizado, ahora lo cambio :P

Respecto a lo segundo, yo lo veo igual que en el tutorial...

Imagen de exterminator

Lo que pasa

es que yo pensaba que tenía que renombrar la estructura porque sí. Jamás se me pasó por la cabeza que lo que en realidad hago es crearme un tipo de dato propio como quien dice, para luego usarlo tantas veces quiera.

Salu2


Para recibir ayuda por parte de otros usuarios más rápidamente, recomendamos que pongas títulos descriptivos y no utilices abreviaturas (estilo MSN) en tus post de los foros. Recuerda que accediendo al Manual del perfecto forero y las Normas de la Comunidad aprenderás trucos para resolver tus dudas antes.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.