5 Strings
5 Strings
23 de agosto de 2022
1. Introducción
En el contexto de un lenguaje de programación, un string es una cadena de caracteres usada para
representar texto. Fueron usados desde el comienzo de la cursada, por ejemplo, en el programa de Hola
mundo
Sin embargo, todos los strings que tratamos hasta ahora fueron siempre literales, es decir, siempre hardco-
deados en los fuentes del programa y nunca asignados a una variable de ningún tipo. El mismo programa
podrı́a ser reescrito de la siguiente manera:
1.1. Implementación en C
Se vio en la sección anterior que puede asignarse un string a un char * . Esto es debido a que, en C,
la representación interna de los strings en memoria está expuesta al programador (cosa que no es ası́ en
todos los lenguajes).
En C, los strings son simples arreglos de caracteres ( char s), por esto es que se usa un char * para
guardarlos: es un puntero a la primer posición de dicho vector.
De tal manera, ambos strings serı́an equivalentes:
1 char * cadena_salida = " Hello , world ! " ;
1 char * cadena_salida = { ’H ’ , ’e ’ , ’l ’ , ’l ’ , ’o ’ , ’ , ’ , ’ ’ , ’w ’ , ’o ’ , ’r ’ , ’l ’ , ’d ’ , ’! ’ , ’ \0 ’ };
Una pregunta no muy evidente que puede surgir de esto es ¿Cómo sabe, por ejemplo, printf dónde
termina el string? Es decir, debe haber una forma de distinguir, por ejemplo, entre los strings 'Hello' y
'Hello, World!' .
C usa los llamados null-terminated strings, designando al valor 0 ( 0xb00000000 en binario, '\0' en la
tabla ASCII) como el fin de string.
1
Dr. Mariano Méndez, Juan Pablo Capurro 75.40 Algoritmos y Programación I Curso 4
Ejercicio 1
Escribir un programa que muestre un string por pantalla, caracter a caracter, es decir, sin hacer uso de
puts , printf con modificador %s o similares.
Análisis: como los strings son un vector de caracteres con un caracter especial que marca su finalización,
lo lógico es iterar sobre el vector, con un ı́ndice, y dejar de iterar al llegar a ese caracter especial.
Hint: La función putchar , de stdio.h , cumple las necesidades de entrada/salida de este programa.
1. ¿Cuál es el tipo de iteración que corresponderı́a implementar: definida o indefinida? ¿Bucle for o
while ? ¿Por qué?
Ejercicio 2
Escribir una función que devuelva el largo de un string pasado por parámetro.
Hint: Al igual que en el ejercicio anterior, se deberá iterar sobre todo el string, pero en vez de mostrar
cada uno de sus caracteres, contarlos.
¿Por qué?
3. Proveer datos de ejemplo y resultados con los que probar la función. En la implementación, puede
usarse la función assert() , de assert.h
4. ¿Cuál es el tipo de iteración que corresponderı́a implementar: definida o indefinida? ¿Bucle for o
while ? ¿Por qué?
5. ¿Qué pasarı́a si se pasa un string sin el marcador de finalización?
Solución del ejercicio ??
1. La función deberı́a devolver un size t , por ser el tipo de dato que usa la librerı́a estándar de C
para representar tamaños.
Strings 2
Dr. Mariano Méndez, Juan Pablo Capurro 75.40 Algoritmos y Programación I Curso 4
Sin embargo, cualquier tipo de dato entero que pueda almacenar el largo de un string serı́a suficiente.
Un char , por ejemplo, no serı́a suficiente.
2. Corresponde que el largo evalúe a 4 , ya que hay cuatro caracteres hasta el señalizador de fin de
string. El 15 se corresponde con la cantidad de char s reservados en memoria para el string.
3. Datos de ejemplo proveı́dos en la implementación.
4. Corresponderı́a usar una iteración indefinida, con un bucle while , porque al comenzar a iterar no
se sabe cuántas iteraciones se realizarán.
5. Si se omitiera el marcador de fin de string, el programa no tendrı́a forma de enterarse dónde termina
el string, por lo que seguirı́a leyendo hasta intentar leer memoria inválida y terminarı́a por segfault.
Implementación:
1
2 # include < stdio .h >
3 # include < assert .h >
4
5 const char * string_vacio = "";
6 const char * string_largo_10 = " comandante " ;
7 const char string_definido_raro [15] = { ’r ’ , ’4 ’ , ’r ’ , ’0 ’ , ’ \0 ’ };
8
9 size_t largo_string ( const char * string ) {
10 size_t largo = 0 , i = 0;
11 while ( string [ i ] != ’ \0 ’) {
12 i ++;
13 largo ++;
14 }
15 return largo ;
16 }
17
18 int main () {
19 assert ( largo_string ( string_vacio ) == 0) ;
20 assert ( largo_string ( string_largo_10 ) == 10) ;
21 assert ( largo_string ( string_definido_raro ) == 4) ;
22 return 0;
23 }
2.1. Definiciones
2.1.1. size t strlen(const char* str)
2.1.2. int strcmp(const char* str left, const char* str right)
Analiza los dos strings pasados por parámetro para chequear su igualdad. Si son iguales, devuelve
0 . Si no son iguales, devuelve un número menor a 0 si str left es lexicográficamente[?] menor a
str right , y un número mayor a 0 en el caso de que str left sea mayor a str right
Copia el string src a dest . Asume que src está bien formado y que se alojó en dest memoria
suficiente. Copia el caracter finalizador.
Strings 3
Dr. Mariano Méndez, Juan Pablo Capurro 75.40 Algoritmos y Programación I Curso 4
2.2. Consideraciones
Todas las funciones anteriores asumen que el string está bien formado, es decir, que cuentan con el
caracter finalizador. En el caso de que esto no sea cierto, todas ellas tienen comportamiento indefinido
[?], probablemente terminando por segfault. Existen versiones más seguras de las últimas dos funciones,
int strncmp(const char* str1, const char* str2, size t n)
y char* strncpy(char* dest, const char* src, size t n) , que cumplen la misma función, pero
con un tope n , lo que evita acceder a memoria inválida en el caso de que algún string esté mal formado.
El parámetro n deberı́a ser seteado a la cantidad de memoria que se sabe que se reservó para ese string.
Ejercicio 3
1. Probar la implementación de la función realizada en el ejercicio ?? contra la implementación de la
biblioteca estándar strlen , haciendo uso assert .
2. De la misma forma, codificar y probar contra strcmp una función que devuelva la diferencia
lexicográfica entre dos strings. Esto es útil para tener bien claro qué es lo que devuelve strcmp .
Solución del ejercicio ??
Implementación:
1 # include < stdio .h >
2 # include < string .h >
3 # include < assert .h >
4
5 const char * string_vacio = "";
6 const char * string_largo_10 = " comandante " ;
7 const char string_definido_raro [15] = { ’r ’ , ’4 ’ , ’r ’ , ’0 ’ , ’ \0 ’ };
8
9 size_t largo_string ( const char * string ) {
10 size_t largo = 0 , i = 0;
11 while ( string [ i ] != ’ \0 ’) {
12 i ++;
13 largo ++;
14 }
15 return largo ;
16 }
17 int diy_strcmp ( const char * un_string , const char * otro_string ) {
18 size_t i =0;
19 while ( un_string [ i ] == otro_string [ i ]) {
20 if (! un_string [ i ]) {
21 return 0;
22 }
23 i ++;
24 }
25 return un_string [ i ] - otro_string [ i ];
26 }
27
28 int main () {
29 puts ( " Pruebas de largo_string () " ) ;
30 assert ( largo_string ( string_vacio ) == strlen ( string_vacio ) ) ;
31 assert ( largo_string ( string_largo_10 ) == strlen ( string_largo_10 ) ) ;
32 assert ( largo_string ( string_definido_raro ) == strlen ( string_definido_raro ) ) ;
33 puts ( " Pruebas de largo_string () : OK " ) ;
34 puts ( " Pruebas de diy_strcmp () " ) ;
35 assert ( strcmp ( string_largo_10 , " comandante " ) == diy_strcmp ( string_largo_10 , "
comandante " ) ) ;
36 assert ( strcmp ( string_largo_10 , string_definido_raro ) == diy_strcmp (
string_largo_10 , string_definido_raro ) ) ;
37 puts ( " Pruebas de diy_strcmp () : OK " ) ;
38 return 0;
39 }
Strings 4
Dr. Mariano Méndez, Juan Pablo Capurro 75.40 Algoritmos y Programación I Curso 4
Referencias
[1] webopedia define un literal como un valor que será interpretado tal como fue escrito, a diferencia de
una variable, que almacena un valor que puede variar a lo largo de la ejecución de un programa.
[2] wikipedia define formalmente el orden lexicográfico. A nosotros nos importa saber que es el orden
alfabético, como en la guı́a telefónica.
[3] En C, se considera comportamiento indefinido al hecho de que no esté especificado qué sucederá frente
a unas condiciones dadas. Esto no quiere decir que no pueda saberse, sino que quien desarrolló esa
función en particular no se preocupa en documentarlo porque está fuera de como esta deberı́a ser
usada. Un estudiante curioso, o un usuario con malas intenciones podrı́a, a veces fácilmente, saber qué
sucederá en tal caso. A menudo el resultado depende del entorno, como el sistema operativo sobre que
está corriendo el programa.
Strings 5