Diferencia entre revisiones de «Constantes de cadena (Informática)»

Línea 5: Línea 5:
 
== Ejemplo ==
 
== Ejemplo ==
 
"Esto es una cadena literal!"
 
"Esto es una cadena literal!"
 +
 
L"Esto es una cadena de caracteres anchos"
 
L"Esto es una cadena de caracteres anchos"
  

Revisión del 11:17 23 may 2011

Constantes de cadena (Informática)
Información sobre la plantilla
Concepto:Son utilizadas para albergar secuencias de caracteres alfanuméricos, y forman una categoría especial dentro de las constantes

Constantes de cadena (Informática). También llamadas cadenas literales o alfanuméricas ("String literals"), son utilizadas para albergar secuencias de caracteres alfanuméricos, y forman una categoría especial dentro de las constantes, aunque también pueden ser consideradas un caso especial de matrices de caracteres. Se representan en el Código fuente como una secuencia de caracteres entre comillas dobles ("):

Ejemplo

"Esto es una cadena literal!"

L"Esto es una cadena de caracteres anchos"

Cadenas literales

Las cadenas literales aparecen como un tipo algo extraño, que en cierta forma desentona del resto de entidades del universo C++ y que no deberían tener cabida en él. En realidad hay algo de esto; representan una herencia de su antecesor C, en el que se utilizan estas "extrañas" construcciones para almacenar texto alfanumérico en el que su punto final se identifica mediante el carácter nulo.

El texto de una cadena literal puede contener cualquier carácter del juego de caracteres imprimibles ASCII. Para representar los caracteres no imprimibles se utilizan las denominadas secuencias de escape; un truco que consiste en sustituir cada carácter no imprimible por una secuencia de dos o tres caracteres. Naturalmente, una cadena literal no debe contener un carácter nulo en su interior (que como hemos indicado señala el final de la cadena); en caso contrario, al aplicarse las funciones de Librería Estándar clásicas (heredadas de C) el resultado es impredecible.

Desde la óptica C++, las cadenas literales:

  • Representan valores (datos) constantes.
  • Para el compilador son en realidad matrices de caracteres constantes, aunque les permite una sintaxis algo especial en atención a que el antiguo código C sea compatible con los compiladores C++.
  • Si la cadena no está precedida por la letra L, es una matriz de caracteres tipo const char, también denominada cadena estrecha u ordinaria ("Narrow string literal").
  • Si la cadena está precedida por la letra L, los miembros de la matriz son caracteres anchos del tipo const w_char, y se denomina cadena ancha ("Wide string literal").
  • Estos objetos tienen almacenamiento estático en el sentido indicado en; es decir, que el compilador conoce los valores en tiempo de compilación, y que probablemente sean guardados en el segmento.

Generalmente aparecen a la derecha en expresiones de asignación o como parámetros de funciones; pueden aparecer incluso como valores devueltos por funciones. Ejemplos:

  char* ptr = "Hola mundo";
  printf("%s\n", "Soy una cadena literal");
  cout << "acabo de llegar" << endl;
  return "Se termina la función";


Secuencias de escape

Dentro de las comillas se pueden representar caracteres especiales (no imprimibles) mediante secuencias de escape. Por ejemplo, el código:

  "\t\t\"Nombre\"\\\tDirección\n\n"

Se representa como:

  "Nombre"\   Dirección 

"Nombre" es precedido por dos tabulaciones; Dirección esta precedido por una tabulación. La línea va seguida de dos nueva línea (NL). La secuencia \" proporciona las comillas interiores. Si se compila con la opción -A para compatibilidad ANSI, la secuencia de escape "\\", es traducida por el compilador a "\".

En C++ las cadenas alfanuméricas son técnicamente matrices de caracteres constantes; se almacenan internamente como secuencias de caracteres más un carácter final nulo '\0', lo que significa que el almacenamiento usado es igual a la longitud visible de la cadena mas uno. Según esto, la cadena nula "" es almacenada como un solo carácter '\0', y no hay más límite que la memoria disponible para la longitud posible de una cadena.

Peculiaridades

Una cadena literal es "un tipo de matriz de caracteres constantes". Se trata pues de verdaderas matrices, aunque la coletilla "de caracteres constantes" es importante. Significa esto que no se trata de ningún nuevo tipo de dato, solo un tipo particular de matrices. En consecuencia, una cadena como "Hola" es del tipo const char [5] (matriz de caracteres constantes de cinco elementos). Su única singularidad es que el compilador C++ les permite ciertas formas particulares de definición y declaración que les confiere cierta personalidad. Respecto a esto último, solo tiene justificación histórica, porque el carácter nulo se utilizaba en las antiguas funciones de librería para indicar el final de la cadena. Por esta razón, aunque es posible incluir caracteres nulos dentro de las cadenas literales. Por ejemplo: "Hola\0 mundo", no está garantizado que funcione en todos los casos (será malinterpretado por las funciones printf, strcpy y strlen de la librería estándar). Ejemplo:

  char* ptr = "Hola\0 mundo";
  printf("%s\n", ptr);

Salida:

  Hola

Una cadena nula (vacía) se representa "" o "\0"; tiene un solo carácter; el carácter nulo (ver a continuación). Observe que desde el punto de vista del Rvalue, la constante de cadena "A" es A\0, mientras que la constante carácter 'A' es A.

Se considera que la longitud de un NTBS es el número de caracteres que preceden al de terminación, de forma que la cadena nula tiene longitud 0 (aunque en realidad contiene un carácter). Sin embargo, el valor de la cadena incluye el carácter de final.

Conviene no confundir una constante de cadena (matriz) de un solo carácter con un carácter char, constante o variable. La cadena de un solo carácter es necesariamente la cadena nula, su único elemento es el de fin de cadena.

Ejemplo:

  char   x1= 'a' ;    		 // L.1: variable x1 tipo char
                   		 // valor == ASCII a == 97 decimal
  const char x2= 'a'; 		 // L.2: constante x2 tipo const char
  char* x3 = "a" ;     	 // L.3: variable x3 tipo puntero-a-char
                   		 // señala a cadena de dos caracteres, 97 y 0 decimal
  const char* x4 = "a";	 // L.4: variable x4 tipo puntero a constante carácter
  char x5[1]= 'a' ;    	 // L.5: variable x5 tipo matriz de un carácter
                    		 // valor x[0]== a == 97 decimal

Los objetos representados por los Rvalues de las expresiones anteriores son de distinto tipo y se almacenan con tamaños distintos. La primera, segunda y quinta son constantes carácter (const char); la tercera y cuarta son cadenas (matrices) de dos caracteres.

En lo que respecta a los cinco objetos definidos, x1 es una variable char; x2 es una constante char; x3 es un puntero a cadena de caracteres; x4 es un puntero cadena de caracteres constantes, y x5 es una matriz de caracteres de un elemento.

Es también muy importante señalar que la asignación:

  str = "AEIOU";

solo es posible si str se ha declarado previamente como puntero a carácter, es decir:

  char* str;               // §g

Aunque se puede declarar y definir en la misma sentencia (preferible):

  char* str = "AEIOU";     // §h

La expresión §h define una matriz de seis caracteres constantes (almacenado en algún sitio), que no tiene identificador simple (nombre). También define un puntero, str al primer elemento de la matriz (más formalmente: es un puntero a carácter). Por tanto, a falta de un nombre, la matriz tiene que ser accedida a través del puntero (que tendrá que ser tratado como tal -puntero-). Sin embargo, las expresiones:

  char arr[] = "AEIOU";              // §j 
  char arr[6] = "AEIOU";
  char arr[6] = {'A','E','I','O','U','\0'};
  char arr[6] = {'A','E','I','O','U',};
  char arr[6] = {'A','E','I','O','U',0};

definen arr como matrices de caracteres de 6 elementos (las 5 expresiones son equivalentes); en estos casos cada matriz puede ser accedida por su nombre (que tienen que ser tratado como tal -identificador-) y no son de contenido constante.

Todo esto tiene varias implicaciones: En el primer caso (§h) , str es un puntero; un objeto que puede ser usado con el álgebra de punteros. Por ejemplo, es válida la expresión: str++ que equivale a: str = str+1;. En los otros cinco casos (§j ), arr es un nemónico que representa una matriz, y la expresión arr++, que equivale a: arr = arr+1; es ilegal. El operando arr+1 es tratado como (&arr[0])+1, lo que es correcto (a un puntero se le puede sumar un entero). La asignación no sería correcta porque intentaría asignar el puntero, &arr[1], a la matriz arr.

No olvidar que en el primer caso *str no significa la matriz "AEIOU", solo el primer elemento 'A', por lo que no tiene sentido intentar la asignación *str = "aeiou";, ni siquiera *str = "a";; solo es posible *str = 'a';. Recuerde que C++ no tiene operadores para tratar las matrices como una unidad, es decir, para hacer una asignación del tipo: x = "aeiou". Si tiene en cambio poderosas funciones en su Librería Estándar para hacer todo tipo de manipulaciones con cadenas alfanuméricas.

Es también importante distinguir otra diferencia entre las expresiones:

  char a1[6] = "AEIOU\0", *p1 = &a1[0];
  char* a2 = "AEIOU";

Ambas producen matrices de caracteres absolutamente idénticos en contenido y tamaño, pero a1 es una matriz, por lo que sus elementos podrían ser alterados usando el identificador. Por ejemplo: es válido a1[1]= 'e', o su equivalente: *(p1+1)='e';. En cambio, un intento análogo sobre el segundo obliga a usar necesariamente la versión con puntero: *(a2+1)='e'. Además de que por las razones ya expuestas el resultado no está garantizado. Si se quiere que los caracteres de una cadena puedan ser modificados lo mejor es incluirlos en una matriz como en a1.

Es posible todavía la asignación:

  a2 = "aeiou";

En este caso, el compilador almacena en algún sitio la cadena "aeiou\0" y asigna a a2 la dirección del primer elemento. A partir de ahora es accesible mediante a2, pero la primitiva cadena "AEIOU", que sigue existiendo en su sitio, se ha perdido irremisiblemente, no es accesible de ningún modo, aunque sigue malgastando espacio de memoria.

También es posible declarar cadenas de caracteres anchos con el prefijo L como en el ejemplo:

  wchar_t* wptr = L"aeiou";

en este caso wptr señala una cadena de caracteres anchos; la cadena es del tipo const wchar_t. Para saber la longitud de una constante literal, es necesario que el programa repase la cadena hasta encontrar el carácter de fin de cadena, lo que se consigue con la función de librería strlen (incluida en la cabecera estándar <string.h>), que proporciona la longitud sin contar el carácter final.

Concatenación de cadenas

Las cadenas literales adyacentes separadas solo por un especio son automáticamente concatenadas durante la fase de preprocesado de la compilación. Por ejemplo: "Hola" " mundo", es equivalente a "Hola mundo". También puede usarse la barra invertida ( \ ) como símbolo de continuación para extender una cadena literal más allá del límite de una línea:

  puts("En realidad, esto es \
  una cadena de una linea");
  char *p = "Esto es en otra cadena, " 
            "también de una sola línea.";

La concatenación suprime el carácter nulo de final en las cadenas intermedias y mantiene el de la última. Esta operación no altera el significado de los caracteres que intervienen en las cadenas concatenadas. Por ejemplo, la concatenación

  "\xA" "B"

Produce la cadena

  "\xAB"

que tiene tres caracteres: el hexadecimal '\xA'; el carácter 'B', y el caracter final nulo '\0'. En vez del carácter hexadecimal '\xAB'.

La concatenación de cadenas anchas y estrechas tiene resultados impredecibles.

Véase también

Fuente