Programación en c (iii parte)

57
Programación en C (III Parte) 06/06/2022 Realizado por Mariela Curiel Universidad Simón Bolívar Junio, 2011

description

Fundamentos de Programación en C, última parte.

Transcript of Programación en c (iii parte)

Page 1: Programación en c (iii parte)

Programación en C (III Parte)

09/04/2023

Realizado por Mariela CurielUniversidad Simón BolívarJunio, 2011

Page 2: Programación en c (iii parte)

Contenido

ApuntadoresManejo de memoria dinámica.

Listas Línea de comandos del main()Entrada/Salida

09/04/2023 2

Page 3: Programación en c (iii parte)

Contenido

FuncionesApuntadoresManejo de memoria dinámica.

Listas Línea de comandos del MainEntrada/Salida

09/04/2023 3

Page 4: Programación en c (iii parte)

Apuntadores

Los apuntadores en el Lenguaje C, son variables que poseen la dirección de la ubicación en memoria de otras variables.

Declaración de un apuntador:tipo de variable apuntada *nombre_apunt;int *pint ;double *pfloat ;char *letra , *codigo , *caracter ;

Page 5: Programación en c (iii parte)

Apuntadores

int x; /* se crea en memoria una variable entera */

int *p; /* se declara un apuntador que contendrá la dirección de una variable entera */

p = &x; /* al apuntador se le asigna la dirección de la variable entera (x) */

Page 6: Programación en c (iii parte)

Apuntadores

int c, ...;int *p;

c = 63;p = &c;

0481216

202428

c: 63

p:4

Page 7: Programación en c (iii parte)

Apuntadores

int c, ...;int *p;

c = 63;

0481216

202428

c: 63

p:

Page 8: Programación en c (iii parte)

Apuntadores

int c,…;int *p;

c = 63;p = &c;*p = 40;

0481216

202428

c: 40

p:4

Page 9: Programación en c (iii parte)

Apuntadores

IMPORTANTE: Cuando se declara un apuntador no apunta a ningún lugar. Es necesario inicializarlo antes de usarlo.

int *p; *p = 100; /* error */ El uso correcto es: int *p, x; p = &x; // se inicializa el apuntador

*p = 100; // se está dando un valor a lo apuntado por p.

Page 10: Programación en c (iii parte)

Apuntadores

El símbolo & , se puede aplicar a variables, funciones , etc , pero no a constantes o expresiones.

Para hallar el valor apuntado se utiliza el operador (*). Así, son equivalentes:y = x ; y = *p; // tomando en cuenta la asignación de la lámina anterior.printf("%d" , x ) ;printf("%d" , *p) ;

Page 11: Programación en c (iii parte)

Operaciones sobre Apuntadores

Incremento de apuntadores

int *dir;

....

dir + 1; /* Ok */

dir += 10; /* incrementa dir para apuntar 10 elementos. mas adelante */

Page 12: Programación en c (iii parte)

Apuntadores

Cuando se incrementa un apuntador se incrementa en un bloque de memoria (depende del tipo). Ejem:

p++;

◦Un apuntador a carácter sumará un byte a la dirección.

◦Un apuntador a entero o float sumará 4 bytes a la dirección

Page 13: Programación en c (iii parte)

Operaciones sobre Apuntadores

Comparación de apuntadores

Sólo se podrán comparar apuntadores del mismo tipo.int t[10];int *p;for (p=t; p < t+10;p++) *p = 1;

Page 14: Programación en c (iii parte)

Operaciones sobre Apuntadores

Resta de apuntadores: la diferencia proporciona el número de elementos del tipo en cuestión, situados entre las dos direcciones.

int strlen(char *s){ char *p=s; while (*p != ‘\0’) p++; return p - s; }

Page 15: Programación en c (iii parte)

Operaciones sobre Apuntadores

Asignaciones y el apuntador NULL

int *p, *t, a[10];p = a:t = p;p = NULL;

Page 16: Programación en c (iii parte)

Apuntadores y Arreglos

El nombre de un arreglo , para el compilador C , es un APUNTADOR inicializado con la dirección del primer elemento del arreglo.

float var,conjunto[]={8.0,7.0,6.0,5.0);float *pf; pf = conjunto; /* equivale a hacer pf = &conjunto[0]*/ var1 = *pf; *pf = 25.1;

Page 17: Programación en c (iii parte)

Apuntadores y Arreglos

Recuperar un elemento de un arreglo usando apuntadores:

int *pa, a[10];

pa = a; /* equivale a pa = &a[0]*/

también ....

x = *(pa + i) equivale a x = a[i]

Page 18: Programación en c (iii parte)

Apuntadores y Arreglos

Un arreglo como apuntador:

a[i] puede escribirse como *(a + i). i.e. &a[i] = a + i.

El apuntador lo podemos tratar como arreglo:

pa[i] en lugar de *(pa + i).

Page 19: Programación en c (iii parte)

Apuntadores y Arreglos

Sin embargo los apuntadores y arreglos son diferentes:

int a[10], *pa;

◦Un apuntador es una variable. Nosotros podemos hacer:

pa = a y pa++

◦Un arreglo no es una variable. Las instrucciones

a = pa y a++ SON ILEGALES.

Page 20: Programación en c (iii parte)

Apuntadores y Arreglos

ASIGNACIONES ERRONEAS

int conjunto[3], lista[] = {5,6,7};

int *apuntador ;

apuntador = lista ; /* correcto */

conjunto = apuntador; /* ERROR */

lista = conjunto ; /* ERROR */

apuntador = &conjunto /* ERROR no se puede aplicar el operador “&” a una constante */

Page 21: Programación en c (iii parte)

Arreglos de Apuntadores

char *flecha; define un apuntador a un caracter.

char *car[5]; define un arreglo de 5 apuntadores a caracteres.

Los arreglos de apuntadores pueden inicializarse de la misma forma que un arreglo común:

char *months = {``no month'', ``jan'', ``feb”, ...};

Page 22: Programación en c (iii parte)

Apuntadores a Estructuras

Los apuntadores pueden servir para el manejo de estructuras, y su alojamiento dinámico.

Tienen además la propiedad de poder direccionar a los miembros de las mismas utilizando el operador (->) .

Page 23: Programación en c (iii parte)

struct conjunto {

int a ;double b ;char c[5] ;} stconj ;stconj.a = 10 ;stconj.b = 1.15 ;stconj.c[0] = 'A' ;

Con apuntadores:

struct conjunto *pconj ;

pconj = (struct conjunto *)malloc( sizeof( struct conjunto )) ;

pconj->a = 10 ;

pconj->b = 1.15 ;

pconj->c[0] = 'A' ;

Page 24: Programación en c (iii parte)

APUNTADORES COMO PARAMETROS DE FUNCIONES

Una estructura, se puede pasar a una función como argumento:struct conjunto {int a ;double b ;char c[5] ;} datos ; //declaración de la variable datos

void funcion( struct conjunto); //prototipo

. . .

funcion(datos); // llamada

Page 25: Programación en c (iii parte)

APUNTADORES COMO PARAMETROS DE FUNCIONES

Otra forma equivalente es utilizar un apuntador a la estructura

struct conjunto {

int a ;

double b ;

char c[5] ;

} a; // declaración de la variable “a”

void una_funcion( struct conjunto *); //prototipo

una_funcion(&a); //llamada

Page 26: Programación en c (iii parte)

APUNTADORES COMO RESULTADO DE UNA FUNCION

Podemos declarar funciones que devuelven apuntadores a un tipo de

datos:

char *funcion1(char * var1 ) ;

double *funcion2(int i, double j, char *k ) ;

struct item *funcion3( struct stock *puntst ) ;

Page 27: Programación en c (iii parte)

APUNTADORES COMO RESULTADO DE UNA FUNCION

El retorno de las mismas puede inicializar apuntadores del mismo tipo al que se devuelve o de un tipo distinto.

void *malloc(int tamaño) ;

p = (double *)malloc( 64 ) ;

Page 28: Programación en c (iii parte)

Apuntadores y Funciones

Cuando en el lenguaje C se pasan argumentos a las funciones, el pasaje de parámetros es por valor.

Los apuntadores se utilizan para realizar el pasaje de parámetros por referencia.

int a,b;

swap(a, b) /* NO FUNCIONA */.

Page 29: Programación en c (iii parte)

Apuntadores y Funciones

Es necesario pasar como parámetro la dirección de las variables para que éstas puedan ser modificadas por la función

swap(&a, &b) /* Llamada */

. . .

void swap(int *px, int *py){

int temp; temp = *px /* lo apuntado por p*/ *px = *py; *py = temp;

}

Page 30: Programación en c (iii parte)

APUNTADORES COMO PARAMETROS DE FUNCIONES

void una_funcion( struct conjunto *p);

…..

struct conjunto {

int a ;

double b ;

char c[5] ;

} a;

una_funcion(&a);

Prototipo

Declaración de la variable a

Llamada con la dirección de la variable

Page 31: Programación en c (iii parte)

Apuntadores y Funciones

Cuando un arreglo se pasa a una función como parámetro lo que realmente se está pasando esla ubicación en memoria de su primer elemento:strlen(s) equivale strlen(&s[0])

La declaración de la función es:

int strlen(char s[]) ;

Y una declaración equivalente es :

int strlen(char *s);

porque char s[] es similar a char *s. llamada

Page 32: Programación en c (iii parte)

Apuntadores y Funciones

strlen() es una función de la librería estándar que retorna la longitud de un string:

int strlen(char *s) { char *p = s; while (*p != `\0’);

p++; return p-s; }

llamada: char nombre[10]; strlen(nombre);

Page 33: Programación en c (iii parte)

Arreglos Multidimensionales y Apuntadores

Un arreglo de dos dimensiones es realmente un arreglo de una dimensión donde cada elemento es en sí mismo un arreglo. De ahí la notación: a[n][m].

Los elementos del arreglo se almacenan por filas.

Cuando se pasa un arreglo de dos dimensiones a una función, se pasa el número de columnas, -- el número de filas es irrelevante.

Page 34: Programación en c (iii parte)

Arreglos Multidimensionales y Apuntadores

Considere la siguiente matriz:

int a[5][35]

Para pasarla como argumento a una función, ésta se declara como:

f(int a[5][35]) {.....}

f(int a[][35]) {.....}

o incluso:

f(int (*a)[35]) {.....}

Page 35: Programación en c (iii parte)

Arreglos Multidimensionales y Apuntadores

int (*a)[35]; declara un apuntador a un arreglo de 35 enteros.

int *a[35]; declara un arreglo de 35 apuntadores a enteros.

Page 36: Programación en c (iii parte)

Arreglos Multidimensionales y Apuntadores

char *name[10]; char Aname[10][20]; Las instrucciones name[3][4] y Aname[3][4] son correctas en C.

Sin embargo

· Aname is un arreglo de 2D de 200 elementos.

· name tiene 10 elementos que son apuntadores no inicilizados.La ventaja es que los vectores de cada fila pueden ser de longitudes diferentes.

Page 37: Programación en c (iii parte)

Memoria Dinámica y estructuras de datos

dinámicas

09/04/2023

Page 38: Programación en c (iii parte)

Memoria Dinámica

La Funcción malloc se usa para obtener una porción contigua de memoria.

void *malloc(size_t number_of_bytes)

Retorna un apuntador del tipo void *.Si la memoria no se puede asignar retorna NULL

El tipo del argumento (size_t) esta definido en stdlib.h y es un tipo unsigned.

Page 39: Programación en c (iii parte)

Memoria Dinámica

char *cp;cp = malloc(100);

La instrucción anterior solicita al sistema operativo 100 bytes consecutivos y asigna la dirección de comienzo de este bloque a al apuntador cp.

Page 40: Programación en c (iii parte)

Memoria Dinámica

Es común usar la función sizeof() para especificar el número de bytes de un determinado tipo o estructura de datos.

int *ip;ip = (int *) malloc(100*sizeof(int));

Page 41: Programación en c (iii parte)

Memoria Dinámica

La función sizeof puede usarse para encontrar el tamaño de cualquier tipo de datos, variable o estructura.

int i;struct COORD {float x,y,z};typedef struct COORD PT; sizeof(int), sizeof(i),sizeof(struct COORD) ysizeof(PT) son todos válidos

Page 42: Programación en c (iii parte)

ip = (int *)malloc(100*sizeof(int));

Aquí haremos uso de la relación entre apuntadores y arreglos y trataremos la memoria reservada como un arreglo.

En lugar de

*ip = 100, podemos hacer:

ip[0] = 100;

o

for(i=0;i<100;++i) printf("%d",ip[i]);

Page 43: Programación en c (iii parte)

Memoria Dinámica

Cuando se termina de usar una porción de memoria se debe liberar usando la función free().

free() toma un apuntador como argumento y libera la memoria direccionada por el apuntador.

Page 44: Programación en c (iii parte)

Creación de Estructuras de datos dinámicas

Queremos almacenar 3 enteros, en una estructura de datos dinámica (lista).

Mostraremos cómo se hace de una forma sencilla:1. Primero crearemos tres variables de un

determinado tipo (struct list). Dichas variables contendrán el valor entero a almacenar y un apuntador inicializado en NULL.

2. Luego colocaremos el apuntador de una variable a “apuntar” a la siguiente.

09/04/2023

Page 45: Programación en c (iii parte)

Estructuras autoreferenciadas

struct list{int data;struct list *next;};struct list a, b, c;a.data = 1;b.data = 2;c.data = 3;a.next = b.next = c.next = NULL;

a

b

c

1

2

3

NULL

NULL

NULL

Paso 1Graficamente.

Page 46: Programación en c (iii parte)

Estructuras autoreferenciadas

a.next = &b;b.next = &c;

a b c

1 2 3 NULL

a.next -> data es 2a.next -> next -> data es 3

Paso 2

Page 47: Programación en c (iii parte)

Otro Ejemplo

Ahora, cada elemento de la lista lo crearemos dinámicamente según se necesite.

Utilizaremos typedef, para crear tipos de datos que permiten una programación más ellegante.

Esta vez, cada elemento de la lista almacenará un carácter y el apuntador al próximo elemento de la lista.

09/04/2023

Page 48: Programación en c (iii parte)

Estructuras autoreferenciadas

// Definición de tipos. Archivo list.h

#define NULL 0

typedef char DATA;struct linked_list{DATA d;struct linked_list *next;};typedef struct linked_list ELEMENT;typedef ELEMENT *LINK;

Page 49: Programación en c (iii parte)

Estructuras autoreferenciadas

El programa de la siguiente lámina recibe como parámetro un arreglo de caracteres y los coloca en una lista.

Las variables head y tail apuntan en todo momento a la cabeza y cola de la lista respectivamente. Al comienzo apuntan a NULL.

09/04/2023

Page 50: Programación en c (iii parte)

#include “list.h”LINK s_to_l (char s[]) {

LINK head = NULL, tail=NULL;int i;if (s[0] != ‘\0’) { head = (LINK) malloc(sizeof(ELEMENT));head -> d = s[0];tail = head;for (i = 1; s[i] != ‘\0’, ++i) { tail ->next = (LINK) malloc(sizeof(ELEMENT)); tail = tail->next; tail -> d = s[i];}tail ->next = NULL;return(head);

} }

Page 51: Programación en c (iii parte)

Se recibe como parámetro El string “AB”

Ahead

tail

?

#include “list.h”LINK s_to_l (char s[]) {

LINK head = NULL, tail=NULL;int i;if (s[0] != ‘\0’) { head = (LINK) malloc(sizeof(ELEMENT));head -> d = s[0];tail = head;for (i = 1; s[i] != ‘\0’, ++i) { tail ->next = (LINK) malloc(sizeof(ELEMENT)); tail = tail->next; tail -> d = s[i];}tail ->next = NULL;return(head);

} }

Page 52: Programación en c (iii parte)

Ahead

tail

?

head

tail

A B ?

LINK head = NULL, tail=NULL;int i;if (s[0] != ‘\0’) { head = (LINK) malloc(sizeof(ELEMENT));head -> d = s[0];tail = head;for (i = 1; s[i] != ‘\0’, ++i) { tail ->next = (LINK) malloc(sizeof(ELEMENT)); tail = tail->next; tail -> d = s[i];}tail ->next = NULL;return(head);

} }

Page 53: Programación en c (iii parte)

head

tail

A B NULL

LINK head = NULL, tail=NULL;int i;if (s[0] != ‘\0’) { head = (LINK) malloc(sizeof(ELEMENT));head -> d = s[0];tail = head;for (i = 1; s[i] != ‘\0’, ++i) { tail ->next = (LINK) malloc(sizeof(ELEMENT)); tail = tail->next; tail -> d = s[i];}tail ->next = NULL;return(head);

} }

Page 54: Programación en c (iii parte)

Argumentos del Main

Para poder tener acceso a los argumentos

de la línea de comandos el main se debe definir de la siguiente forma:

main(int argc, char **argv) · argc es el número total de argumentos

incluyendo el nombre de programa. · argv es un arreglo de strings. Cada posición del

arreglo contiene un argumento.

Page 55: Programación en c (iii parte)

Línea de Comandos

#include<stdio.h>

main (int argc, char **argv) {

/* programa que imprime los argumentos de la línea de comandos */

int i;

printf(``argc = %d\n'',argc);

for (i=0;i<argc;++i)

printf(``argv[%d]:%s\n'',i,argv[i]);

}

Page 56: Programación en c (iii parte)

Línea de Comandos

Si se invoca el programa (argum) con los siguientes argumentos:

argum f1 “f2” f3 4 stop!

La salida será:argc = 6argv[0] = argumargv[1] = f1argv[2] = f2argv[3] = f3argv[4] = 4argv[5] = stop!

Los caracteres “” se ignoran.

Page 57: Programación en c (iii parte)

Bibliografía

Brian Kernighan y Dennis Ritchie. El Lenguaje de Programación C. Prentice Hall.

http://www.its.strath.ac.uk/cources/c

09/04/2023 58