|
CONJUNTO ORDENADO DE CARACTERES (STRINGS)
Los strings son simplementes
arrays de caracteres , el caracter NULL ( ASCII == 0 , simbolizado por la secuencia de
escape \0 ) . Este agregado permite a las funciones que procesan a los mismos , determinar
facilmente la finalización de los datos.
Podemos generar un string , declarando :
char car_str[] = { 'A' , 'B' , 'C' , 'D' , 0 } ;
char car_str[] = { 'A' , 'B' , 'C' , 'D' , '\0' }
;
Ambas maneras son equivalentes.
Sin embargo hay , en el lenguaje C , una forma más compacta de declararlos :
char car_str[] = "ABCD" ;
char car_str[5] = "ABCD" ;
int texto[] = "renglon 1 \n renglon 2 \n
" ; /* ERROR */
unsigned char texto[] = "renglon 1 \n
renglon 2 \n " ;
Simplemente en la declaración
del mismo se encierran los caracteres que lo componen entre comillas . Obsérvese que en
la segunda declaración , se ha explicitado ( no es necesario ) , la cantidad de elementos
que tiene el string , y és uno más que la cantidad de caracteres con que se lo
inicializa , para dejar lugar al NULL . Todas éstas declaraciones agregan
automáticamente el NULL como último elemento del array .
Un caso interesante es él de la tercer línea (
comentada como ERROR ) , con el fín de poder albergar al caracter "\n"20( ASCII
179 ) se intentó asignar el string a un array de enteros , Esto no es permitido por el
compilador , que lo rechaza como una asignación inválida . La razón de ello se verá
más adelante cuando analicemos punteros , ya que el string constante usado como rvalue es
un puntero a char , y no a int . La solución mas común para este caso es , declarar el
array como unsigned char , con lo que llevamos el alcance de sus elementos a 255 . Si
tuvieramos el caso de tener que albergar en un string el caracter EOF ( -1 ) y al mismo
tiempo caracteres con ASCII mayor que 127 ,se podría definir el array como int , pero su
inicialización se tendrá que hacer obligatoriamente usando llaves , como vimos
anteriormente .
Se deduce entonces , de lo antedicho que un string
sigue siendo un array de caracteres , con la salvedad del agregado de un terminador , por
lo que las propiedades que veremos a continuacion , se aplicaran indistintamente a ambos .
ARRAYS Y STRINGS COMO ARGUMENTOS DE FUNCIONES
Los arrays , como todos los otros
tipos de variables , pueden ser pasados como argumentos a las funciones . Veamos
esquematicamente como sería la sintaxis :
double funcion_1( float numeros[10] , char
palabra[] ) ; /*linea 1*/
main() /*linea 2*/
{
float numeros[10] = { 1.1 , 2.2 , 3.0 } ; /*linea
3*/
char palabra[] = " Lenguaje C " ;
/*linea 4*/
double c ; /*linea 5*/
........................................................
c = funcion_1( numeros , palabra ) /*linea 6*/
........................................................
}
double funcion_1( float numeros[10] , char
palabra[] ) /*linea 7*/
{
........................................................
}
Es necesario analizar con mucho
detenimiento , este último ejemplo . En la primer línea declaramos el prototipo de
funcion_1() que recibe como argumentos dos arrays , uno de 10 elementos del tipo float , y
otro de caracteres de longitud indeterminada . En el primer caso la función necesitará
saber de alguna manera cual es la longitud del array numérico recibido, mientras que en
el segundo , no hace falta , ya que la función puede ser construída para que , por sí
misma , detecte la finalización del string por la presencia del caracter NULL . Se
podría generalizar más el programa declarando :
double funcion_1( double numeros[] , int
longitud_array , char palabra[] ) ;
en donde , en la variable
longitud_array se enviaría la cantidad de elementos de numero[] .
En la tercer línea se declara el array numérico ,
inicializandose sólo los tres primeros elementos , y en la cuarta línea se declara el
string .
En la séptima línea se dá la definición de la
función , de acuerdo al prototipo escrito anteriormente .
Si miramos con detenimiento la sexta línea , el
llamado a la función , vemos que los argumentos pasados sólo tienen el NOMBRE de ambos
arrays . Esta es la diferencia más importante entre este tipo de estructura de datos y
las variables simples vistas anteriormente , ya que los arrays son pasados a las funciones
por DIRECCION y nó por valor .
En el lenguaje C se prefiere , para evitar el uso
abusivo del stack , cuando hay que enviar a una función una larga estructura de datos ,
en lugar de copiar a todos ellos , cargar el stack sólo con la dirección de la posición
de memoria donde está ubicado el primero de los mismos.
El nombre de un array equivale sintácticamente a la
direccion del elemento cero así será :
numero == dirección de numero[0]
palabra == direccion de palabra[0]
Esto habilita a las funciones a
que puedan acceder a los arrays directamente , allí donde el programa los ha ubicado en
la memoria , por lo que pueden modificarlos en forma permanente aunque no hayan sido
declarados como locales a la función misma ní globales al programa .
Es muy importante recordar este último concepto , a
fín de evitar errores muy comunes , en los primeros intentos de programación en C .
Otra característica importante de los arrays es que
, su nombre ( ó dirección del primer elemento ) es una CONSTANTE y nó una variable . El
nombre de los arrays implican para el compilador el lugar de memoria donde empieza la
estructura de datos por lo que , intentar cambiar su valor es tomado como un error , asI
si escribieramos por ejemplo :
char titulo[] = "Primer titulo" ;
titulo = "subtitulo" ;
La primer sentencia es correcta ,
ya que estamos incializando al string , pero la segunda produciría un error del tipo
" LVALUE REQUERIDO " , es decir que el compilador espera ver , del lado
izquierdo de una expresión , a una variable y en cambio se ha encontrado con una
constante titulo (ó sea la dirección de memoria donde está almacenada la P de
"Primer título") . Esto al compilador le suena similar a una expresión de la
clase : 124 = j y se niega rotundamente a compilarla .
|