Está en la página 1de 33

Almacenamiento Lineal de Datos: Arreglos, Strings y

Estructuras

Introducción a la Ingenierı́a

Ayudantes: Francisco Olivares, Camilo Pérez, Ignacio Tampe

Departamento de Informática, UTFSM

francisco.olivars.14@sansano.usm.cl
camilo.perez@alumnos.inf.utfsm.cl
ignacio.tampe@sansano.usm.cl

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 1 / 32


Arreglos

Almacenamiento básico de datos

I La primera estructura que aprendieron a usar en Programación fueron


las listas.
I Pero las listas no existen de forma nativa en C, y además su
implementación no es trivial.
I Materia de Estructuras de Datos!
I El ”análogo” nativo que existe en C son los arreglos.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 2 / 32


Arreglos

Arreglos

I Arreglo: colección lineal y no dinámica de datos del mismo tipo.


I Son bloques de memoria contigua convenientemente fileteados para
que en cada casilla quepa un elemento.
I Verán más detalles en Lenguajes de Programación.
I Por el momento lo que nos interesa es saber cómo crearlos y usarlos.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 3 / 32


Arreglos

Creación y uso de arreglos

I Al igual que con las variables, debemos especificar el tipo de elemento


que irá en cada casilla del arreglo.
I Podrı́a ayudarlos el ver a los arreglos como un puñado de variables
pegadas... pueden ser declaradas, definidas e inicializadas de forma
independiente, o todas juntas.

int arreglo[5];

I Aquı́ hemos creado un arreglo con tamaño máximo 5.


I Caben 5 enteros como máximo, pero no hemos inicializado ninguno
todavı́a.
I Por lo tanto, el contenido actual es basura.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 4 / 32


Arreglos

Basura?

I Basura.

#include <stdio.h>
int main(){
int basura[100], i;
for (i = 0; i < 100; i++){
printf("%d", basura[i]);
}
printf("\n");
return 0;
}

Conteo de ”basura” en esta diapositiva: 10 ocurrencias

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 5 / 32


Arreglos

I Recuerdan que Python permitı́a explicitar los contenidos de una lista


para crearla?
I Eso también se puede hacer con los arreglos de C:

int arreglo2[5] = {1, 2, 3, 4, 5};

I En este caso declaramos que el arreglo tenı́a tamaño 5, y luego


indicamos qué 5 elementos tendrı́a.
I Pero también podemos no decirle cuántos elementos son si le decimos
cuáles son:

int arreglo3[] = {4, 2, 0, 6, 9};

I Aquı́ tenemos un arreglo de tamaño 5 sin que le tuviésemos que decir


que eran 5.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 6 / 32


Arreglos

I También puedo elegir decir la cantidad de elementos que tendrá el


arreglo pero no inicializarlos todos:

int arreglo4[10] = {9, 9, 9, 9, 9, 9};

I En este caso tenemos espacio reservado en memoria para 10 enteros,


pero sólo hemos definido los valores de los primeros 6.
I Por lo tanto, los otros 4 son basura. No tiene sentido el intentar
emplearlos.
I Y, naturalmente, podemos guardar cualquier tipo de datos en un
arreglo:

float arreglo5[] = {1.0, 0.5, 0.25, 0.125, 0.0625};

I Aquı́ tenemos un arreglo de números de punto flotante.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 7 / 32


Arreglos

I Ok, tengo mi arreglo creado.


I Pregunta: Ahora, cómo accedo a los contenidos?
I Respuesta: Mediante la notación de corchetes, al igual que con las
listas de Python.

float ejemplo = arreglo5[2];

I Las reglas de indexación son las mismas que las que conocen (es
decir, partimos contando desde cero).
I Por lo tanto, ejemplo contendrá el tercer valor de arreglo5, que
serı́a 0.25.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 8 / 32


Arreglos

I En algún momento podrı́a querer conocer la cantidad de elementos


que hay en un arreglo.
I Pero la función len() no existe en C.
I Solución: Usar el operador sizeof.
I Es un operador unario que devuelve la cantidad de bytes que un
elemento ocupa en memoria.
I Entonces, puedo usarlo para obtener el tamaño en bytes de un
arreglo, luego obtener el tamaño en bytes de uno de los elementos
que contiene el arreglo, y luego dividir los dos valores.

int tamanyo = sizeof arreglo5 / sizeof float;

I Pero... qué hacemos si no sabemos qué contiene el arreglo?


I gcc nos ofrece el operador typeof!

tamanyo = sizeof arreglo5 / sizeof (typeof arreglo5[0]);


Nota 1: Puedo hacer esto sin preocuparme porque sizeof tiene mayor precedencia que el operador de división.
Nota 2: Este truco sólo funciona con arreglos definidos estáticamente, verán la diferencia en Lenguajes de Programación.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 9 / 32


Strings

Strings
I Python posee un tipo de datos especial para los strings.
I Pero eso en C no existe...
I Los strings son arreglos de caracteres.
I Para indicar el fin del string, se debe usar el caracter especial “\0”.
I Es una forma de decirle a NULL.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 10 / 32


Strings

I Y por qué se debe usar el caracter especial ese?


I Cuando C lee un arreglo, leerá lo que encuentre en memoria hasta
que se tope con un valor nulo.
I También podemos inicializar el string de forma explı́cita.
I Ejemplo:

char string[] = "Intro a la Ingenieria";

I Cuando indicamos el string explı́citamente C pone un \0 de forma


automática.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 11 / 32


Strings

I Qué pasó aquı́?

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 12 / 32


Strings

I Qué pasó aquı́?


I Representemos la memoria como una matriz.
0x64 0 0 h o
0x68 l a m
Sı́mbolo Dirección
0x6C u n d o
ejemplo1 0x66
0x70 h o l a
ejemplo2 0x70
0x74 \0 m u
0x78 n d o 0

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 12 / 32


Strings

Trabajo con strings

I Como los strings no existen como tipo básico, entonces hay un


montón de cosas que no se pueden hacer por defecto que en Python
sı́ se podı́an.
I Ejemplo: concatenación mediante el operador de suma.
I Habrı́a que entrar a modificar los strings manualmente, caracter por
caracter.
I Y como los arreglos son inmutables, habrı́a que crear más strings cada
vez que crezca.
I Afortunadamente, alguien lo hizo ya por nosotros.
I Sólo debemos importar la librerı́a string.h.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 13 / 32


Strings

Largo

I Para obtener el largo de un string usaremos strlen.

size t strlen(const char *str)

I El argumento es un string, y el retorno es un tipo de valor que se


puede guardar en un entero sin problemas.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 14 / 32


Strings

I Ejemplo en Python:

string = "13 caracteres"


largo = len(string)
print "\"" + string + "\" tiene " + largo + "caracteres."

I Ejemplo equivalente en C:

#include <stdio.h>
#include <string.h>

int main(){
char string[] = "13 caracteres";
int largo = strlen(string);
printf("\"%s\" tiene %d caracteres.", string, largo);
return 0;
}

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 15 / 32


Strings

Copia

I Para copiar un string hacia otra variable usaremos strcpy.

char *strcpy(char *dest, const char *src)

I El argumento son dos strings. El primero es la variable de destino, en


dónde quieren copiar. El segundo es la variable fuente, qué string
quieren copiar. La función retorna un puntero al destino, pueden
ignorarlo por ahora.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 16 / 32


Strings

I Ejemplo en Python: I Ejemplo equivalente en C:

string1 = "ejemplo" #include <stdio.h>


string2 = string1 #include <string.h>
print string2
int main(){
char string1[] = "ejemplo";
char string2[8];
strcpy(string2, string1);
printf("%s", string2);
return 0;
}
I Noten que deben pasar como destino un string que tenga tamaño
suficiente. Si es muy chico, C no reclamará, pero strcpy escribirá
saliéndose de la memoria que tienen asignada y podrı́a pasar a llevar
otras variables, lo cual es peligroso.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 17 / 32


Strings

I Este ejemplo puede verse inofensivo, y hasta ridı́culo.


I Pero el mal manejo de strings puede presentar graves problemas de
seguridad, sobre todo si dichos strings son generados por usuarios.
I Googleen “buffer overflow” (desbordamiento de buffer).
IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 18 / 32
Strings

Concatenación

I Para concatenar un string con otro usaremos strcat.

char *strcat(char *dest, const char *src)

I El argumento son dos strings. El primero es la variable de destino, a


la que le quieren concatenar algo. Debe tener el espacio suficiente
para poder albergar los dos strings juntos. El segundo es la variable
fuente, qué string quieren ponerle al lado. La función retorna un
puntero al destino, nuevamente pueden ignorarlo por ahora.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 19 / 32


Strings

I Ejemplo en Python: I Ejemplo equivalente en C:

hola = "saludos" #include <stdio.h>


mundo = "universo" #include <string.h>
string = hola + mundo
print string int main(){
char hola[] = "saludos";
char mundo[] = "universo";
char string[16];
strcpy(string, hola);
strcat(string, mundo);
printf("%s", string);
return 0;
}
I Ambos programas imprimen saludosuniverso. No olviden tener en
cuenta los espacios!

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 20 / 32


Strings

I Pero... qué pasa si el string que estoy concatenando no tiene un \0 al


final?
I strcat no se detendrá nunca y concatenará toda la memoria...
I O lo intentará, al menos.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 21 / 32


Strings

Concatenación controlada
I Qué pasó aquı́?
I Es una situación llamada “stack buffer overflow” (desbordamiento de
buffer de pila).
I Potencial fuente de bugs y problemas de seguridad!
I Para evitar esto, acostúmbrense a usar strncat en vez de strcat.

char *strncat(char *dest, const char *src, size t n)

I El argumento son dos strings y un número n. Hace lo mismo que


strcat, con la salvedad de que sólo concatenará hasta un máximo de
n caracteres.
I No hay razón para usar strcat en vez de strncat si saben el
tamaño máximo de lo que van a concatenar. E incluso aunque no lo
sepan, no es recomendable usarla.
IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 22 / 32
Strings

Comparación

I Con lo que hemos visto hasta ahora, serı́a ridı́culo pensar que C
permitirı́a usar operadores de comparación para ver si dos strings son
iguales o si alguno va antes que el otro.
I Efectivamente, es ridı́culo.
I Para comparar un string con otro usaremos strcmp.

int strcmp(const char *str1, const char *str2)

I El argumento son dos strings str1 y str2. El retorno es un entero, que


será 0 si ambos strings son iguales, menor a 0 si str1 va antes que
str2 al ordenarlos alfabéticamente, y mayor a 0 si str2 va primero.
Nota: La comparación se realiza con respecto a los valores ASCII, donde las mayúsculas van antes que las minúsculas.
strcmp("Abc", "abc") retornarı́a un valor menor a 0, por ejemplo.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 23 / 32


Strings

I Ejemplo en Python:
print "Escriba \"salir\" para terminar el programa."
while raw_input() != "salir":
continue
I Ejemplo equivalente en C:
#include <stdio.h>
#include <string.h>

int main(){
char cierre[10];
printf("Escriba \"salir\" para terminar el programa.\n");
while(strcmp(cierre, "salir") != 0){
scanf("%s", cierre);
}
return 0;
}
IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 24 / 32
Estructuras

Estructuras

I Estructura: colección no dinámica de datos de varios tipos.


I Son bloques de memoria contigua divididos en espacios de distintos
tamaños para almacenar varias variables de una vez.
I Son una forma sencilla de manejar datos pertinentes a un solo ente.
I Son las antepasadas de las clases y los objetos!

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 25 / 32


Estructuras

Creación y uso de estructuras


I Al igual que con las variables y arreglos, debemos especificar el tipo
de elemento que tendrá cada miembro de la estructura.
I Tiene sentido si pensamos que realmente son un montón de variables
unidas por un nombre común.

struct estudiante{
char nombre[20];
int edad;
char rol[12];
};

I Aquı́ hemos creado un tipo de estructura “estudiante” que puede


almacenar dos strings y un entero.
I Lo que hemos hecho aquı́ es definir una plantilla para estudiantes, que
después podremos instanciar como si fuesen variables.
IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 26 / 32
Estructuras

struct estudiante ejemplo;

I Ahora tenemos una variable estructurada llamada ejemplo, cuyos


contenidos no están inicializados, y por lo tanto, son basura.
I Existen un par de formas de inicializar que les podrı́an recordar a los
arreglos.
I Opción 1: Dar todos los datos en orden y de inmediato, usando llaves.

struct estudiante alumno1 = {"Rafael", 22, "201273501-7"};

I El operador . (punto) se llama operador de membresı́a, y permite


acceder a los datos de una estructura.
I Si quisiéramos guardar la edad de Rafael en una variable, dirı́amos:

int Rafaedad = alumno1.edad;

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 27 / 32


Estructuras

I Opción 2: Dar todos o algunos de los datos de inmediato, en


desorden, indicando qué campos estoy dando.

struct estudiante alumno2 = {.rol = "201273552-1", .nombre


= "Diego"};

I Esto se puede leer como “el miembro de la estructura “rol” tiene el


valor...”
I Si necesitamos definir los miembros faltantes de la estructura lo
podremos hacer de forma separada.
I Supongamos que Diego se ha echado Quı́mica y Sociedad muchas
veces y se las ha arreglado de alguna forma para que no lo echen,
para fijar su edad escribiremos:

alumno2.edad = 40;

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 28 / 32


Estructuras

I Lo que nos lleva directamente a la otra forma...


I Opción 3: Definir la estructura y luego inicializar cada elemento en
instrucciones separadas.
struct estudiante alumno3;
alumno3.edad = 22;
strcpy(alumno3.nombre, "Fabian");
strcpy(alumno3.rol, "201273549-1");

I Si fuese necesario crear un arreglo de estructuras, entonces esta serı́a


la mejor opción.

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 29 / 32


Estructuras

La instrucción typedef
I Es posible evitar escribir struct cada vez que quieran definir una
variable estructurada.
I Para esto definiremos un tipo personalizado mediante la palabra clave
typedef.
I La sintaxis es la siguiente:

typedef <contenido a definir> <nombre del nuevo tipo>;

I Por lo tanto, podrı́amos haber definido la estructura estudiante de


la siguiente forma:
typedef struct estudiante{
char nombre[20];
int edad;
char rol[12];
} alumno;
IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 30 / 32
Estructuras

I Esto causarı́a que alumno se convirtiese en un tipo de dato


reconocido por el lenguaje, y luego podrı́amos definir a otro
estudiante (ahora “alumno”) de la siguiente forma:

alumno alumno4 = {"Sebastian", 20, "201473525-1"};

I typedef se puede usar para definir cualquier estructura o tipo de


datos como un tipo nuevo.
I Su imaginación es el lı́mite!
I Podrı́an, incluso, programar strings como un tipo legı́timo de datos...

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 31 / 32


Estructuras

Almacenamiento Lineal de Datos: Arreglos, Strings y


Estructuras

Introducción a la Ingenierı́a

Ayudantes: Francisco Olivares, Camilo Pérez, Ignacio Tampe

Departamento de Informática, UTFSM

francisco.olivars.14@sansano.usm.cl
camilo.perez@alumnos.inf.utfsm.cl
ignacio.tampe@sansano.usm.cl

IWG-101 (FO/CP/IT) Arreglos y estructuras 26-28-30/09/2016 32 / 32

También podría gustarte