Gracias a que existen compiladores de C para pics es posible que los micros puedan entregar resultados en forma de texto y no en bits. Los compiladores de C normal (nada de c++, ni c#, ni java) no manejan variables tipo string pero manejan algo similar: arreglos de chars.
La variable char mide 8 bits y puede expresar datos de 0 a 255 (256 valores). Comúnmente se vincula un char a una letra o caracter del código ascii dependiendo del valor binario que éste tenga. Por ejemplo, la letra 'a' vale 0x61 en código ascii o el espacio ' ' vale 0x20.
La tabla ascii es muy popular, acá están sus valores:
http://www.asciitable.com/Un arreglo es una sucesión de variables en memoria ram. Un arreglo de chars es una sucesión de variables de 8 bits.
Si se declara lo siguiente:
char arreglo[5];
se tendrá un arreglo de 5 elementos de tipo char. El contenido de cada char es aleatorio al arrancar el pic y usando el compilador de CCS para el ejemplo anterior. Se deberá inicializar el valor de cada elemento según el uso que se le vaya a dar.
Para convertir el arreglo de chars anterior en una cadena formal, el arreglo deberá contar con lo siguiente:
- Debe tener de 0 a 4 elementos (caracteres ascii) en las primeras 4 posiciones
- El último elemento deberá ser un NULL char que equivale a 0x00
El elemento NULL marca el fin de los caracteres útiles de la cadena. Armemos una cadena sencilla con las características que se mencionaron:
arreglo[0]='c';
arreglo[1]='a';
arreglo[2]='s';
arreglo[3]='a';
arreglo[4]=0x00;
La cadena claramente contiene 'casa'. El quinto elemento dice: 'aquí terminó el texto'.
Al usar la declaración
char arreglo[5]; en realidad se está declarando un apuntador a una secuencia de chars. El apuntador se llamará arreglo y será capaz de conocer la dirección ram de un char.
Por ejemplo, si yo quisiera saber cuál es la tercera letra de mi cadena puedo hacerlo de muchas formas...
//Usando un índice con arreglo (la más fácil)
if(arreglo[2]=='s')
//Es una s
//Usando otro apuntador de chars
char *apuntador;
apuntador = arreglo+2; //copia la dirección ram del tercer elemento de la cadena (letra s)
if(*apuntador == 's')
//Es una s
//Usando otro apuntador de chars
char *apuntador;
apuntador = &arreglo[2]; //copia la dirección ram del tercer elemento de la cadena (letra s)
if(*apuntador == 's')
//Es una s
El siguiente ejemplo muestra una cadena que contiene el texto útil 'Calcula'.
char cadena[30]; //Una cadena que podrá almacenar hasta 29 caracteres
cadena[0]='C';
cadena[1]='a';
cadena[2]='l';
cadena[3]='c';
cadena[4]='u';
cadena[5]='l';
cadena[6]='a';
cadena[7]=0x00;
cadena[8]='d';
cadena[9]='o';
cadena[10]='r';
cadena[11]='a';
Al insertar el null char en la octava posición sabremos que ahí terminó la cadena a pesar de que hay más letras después.
Pude haberme ahorrado el esfuerzo y declarado lo anterior más rápido:
char cadena[]="Calcula";
Al escribir lo anterior el compilador cuenta cuántos chars lleva la cadena y agrega el NULL char, obteniendo 8 elementos para el arreglo cadena. Este arreglo es de tamaño fijo a pesar de que no le declaramos uno. El uso de tal instrucción solo es válido al principio del programa. Si se desea construir una cadena a mitad de un programa es mejor usar sprintf.
Para declarar cadenas hay 2 formas básicas: cadenas de tamaño constante y cadenas dinámicas. Ya se vio la declaración de las de tamaño constante, ahora se verá la dinámica:
char *cadena;
Al no tener un tamaño la cadena puede invadir memoria ram dedicada a otros propósitos y eso se debe evitar a toda costa. Para ubicar memoria ram en CCS para cadenas dinámicas (también para arreglos de cualquier otra variable dinámica) se usa malloc(). No profundizaré en este tema porque se usa poco en microcontroladores. Ejemplo:
#USE DYNAMIC_MEMORY
...
char *cadena;
...
//Búscame ram para almacenar 30 chars consecutivos
cadena=(char *)malloc(30);
...
//Ya no voy a usar la cadena, deséchala
free(cadena);
De esa forma la cadena ocupará espacio seguro y no invadirá el espacio de otros registros.
En C se usa la función sprintf para convertir variables (enteros, chars, arreglos de chars, flotantes, etc.) en texto legible para un usuario. Lo que hace la función es construir arreglos de chars y terminarlos con un NULL char.
Ejemplo 1 - Cómo almacenar 5 cadenas en una sola cadena
char cadena[50]; //cada cadena tendrá 9 chars + 1 NULL = 10 chars
//primera palabra
sprintf(cadena,"perro");
//segunda
sprintf(cadena+10,"gato");
//tercera
sprintf(cadena+20,"ratón");
//cuarta
sprintf(cadena+30,"queso");
//quinta
sprintf(cadena+40,"leche");
Pero, ¿por qué caben 5 cadenas en una sola cadena? Sprintf se encargó de insertar las letras de la palabra más un null char al final de cada una de ellas. Al usar printf para imprimirlas, buscará el null char y ahí se detendrá sin importar qué más hay después.
Ejemplo 2 - Imprimiendo las multicadenas (sigue del ejemplo 1)
//Define el tamaño de cadena en la multicadena
#define tamano 10
...
//primera
printf("%s \n", &cadena[0*tamano]);
//segunda
printf("%s \n", &cadena[1*tamano]);
//tercera
printf("%s \n", &cadena[2*tamano]);
//cuarta
printf("%s \n", &cadena[3*tamano]);
//quinta
printf("%s \n", &cadena[4*tamano]);
Lo que saldría en pantalla sería
perro
gato
ratón
queso
leche
Y un último ejemplo más difícil en el que determino la extensión del nombre de un archivo para ver si es un archivo JPEG válido (.jpg o .JPG).
Ejemplo 3 - Detectando la extensión de un archivo
//verifica que el archivo sea un jpg válido
//.jpg, .JPG
char temporal[6];
bool jpg_valido=0;
j=0;
for(i=(strlen(filename)-4);i<strlen(filename);i++)
temporal[j++]=filename[i];
temporal[j]=0;
if(strcmp(temporal,".jpg")==0) jpg_valido=1;
if(strcmp(temporal,".JPG")==0) jpg_valido=1;
//.jpeg, .JPEG
j=0;
for(i=(strlen(filename)-5);i<strlen(filename);i++)
temporal[j++]=filename[i];
temporal[j]=0;
if(strcmp(temporal,".jpeg")==0) jpg_valido=1;
if(strcmp(temporal,".JPEG")==0) jpg_valido=1;
Primero se posiciona en el cuarto char de atrás hacia adelante de la cadena filename gracias a la función strlen() que indica cuántos chars útiles hay en la cadena. Después copia los 4 últimos chars en otra cadena llamada temporal. Por último determina con la función strcmp si la cadena temporal es idéntica a la cadena ".JPG" o ".jpg". De ser el caso, el archivo es un JPEG.
Repite el caso para .jpeg y .JPEG.
Si pudiste entender el ejemplo 3 entonces ya te sirvió este mini tutorial de cadenas.
Si lo creen necesario puedo seguir explicando funciones de concatenación de strings, comparación, conteo, etc.
Actualización.Gera continuará explicando los demás funciones de string.h aquí:
http://www.todopic.com.ar/foros/index.php?topic=25785.msg210828#msg210828