Variables estáticas con Strings en C
Puede que en algún momento de tu carrera como programador en lenguaje C te hayas topado con el error "Segmentation Fault". Este error tiene un sin número de causas, sin embargo, hoy veremos una de las más importantes y requiere que tengas conocimiento en Arrays, Punteros, Cadenas, funciones y clases de almacenamiento.
Resulta, y esto sucede sobretodo cuando vienes de lenguajes de más alto nivel, que puede parecer sencillo retornar un array de caracetes o "string" en una función después de que hemos realizado algún proceso con este string. Por ejemplo, supongamos que quieres hacer una función que concatene un caracter un número de veces al final de un string y a esta función la llamaremos pad_right. Es decir, que si ejecutamos el siguiente código:
char word[] = "Hola";
char padded[10];
pad_right(word, 10, "*");
El valor de retorno de nuestra función debería ser el siguiente:
Hola******
Siendo así, podríamos codificar una función similar a la siguiente:
char* pad_right(char* string, int length, char* pad_char)
{
int extra_chars = length - strlen(string);
if (extra_chars < 0) {
return string;
}
char padded_text[40] = {'\0'};
strcpy(padded_text, string);
for (int i = 0; i < extra_chars; i++) {
strcat(padded_text, pad_char);
}
return padded_text;
}
Veamos este programa paso a paso. En las primeras líneas se verifica si el size que queremos para el pad es menor al valor del string que hemos pasado. En caso de que no, se retorna el mismo string.
int extra_chars = length - strlen(string);
if (extra_chars < 0) {
return string;
}
Es decir, en caso que hagamos algo como esto:
char word[] = "Hola";
char padded[1];
pad_right(word, 1, "*");
Obtendríamos el mismo string ya que el tamaño del pad que estamos colocando es menor que el de la palabra.
Hola
En las siguientes líneas está la magia (y también nuestro problema). Creamos un array de 40 caraceteres para alojar el valor que queremos retornar. Después, asignamos la palabra a nuestro valor de retorno, así solo faltaría agregar el pad.
char padded_text[40] = {'\0'};
strcpy(padded_text, string);
Finalmente utilizamos un ciclo para repetir el caracter pad las veces que sea necesario para completar el tamaño adecuado.
for (int i = 0; i < extra_chars; i++) {
strcat(padded_text, pad_char);
}
El problema con este código es que cuando querramos hacer debug obtendremos el famoso error "Segmentation fault". El compilar arrojará el siguiente warning:
warning: function returns address of local variable
Por lo tanto, como es de esperar nuestro programa no funcionará como esperabamos. La solución a este problema como ya te habrás dado cuenta, es utilizar la clase de almacenamiento static así:
static char padded_text[40] = {'\0'};
Como recordarás, a nivel interno las variables que se crean dentro de un bloque desaparecen después de dicho bloque, por lo que no estarán disponibles fuera de la función. Es por esto, que no podemos retornar un string, o dirección de memoria de un valor que ya no existe!.
La clase de almacenamiento static nos permite persistir el valor creado para poder retornarlo.