String - Departamento de Electrónica

Anuncio
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
Se describen las rutinas que manipulan strings, cuyos prototipos se encuentran en string.h
#include <string.h>
typedef unsigned size_t;
#define NULL 0
/* define tipo requerido por sizeof */
/* terminador nulo */
Definición de string.
La siguiente definición reserva espacio para un string como un arreglo de caracteres.
La definición de un string como arreglo de caracteres, debe incluir un espacio para el
carácter fin de string (el carácter NULL). Quizás es mejor definir el terminador de string
como null, para evitar confusiones con el valor de un puntero nulo.
char string[6]; /*crea string con espacio para 6 caracteres. Indice varía entre 0 y 5 */
string[5] = NULL;
string
\0
El nombre del string es un puntero constante que apunta al primer carácter del string. Por
ser constante no se le puede asignar nuevos valores o modificar.
La definición de un string como un puntero a carácter, puede ser inicializada asignándole
una constante de tipo string. La que se define como una secuencia de cero o más caracteres
entre comillas dobles; el compilador agrega el carácter ‘\0’ automáticamente al final.
Si dentro del string se desea emplear la comilla doble debe precedérsela por un \.
En caso de escribir, en el texto de un programa, un string de varias líneas, la secuencia de
un \ y el retorno de carro(que es invisible en la pantalla) no se consideran parte del string.
char * str1 = "abcdefghi"; /* tiene 10 caracteres, incluido el NULL que termina el string.*/
Un argumento de tipo puntero a carácter puede ser reemplazado en una lista de parámetros,
en la definición de una función por un arreglo de caracteres sin especificar el tamaño. En el
caso del ejemplo anterior: char str1[ ]. La elección entre estas alternativas suele realizarse
según sea el tratamiento que se realice dentro de la función; es decir, si las expresiones se
elaboran en base a punteros o si se emplea manipulación de arreglos.
Prof. Leopoldo Silva Bijit.
18-08-2003
15
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
Copia el string fuente en el string destino.
Se detiene la copia después de haber copiado el carácter nulo del fin del string.
Retorna la dirección del string destino.
char *strcpy(char * destino, register const char * fuente)
{ register char * cp= destino;
while(*cp++ = *fuente++) continue;
return destino;
}
destino
cp
fuente
El diagrama ilustra los punteros fuente y cp, después de haberse realizado la copia del
primer carácter. Se muestra el movimiento de copia y el de los punteros.
Cuando el contenido de *fuente es el carácter NULL, primero lo copia y la expresión
resultante de la asignación toma valor cero, que tiene valor falso para la condición,
terminando el lazo while.
La instrucción continue puede aparecer en el bloque de acciones de un while, do o for. Su
ejecución lleva a reevaluar la condición de continuación del bloque de repetición más
interno (en caso de bloques anidados). En el caso de la función anterior podría haberse
omitido la instrucción continue; ya que un punto y coma se considera una acción nula.
El operador de postincremento opera sobre un left value(que recuerda un valor que puede
colocarse a la izquierda de una asignación). Un lvalue es un identificador o expresión que
está relacionado con un objeto que puede ser accesado y cambiado en la memoria.
El uso de estos operadores en expresiones produce un efecto lateral, en el sentido que se
efectúan dos acciones. Primero se usa el valor del objeto en la expresión y luego éste es
incrementado en uno.
El operador de indirección ( el *) y el operador ++ tienen la misma precedencia, entonces
se resuelve cuál operador recibe primero el operando mediante su asociatividad, que en el
caso de los operadores unarios es de derecha a izquierda. Es decir *fuente++ se interpreta
según: ( * (fuente++) ) . La expresión toma el valor del puntero fuente y lo indirecciona,
posteriormente incrementa en uno al puntero. En la expresión (* fuente) ++, mediante el
uso de paréntesis se cambia la asociatividad, la expresión toma el valor del objeto apuntado
por fuente, y luego incrementa en uno el valor del objeto, no del puntero.
Prof. Leopoldo Silva Bijit.
18-08-2003
16
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
Puede evitarse la acción doble relacionada con los operadores de pre y postincremento,
usando éstos en expresiones que sólo contengan dichos operadores. En el caso de la acción
de repetición: while(*cp++ = *fuente++) continue;
Puede codificarse: while( *cp = *fuente) {cp++, fuente++};
Sin embargo los programadores no suelen emplear esta forma. Adicionalmente no producen
igual resultado, ya que en la primera forma los punteros quedan apuntando una posición
más allá de los caracteres de fin de string; la segunda forma deja los punteros apuntando a
los terminadores de los strings. Ambas formas satisfacen los requerimientos de srtcpy.
La primera forma sólo tendría ventajas si el procesador tiene mecanismos de
direccionamientos autoincrementados, y si el compilador emplea dichos mecanismos al
compilar la primera forma.
Cuando en la lista de parámetros de una función aparece la palabra reservada const
precediendo a una variable de tipo puntero, el compilador advierte un error si la función
modifica la variable a la que el puntero apunta.
No se valida si el espacio a continuación de destino puede almacenar el string fuente sin
sobreescribir en el espacio asignado a otras variables.
Ejemplo:
#include <string.h>
#include <stdio.h>
char string[10]; /*crea string con espacio para 10 caracteres */
char * str1 = "abcdefghi"; /* tiene 10 caracteres, incluido el NULL que termina el string.*/
int main(void)
{ strcpy(string, str1); printf("%s\n", string);
return 0;
}
strncpy copia n caracteres desde el string fuente hacia el string destino. Si el string fuente
tiene menos de n caracteres rellena con nulos hasta completar la copia de n caracteres.
Si el string fuente tiene n o más caracteres el string destino no queda terminado en un nulo.
char *strncpy(register char * destino, register const char * fuente, register size_t n )
{ register char * cp = destino;
while( n ) { n--; if(!(*cp++ = *fuente++)) break; }
while( n--) *cp++ = 0;
return destino;
}
Prof. Leopoldo Silva Bijit.
18-08-2003
17
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
La sentencia break termina el bloque de repetición (más interno, si existen estructuras
repetitivas anidadas), y pasa a ejecutar la instrucción siguiente al bloque.
Si se copia el fin del string fuente se activa el break y comienza el segundo while que
produce el relleno de nulos. Si se copian n caracteres en el primer while, el segundo no se
efectúa, ya que se entra a éste con un valor cero de n.
Concatena una copia del string fuente luego del último carácter del string destino.
El largo del string resultante es la suma: strlen(dest) + strlen(src).
Retorna un puntero al string destino, que ahora contiene la concatenación.
char *strcat(register char * destino, register const char * fuente)
{ register char *cp= destino;
while(*cp) cp++;
while(*cp++ = *fuente++) continue; /*
return destino;
}
El primer while deja el puntero cp apuntando al carácter de fin del string destino. Luego el
segundo while efectúa la copia, sobreescribiendo el NULL del string destino, con el primer
carácter del string fuente.
La función también concatena un string fuente nulo.
destino
Ejemplo:
#include <string.h>
#include <stdio.h>
char destino[25];
char *espacio = " ", *fin = "Final", *destino = "Inicio";
int main(void)
{ strcat(destino, espacio); strcat(destino, fin);
printf("%s\n", destino);
return 0;
}
cp
fuente
strncat concatena al final del string destino a lo más n caracteres del string fuente.
char *strncat(register char * destino, register const char * fuente, register size_t n )
{ register char * cp = destino;
while(*cp) cp++; /*apunta al final del string destino */
while( n && (*cp++ = *fuente++) ) n--;
if( n == 0) *cp = 0;
return destino;
}
Prof. Leopoldo Silva Bijit.
18-08-2003
18
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
Si fuente tiene menos de n caracteres, el segundo operador del and copia el fin de string. Si
el string fuente tiene n o más caracteres, es el primer operando del and es el que da por
terminado el segundo while; saliendo de éste con un valor cero de n. Es para este último
caso que está el if final que escribe el terminador del string destino.
El máximo largo del string destino resultante es strlen(destino al inicio) + n.
Agrega una porción del string fuente a continuación del string destino.
Largo de un string.
Retorna el número de caracteres del string s. No cuenta el carácter de terminación.
size_t strlen(const char * s)
{ register const char * cp= s;
while(*cp++) continue;
return (cp-1) - s;
}
El while termina cuando *cp tiene valor cero. Pero debido al operador de postincremento,
al salir del while, cp queda apuntado una posición más allá de la posición que ocupa el
NULL. Entonces cp-1, apunta al NULL. Y la resta de punteros, produce un entero como
resultado; éste da el número de caracteres del string. Si a s se le suman 5, se tiene el valor
del puntero que apunta al terminador del string, en el caso del ejemplo que se ilustra a
continuación; entonces (cp-1) – s resulta 5 en este caso.
s
\0
cp
Compara dos strings.
La comparación comienza con el primer carácter de cada string y continua con los
caracteres subsecuentes hasta que los caracteres correspondientes difieren o hasta que se
llegue al final de uno de los strings.
int strcmp(register const char * s1, register const char * s2)
{ register signed char r;
while( !( r = *s1 - *s2++) && *s1++) continue;
return r;
}
Prof. Leopoldo Silva Bijit.
18-08-2003
19
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
Retorna un valor entero:
Menor que cero si
s1 < s2
Igual a cero si
s1 == s2
Mayor que cero si
s1 > s2
Si los caracteres *s1 y *s2 son iguales, r es cero; y el valor lógico del primer operando del
and es verdadero. Si son diferentes, termina el lazo de repetición. Si el valor de *s2 es
mayor que el valor de *s1, r será negativo; implicando que el string s2 es "mayor" que el
string s1. Si *s2 es el carácter NULL, r será positivo si *s1 no es cero, terminando el while;
implicando que s1 > s2. Si *s1 es el carácter NULL, r será negativo si *s2 no es cero,
terminando el while; implicando que s1 < s2.
Strncmp compara hasta n caracteres de los strings s1 y s2.
La comparación comienza con el primer carácter de cada string y continua con los
caracteres siguientes hasta que éstos difieran o hasta que se hayan revisado n.
int strncmp(register const char * s1, register const char * s2, size_t n)
{
while( n--) { if(*s1 == 0 || *s1 != *s2) return (*s1 - *s2); s1++; s2++; }
return 0;
}
Para los primeros n caracteres, si los caracteres difieren o se llegó al fin del string s1 se
retorna la resta del valor entero asociado a los caracteres.
Si s2 es más corto que s1, los caracteres difieren ya que *s2 es cero, y el retorno será
positivo; indicando s1 > s2.
Strstr encuentra la primera ocurrencia de un substring s2 en un string s1.
Si encuentra s2 en s1, retorna un puntero al carácter de s1 en que se inicia el substring que
es igual a s2; si no lo encuentra retorna un puntero nulo.
char *strstr(register const char * s1, register const char * s2)
{
while(s1 && *s1)
{ if(strncmp(s1, s2, strlen(s2)) == 0) return (char *)s1;
s1 =strchr(s1+1, *s2);
}
return (char *) 0;
}
La condición del if es verdadera si s2 está contenido en s1, con retorno exitoso. Si no lo
encuentra busca el primer carácter de s2(mediante strchr) a partir del siguiente carácter de
s1; si lo encuentra avanza s1 hasta esa coincidencia; si no lo encuentra s1 será un puntero
Prof. Leopoldo Silva Bijit.
18-08-2003
20
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
nulo, dando término al while(ya que el primer operando del and será falso). También
termina el while si s1 es un string nulo.
Busca la primera ocurrencia de un carácter c en el string s.
Si lo encuentra retorna un puntero al carácter c; en caso contrario, si c no está presente en s,
retorna un puntero nulo.
char *strchr(register const char * s, int c)
{ while( *s ) { if( *s == (char) c ) return (char *) s; s++;}
return (char *) 0;
}
El tipo char es tratado como entero con signo de 8 bits(-128 a +127) y es promovido
automáticamente a tipo entero. Sin embargo se emplea un conversión explícita de entero a
char mediante el molde o cast: (char) c
Debido a que el parámetro formal se trata como puntero a una constante string(para evitar
que la función modifique a s), se debe efectuar una conversión del tipo de puntero para el
retorno, se pasa a puntero a carácter (char *) el puntero a string constante: const char *.
La búsqueda de c en s es hacia delante (de izquierda a derecha, o de arriba hacia abajo).
Si s apunta al terminador del string, la expresión *s tiene valor cero, y la condición del
while es falsa, por lo tanto no busca el terminador del string.
El fin de string(terminador nulo) es parte del string. Si se desea que la búsqueda strchr(s, 0)
retorne un puntero al terminador nulo del string s, debe efectuarse la siguiente
modificación:
char *strchr(register const char * s, int c)
{ while( *s ) { if( *s == (char) c ) return (char *) s; s++;}
if( *s == (char) c ) return (char *) s;
return (char *) 0;
}
La rutina modificada puede buscar el terminador del string incluso en un string nulo.
strrchr encuentra la última ocurrencia del carácter c en el string s. Si encuentra c en s,
retorna un puntero al carácter encontrado; en caso contrario, un puntero nulo. La búsqueda
la efectúa en reversa.
cp
char *strrchr(register const char * s, int c)
{ register const char * cp = s;
while(*s) s++; /* s queda apuntado al terminador */
while(s != cp) { s--; if(*s == (char)c ) return (char *)s;}
return (char *) 0;
}
Prof. Leopoldo Silva Bijit.
18-08-2003
\0
s
21
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
El diagrama ilustra los punteros una vez terminado el primer while.
El terminador nulo es considerado parte del string. Si se desea buscar el terminador del
string debe modificarse la rutina anterior, o utilizar strchar.
strpbrk busca en el string s1 la primera ocurrencia de cualquier carácter presente en s2;
retorna un puntero al primer encontrado, en caso que ningún carácter de s2 esté presente en
s1 retorna un puntero nulo.
char *strpbrk(register const char * s1, register const char * s2)
{
while(*s1) { if(strchr(s2, *s1)) return (char *)s1; s1++; }
return (char *)0;
}
strcspn encuentra el segmento inicial del string s1 que no contiene caracteres que se
encuentren presentes en s2. Retorna el largo del segmento encontrado.
size_t strcspn(register const char * s1, register const char * s2)
{ register size_t i=0;
while(*s1 && !strchr(s2, *s1) ) {s1++; i++;}
return i;
}
A partir del primer carácter de s1 se revisa que éste no esté presente entre los caracteres que
forman s2.
strspn encuentra el segmento inicial del string s1 que solamente contiene caracteres que se
encuentren presentes en s2. Retorna el largo del segmento encontrado.
size_t strspn(register const char * s1, register const char * s2)
{ register size_t i = 0;
while(*s1 && strchr(s2, *s1) ) { s1++; i++;}
return i;
}
Se mantiene realizando el bloque mientras encuentre los caracteres de s1 en s2 y no sea fin
de string s1.
Strtok busca el primer substring de s1 que está antes del string s2 que se considera un
separador.
Se considera que s1 es un string formado por una secuencia de cero o más símbolos(tokens)
separados por el string s2.
Prof. Leopoldo Silva Bijit.
18-08-2003
22
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
La función strtkn permite obtener todos los tokens mediante llamados subsiguientes
primero. Para esto el primer llamado debe retornar un puntero al primer token, y escribir
carácter NULL en el string s1, inmediatamente después del último carácter del token que
retorna.
Los siguientes llamados deben realizarse con un puntero nulo en el primer argumento.
separador s2 puede ser diferente para cada una de las siguientes invocaciones. Si no
encuentran símbolos la función debe retornar un puntero nulo.
al
un
se
El
se
Como es una rutina que puede llamarse varias veces, su diseño debe incluir una variable
estática que permanezca entre llamados. Ya que los argumentos y variables locales sólo
existen mientras la función esté activa, debido a que se mantienen en un frame en el stack.
s1
t1
s2
t2
s2
t2
s2
sp
El primer llamado a strtrk, debe retornar s1, colocando un nulo en el primer carácter de s2,
y fijar la posición de la estática sp inmediatamente después del terminador recién insertado.
Los llamados subsiguientes llevan un NULL en el primer argumento, correspondiente al
puntero al string s1; esto le indica a la función que debe emplear ahora sp para seguir
buscando tokens.
El primer if, si s1 es un puntero nulo, fija s1 en el valor guardado en la estática sp por la
invocación anterior. Si el primer llamado se efectúa sobre un string nulo, debe estar
inicializada la estática sp.
El segundo if, retorna un puntero nulo, si el llamado inicial es con un puntero nulo, o si se
agotó la búsqueda de símbolos en llamados subsiguientes (encuentra sp con valor nulo).
char *strtok(register char * s1, register const char * s2)
{ static char * sp = NULL;
if(!s1) s1 = sp;
if(!s1) return NULL;
s1 += strspn(s1, s2); /* salta separador */
if(!*s1) return sp = NULL;
sp = s1 + strcspn(s1, s2);
if(*sp) *sp++ = '\0'; else sp = NULL;
return s1; /* puntero al token encontrado */
}
Mediante la función strspn se saltan los caracteres pertenecientes al separador s2, y s1
queda apuntado al primer carácter siguiente al separador s2.
El tercer if, si se llegó al final del string, fija sp en puntero nulo, y retorna un puntero nulo.
No se efectúa la acción del tercer if, si quedan caracteres por escanear.
Prof. Leopoldo Silva Bijit.
18-08-2003
23
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
Mediante la función strcspn se fija sp una posición más allá del último carácter del
encontrado.
El cuarto if, fija sp en puntero nulo, si se agotó la búsqueda (se efectúa el else); en
contrario si quedan caracteres por escanear, coloca un carácter nulo para finalizar el
encontrado, y avanza sp una posición más adelante.
El tipo del argumento de s1 no puede ser un puntero constante, ya que se escribe
string.
token
caso,
token
en el
Si por ejemplo el string s1 tiene el valor "abc, dd,efg" y si el separador s2 es el string ",";
se encuentra, después del primer llamado el token: abc. Luego del segundo(con primer
argumento NULL) el token: dd. Finalmente el símbolo: efg.
strdup crea un duplicado del string s, obteniendo el espacio con un llamado a malloc.
El espacio requerido es de (strlen(s) + 1) bytes, para incluir el terminador, el que es
insertado por strcpy.
Si malloc no puede asignar espacio retorna puntero nulo.
La función retorna un puntero al duplicado; en caso que falle malloc retorna un puntero
nulo. El programador es responsable de liberar el espacio ocupado cuando ya no sea
necesario, empleando la función free.
char *strdup(register const char * s)
{ register char * cp;
if(cp = (char *) malloc(strlen(s)+1)) strcpy(cp, s);
return cp;
}
Con las siguientes definiciones:
char *duplicado;
char *string = "1234";
Un ejemplo de uso es: duplicado = strdup(string);
Y para liberar el espacio: free(duplicado);
El prototipo de malloc es: void *malloc(size_t size);
Malloc retorna un puntero de tipo void o un puntero genérico. Se emplean cuando el
compilador no puede determinar el tamaño del objeto al cual el puntero apunta. Por esta
razón los punteros de tipo void deben ser desreferenciados mediante casting explícito.
El siguiente ejemplo muestra que a un puntero tipo void se le puede asignar la dirección de
un entero o un real. Pero al indireccionar debe convertirse el tipo void al del objeto que
éste apunta.
int x;
Prof. Leopoldo Silva Bijit.
18-08-2003
24
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
float r;
void *p;
p = &x; * (int *) p = 2;
p = &r; *(float *)p = 1.1;
El conjunto de funciones cuyos prototipos se encuentran en string.h también incluye un
grupo de funciones que manipulan bloques de memoria.
Los bloques son referenciados por punteros de tipo void, en la lista de argumentos. Luego
en las funciones se definen como variables locales punteros a caracteres, que son iniciados
con los valores de los punteros genéricos amoldados a punteros a caracter.
memcpy Copia un bloque de n bytes desde la dirección fuente hacia la dirección destino.
void *memcpy(void * destino, const void * fuente, register size_t n)
{ register char *d = (char *)destino; register const char *s= (char *)fuente;
while(n--) *d++ = *s++;
return destino;
}
Si fuente y destino se traslapan la conducta de memcpy es indefinida. Ya que no se puede
sobreescribir el bloque fuente, que se trata como puntero genérico constante. Dentro de la
función se emplean punteros locales a caracteres.
Copia no más de n bytes desde el bloque apuntado por fuente hacie el bloque apuntado por
destino, deteniéndose cuando copia el carácter c.
Retorna un puntero al bloque destino, apuntando al byte siguiente donde se copió c.
Retorna NULL si no encuentra a c en los primeros n bytes del bloque fuente.
void *memccpy (void *destino, const void *fuente, int c, size_t n)
{
register const char *s = (char *)fuente;
register char *d = (char *)destino;
register const char x = c;
register size_t i = n;
while (i-- > 0) if ((*d++ = *s++) == x) return d;
return NULL;
}
Se emplean locales de tipo registro para acelerar la copia. Nótese que los punteros de tipo
void de los argumentos son los valores iniciales de los registros con punteros a caracteres.
Prof. Leopoldo Silva Bijit.
18-08-2003
25
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
Con memmove, si los bloques apuntados por fuente y destino se traslapan, los bytes
ubicados en la zona de traslapo se copian correctamente.
void *memmove(void * destino, void * fuente, register size_t n)
{ register char *d= (char *)destino; register char *s = (char *)fuente;
if(s < d && s+n >=d) { s += n; d += n; do *--d = *--s; while(--n); }
else if(n) do *d++ = *s++; while(--n);
return destino;
}
La condición de traslapo del bloque s sobre el bloque d, se ilustra en el diagrama de más a
la derecha. En este caso se efectúa la copia en reversa. Se sobreescriben los últimos
elementos del bloque apuntado por s; es decir los que primero fueron copiados.
La negación lógica de la condición de traslapo, por De Morgan, es: (s>=d || s+n<d )
Los dos casos del or se ilustran en las dos figuras de más a la izquierda. En el caso que
ilustra la figura central, no hay traslapo.
En el caso s>=d, si d+n>=s, se produce traslapo y se sobreescriben las primeras posiciones
del bloque s, las que primero fueron copiadas (cuando se ejecuta el else, avanzado los
punteros hacia direcciones cada vez mayores).
d
s < d && s+n >= d
s + n <d
s>=d
s
s
n
s
d
n
d
Debido a que el bloque fuente puede ser sobrescrito, no puede ser un puntero vacío
constante.
Los punteros a carácter s y d, son iniciados con los valores amoldados (cast) a punteros a
carácter de fuente y destino.
Prof. Leopoldo Silva Bijit.
18-08-2003
26
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
memcmp compara los primeros n bytes de los bloques s1 y s2, como unsigned chars.
int memcmp(const void *s1, const void *s2, size_t n)
{ int i;
register const unsigned char *a1, *a2;
a1 = (unsigned char *)s1; a2 = (unsigned char *)s2;
while(n--) if( i = (int)(*a1++ - *a2++) ) return i;
return 0;
}
Valor de retorno menor que cero si s1 < s2
Valor de retorno igual a cero si
s1 == s2
Valor de retorno mayor que cero si s1 > s2
Rellena n bytes del bloque s con el byte c. Retorna puntero genérico al bloque.
void *memset(void * s, int c, register size_t n)
{ register char * p = (char *)s;
while(n--) *p++ = (char) c;
return s;
}
Efectuar movimientos de bloques orientados al carácter es ineficiente. Por esta razón las
funciones de movimiento tratan de mover palabras.
Primero se mueven los bytes parciales de una palabra, luego se pueden mover palabras
alineadas; para finalmente, copiar los bytes presentes en la última palabra.
Estas funciones, implementadas en base a macros para mejorar la velocidad, son
dependientes del procesador. Se requiere conocer el ancho de la palabra y el ordenamiento
de los bytes dentro de la palabra(little o big endian).
El siguiente ejemplo introduce en un entero de 32 bits, el carácter '4' en el byte más
significativo, luego el '3', después el '2', y el carácter '1' en el byte menos significativo.
Luego convierte la dirección de i en un puntero a carácter, e imprime el string de largo 4.
En el string el byte con la menor dirección queda más a la izquierda, y el byte con dirección
mayor queda a la derecha.
unsigned long int i;
if (sizeof (i) == 4)
{
i = (((((('4' << 8) + '3') << 8) + '2') << 8) + '1');
printf ("Orden de los Bytes = %.4s\n", (char *) &i);
} else printf (" \nNo es una máquina de 32 bits");
Prof. Leopoldo Silva Bijit.
18-08-2003
27
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
Los strings asociados reflejan el ordenamiento de los bytes dentro de la palabra. Suelen
denominarse:
LITTLE ENDIAN
"1234"
BIG ENDIAN
"4321"
PDP ENDIAN
"3412"
rettype
memmove (a1, a2, len)
a1const void *a1;
a2const void *a2;
size_t len;
{
unsigned long int dstp = (long int) dest;
unsigned long int srcp = (long int) src;
/* This test makes the forward copying code be used whenever possible.
Reduces the working set. */
if (dstp - srcp >= len)
/* *Unsigned* compare! */
{
/* Copy from the beginning to the end. */
/* If there not too few bytes to copy, use word copy. */
if (len >= OP_T_THRES)
{
/* Copy just a few bytes to make DSTP aligned. */
len -= (-dstp) % OPSIZ;
BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
/* Copy whole pages from SRCP to DSTP by virtual address
manipulation, as much as possible. */
PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
/* Copy from SRCP to DSTP taking advantage of the known
alignment of DSTP. Number of bytes remaining is put
in the third argument, i.e. in LEN. This number may
vary from machine to machine. */
WORD_COPY_FWD (dstp, srcp, len, len);
/* Fall out and copy the tail. */
}
/* There are just a few bytes to copy. Use byte memory operations. */
Prof. Leopoldo Silva Bijit.
18-08-2003
28
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Programación Avanzada en C
BYTE_COPY_FWD (dstp, srcp, len);
}
else
{
/* Copy from the end to the beginning. */
srcp += len;
dstp += len;
/* If there not too few bytes to copy, use word copy. */
if (len >= OP_T_THRES)
{
/* Copy just a few bytes to make DSTP aligned. */
len -= dstp % OPSIZ;
BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);
/* Copy from SRCP to DSTP taking advantage of the known
alignment of DSTP. Number of bytes remaining is put
in the third argument, i.e. in LEN. This number may
vary from machine to machine. */
WORD_COPY_BWD (dstp, srcp, len, len);
/* Fall out and copy the tail. */
}
/* There are just a few bytes to copy. Use byte memory operations. */
BYTE_COPY_BWD (dstp, srcp, len);
}
RETURN (dest);
}
Prof. Leopoldo Silva Bijit.
18-08-2003
29
Descargar