Biblioteca estándar de C: Algunas funciones y trucos

Anuncio
Biblioteca estándar de C: Algunas funciones y trucos
Lectura de Input
fscanf(FILE *stream, const char *format, ...) Caracterı́sticas: Retorna el número de ı́temes asignado (puede ser menor que el suplementado). Retorna
EOF si se leyó el fin de archivo. Ignora todo tipo de separadores (espacios en
blanco, fines de lı́nea, tabulaciones).
Recomendada para: leer números, palabras (una por una), hacer parseos simples.
Ejemplos de buen uso:
fscanf(f,"%s%d",str,&x); /* para leer un string seguido de un entero
sin importar que hay entremedio */
Uso no recomendable:
fscanf(f,"numero: %d",&x);/* para leer número seguido de la palabra
"numero:" (peligroso) */
Jorge Baier Aranda, PUC
1
Se permite que el string de formato tenga caracteres al comienzo. En este caso,
la función fscanf espera que éstos aparezcan al comienzo del input. Si no es
ası́, no leerá nada.
No recomendada para: En general no se recomienda usarla si importa leer
caracteres normalmente ignorados. En particular, no sirve para leer archivos lı́nea
por lı́nea y no sirve para hacer cualquier tipo de “parseo”.
Truco 1: Es posible obtener el número de caracteres que fscanf ha leı́do usando
el caracter de formato n. En el siguiente programa se usa dicho parámetro.
#include <stdio.h>
int main() {
char c;
int x,i,r,cant;
while (!feof(stdin)) {
r=fscanf(stdin,"%d%n",&x,&cant);
if (r) printf("%d\t%d\t%d\n",r,x,cant);
else break;
}
return 0;
Jorge Baier Aranda, PUC
2
}
Este es un ejemplo de ejecución:
34 54 67
1
34
1
54
1
67
45
1
45
2
3
3
3
Truco 2: Es posible descartar el almacenamiento un dato exitosamente convertido
con fscanf. Esto se hace anteponiendo un * al caracter de formato. Ejemplo:
fscanf(stdin,"%*s%d%n",&x); /* solo interesa leer el entero */
char *fgets(char *s, int size, FILE *stream) Caracterı́sticas: Lee
una lı́nea completa desde el archivo stream, almacena el resultado en el string
s. Lee a lo más size caracteres. Retorna s en caso de éxito y NULL en caso de
error.
Advertencia: fgets lee también el fin de lı́nea \n.
Jorge Baier Aranda, PUC
3
int fgetc(FILE *stream) Caracterı́sticas: Lee un caracter desde stream
como unsigned char convertido a int.
int ungetc(int c, FILE *stream) Caracterı́sticas: Devuelve un caracter
hacia stream. Sólo se garantiza que se pueda devolver un caracter. No se puede
devolver EOF. Retorna el caracter devuelto o EOF en caso de error.
int feof(FILE *stream) Caracterı́sticas: Retorna un valor no nulo si se ha
leı́do el fin de archivo desde stream.
Manejo de Strings
char *strstr(const char *haystack, const char *needle) Caracterı́sticas: Retorna un puntero al primer caracter de la primera ocurrencia del string
needle dentro del string heystack o NULL si no hay tal ocurrencia.
char *strpbrk(const char *s, const char *accept)
Jorge Baier Aranda, PUC
Caracterı́sticas:
4
Retorna un puntero al caracter en s que está presente en el string accept
o NULL si tal caracter no es encontrado.
char *strtok(char *s, const char *delim) Busca en s por tokens delimitados por caracteres en delim.
El primer llamado a strtok debe tener a s como primer argumento; los siguientes,
NULL. Cada llamado retorna un puntero al siguiente token o NULL cuando no se
encuentran más tokens.
Cuando un token termina con un delimitador, el caracter delimitador es sobreescrito con un \0. Esto significa que el string original es alterado.
Dato curioso: En el manual de unix de esta función aparece lo siguiente:
BUGS
Never use these functions. If you do, note that:
These functions modify their first argument.
These functions cannot be used on constant strings.
The identity of the delimiting character is lost.
Ejemplo de Uso: El siguiente programa encuentra los campos en un archivo del
estilo /etc/passwd de Unix. Tiene un serio problema con los campos vacı́os...
Jorge Baier Aranda, PUC
5
#include <stdio.h>
#include <string.h>
#define MAX 1024
#define SEP "-----------------------"
int main() {
FILE *fp;
char buf[MAX],datos[7][MAX];
char *ptr;
int i;
fp=fopen("passwd","r");
while (fgets(buf,MAX,fp)!=NULL) {
ptr=strtok(buf,":\n");
for(i=0;ptr;ptr=strtok(NULL,":\n"),i++)
strcpy(datos[i],ptr);
if (i<7) printf("No encontré todos los datos!\n");
printf("login: %s\npasswd: %s\nuser: %s\ngroup: %s\nname: %s\nhome: %s\nshell: %s\n%s\n",
datos[0],datos[1],datos[2],datos[3],
datos[4],datos[5],datos[6],SEP);
}
fclose(fp);
return 0;
}
Con el archivo:
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
Jorge Baier Aranda, PUC
6
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
pcap:x:77:77::/var/arpwatch:/sbin/nologin
tiene el siguiente comportamiento:
login: rpcuser
passwd: x
user: 29
group: 29
name: RPC Service User
home: /var/lib/nfs
shell: /sbin/nologin
----------------------login: nfsnobody
passwd: x
user: 65534
group: 65534
name: Anonymous NFS User
home: /var/lib/nfs
shell: /sbin/nologin
----------------------No encontré todos los datos!
login: pcap
passwd: x
user: 77
group: 77
name: /var/arpwatch
home: /sbin/nologin
-----------------------
Jorge Baier Aranda, PUC
7
STL: Standard Template Library
STL es uno de los elementos más interesantes de C++. Permite usar strings,
algoritmos pre-definidos y contenedores (vectores, colas, stacks, etc.) de manera
muy directa.
Manejo de Strings
STL provee la clase string para manejo de strings.
Muchas operaciones (como concatenación y reemplazo) tienen sus propios operadores.
Jorge Baier Aranda, PUC
8
El siguiente ejemplo muestra algunas de sus potencialidades.
#include <iostream>
#include <string>
using namespace std;
int main() {
string s1;
// inicializa un string vacı́o
string s2="hola";
// inicializa string en "hola";
string s3(6,’c’);
// string s3 = "cccccc";
s1 = s2 + " " + s3;
// s1 = "hola cccccc";
cout << ((s1==s2)? 1 : 0) << endl; // imprime "0", se puede usar >, < , >=, etc.
s1[0] = ’t’;
// s1 = "tola cccccc";
printf("%s\n",s1.c_str()); // compatibilidad con strings de C
s1.insert(0,s2);
// s1 = "holatola cccccc"
string::size_type i = s1.find("cc"); // i=9
i = s2.length();
// i = 4
s3=s2.substr(1,3);
// s3="ola"
s1.replace(s1.find("tola"),4,","); // s1 = "hola, cccccc"
return 0;
}
Jorge Baier Aranda, PUC
9
Contenedores en STL
Un contenedor objeto que permite almacenar otros objetos.
Existen contenedores basados en estructuras de datos conocidas.
Pueden almacenar distintos tipos de datos pues están definidos como templates.
Estos son los contenedores definidos en STL:
Cabecera
Contenedor
<vector>
<list>
<deque>
<queue>
<stack>
<map>
<set>
<bitset>
arreglo unidimensional de T
lista doblemente ligada de T
cola de doble extremo de T
cola de T
pila de T
arreglo asociativo de T
conjunto de T
arreglo de bits T
El contenedor priority_queue se declara en <queue>. Veremos el uso de
algunos de estos contenedores.
Jorge Baier Aranda, PUC
10
Vectores
Los vectores son muy similares a los arreglos. De hecho, se permite acceder a la
enésima posición a través de A[n].
Agregar elementos al final de un vector es muy eficiente (O(1)) pero eliminar o
agregar elementos en otra parte toma en general tiempo O(n), con n el número
de elementos en el vector.
Las siguientes están dentro de los métodos más útiles de la clase vector:
Método
Efecto/Retorno
begin()
end()
push_back(valor)
pop_back(variable)
insert(iterador,valor )
erase(iterador)
size()
empty()
[]
Retorna iterador apuntando al primer elemento
Retorna iterator apuntando después del último elemento
Agrega un elemento al final del vector
Destruye el elemento al final del vector
Inserta un nuevo elemento
Elimina un elemento (*)
Número de elementos
Verdadero si el vector está vacı́o
Acceso directo
Jorge Baier Aranda, PUC
11
El siguiente ejemplo muestra el uso de algunas funciones.
#include <iostream>
#include <vector>
#include <cstdlib>
using namespace std;
void muestra(vector<int> &v) {
for (vector<int>::iterator viter=v.begin(); viter!=v.end(); ++viter)
cout << *viter << " "; cout << endl;
}
int main() {
vector<int> v;
for (int i=0; i<5; i++) {
v.push_back(rand()/100000);
}
muestra(v);
sort(v.begin(), v.end() );
muestra(v);
v.erase(v.begin()+1);
v.insert(v.begin(),-1);
muestra(v);
return( EXIT_SUCCESS );
}
El siguiente es el resultado que produce:
18042 8469 16816 17146 19577
Jorge Baier Aranda, PUC
12
8469 16816 17146 18042 19577
-1 8469 17146 18042 19577
Jorge Baier Aranda, PUC
13
Lectura de Input en C++
En C++, la lectura de input se debiera realizar usando las funciones C++ para
lectura de archivo.
El operador >> aplicado sobre un objeto del tipo ifstream tiene un efecto similar
al de scanf (ignora separadores). Ejemplo:
#include <iostream>
#include <string>
...
string s;
cin >> s;
Para leer lı́neas completas, se usa el método getline. Ejemplo:
string s;
getline(cin,s,’\n’);
El siguiente programa lee lı́neas que contienen un string y luego un entero.
Jorge Baier Aranda, PUC
14
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
string s,s2;
int n;
ifstream f;
istream *p;
// comentar siguientes lı́neas para leer de entrada estándar
f.open("hola.txt");
if (f.fail()) {
perror("no se puede abrir el archivo");
exit(1);
}
p = &f;
//p = &cin;
// descomentar para leer de la entrada estándar
while (1) {
*p >> s; *p >> n;
if (p->fail()) break;
cout <<"!"<< s << "!" << n << "!" << endl;
}
f.close();
return 0;
}
Jorge Baier Aranda, PUC
15
Colas con acceso doble (deque)
Son similares a los vectores, pero:
• Agregar/eliminar al principio y al final es O(1). El método push_front() y
pop_front() permite operar al principio de la lista.
Listas (list)
Son similares a los deques, pero:
• No es posible tener acceso directo al enésimo elemento.
• Eliminar un elemento que no está al final ni al principio es O(1).
Colas (queue)
Son similares a las listas, pero:
• Sólo es posible agregar un elemento al final de la cola.
• Sólo es posible extraer un elemento del principio de la cola.
Jorge Baier Aranda, PUC
16
Colas de Prioridades (priority queue)
Son similares a las colas. Sirven cuando es necesario tener un contenedor donde
sólo extraer importa el elemento más grande.
La operación de eliminación e inserción es O(log n). (Se usan los métodos push()
y pop() respectivamente.)
Conocer el elemento mayor es O(1). (Se usa el método top())
El siguiente es un ejemplo:
// C++ STL Headers
#include <iostream>
#include <queue>
#include <string>
using namespace std;
class Proceso {
private:
unsigned int prioridad;
string nombre;
public:
friend ostream& operator << ( ostream& os, const Proceso &task );
friend bool operator < (const Proceso &p1, const Proceso &p2);
Jorge Baier Aranda, PUC
17
Proceso(const char *nom = "", unsigned int prio = 0 ){
nombre = nom;
prioridad = prio;
}
};
// Compara dos procesos
bool operator < (const Proceso &p1, const Proceso &p2) {
return p1.prioridad < p2.prioridad;
}
// Muestra un proceso en pantalla
ostream & operator<<( ostream &os, const Proceso &task )
{
os << "Proceso: " << task.nombre << "\tPrioridad: " << task.prioridad;
return os;
}
int main( int argc, char *argv[] )
{
int i;
priority_queue<Proceso> task_queue;
Proceso tasks[] = {
Proceso("JORGE"),
Proceso("INIT",6), Proceso("Swapper",16),
Proceso("LPD",8) , Proceso("HTTPD",8) };
for ( i = 0; i < sizeof(tasks)/sizeof(tasks[0]) ; i++ )
task_queue.push( tasks[i] );
while ( !task_queue.empty() ) {
cout << task_queue.top() << endl;
task_queue.pop();
}
Jorge Baier Aranda, PUC
18
cout << endl;
return( EXIT_SUCCESS );
}
Y produce el siguiente output
Proceso:
Proceso:
Proceso:
Proceso:
Proceso:
Swapper
Prioridad: 16
LPD
Prioridad: 8
HTTPD Prioridad: 8
INIT
Prioridad: 6
JORGE Prioridad: 0
Jorge Baier Aranda, PUC
19
Algoritmos
La STL provee una gran cantidad de algoritmos predefinidos cuando se incluye la
cabecera <numeric>.
Destacan los siguientes (generalmente usados en deques, listas y vectores):
Función
Descripción
find()
replace_if()
reverse()
random_shuffle()
sort()
stable_sort()
binary_search()
generate()
unique()
lower_bound()
upper_bound()
merge()
Encuentra un elemento en una secuencia
Reemplaza los elementos que satisfacen una propiedad
Invierte el orden de los elementos propiedad
Reordena los elementos en forma aleatoria
Ordena los elementos
Ordena los elementos en forma estable
Busca un elemento en una secuencia ordenada
Reemplaza cada elemento con el resultado de una operación sobre éste.
Elimina elementos adyacentes que son iguales
Encuentra la cota inferior en una secuencia ordenada
Encuentra la cota superior en una secuencia ordenada
Mezcla dos secuencias ordenadas
Jorge Baier Aranda, PUC
20
Descargar