Na linguagem C, uma ou string (ou cadeia de caracteres) é um vetor de caracteres em que o caractere nulo ('\0') é interpretado como fim da parte relevante do vetor. Exemplo:
char *s;
s = malloc (10 * sizeof (char));
s[0] = 'A';
s[1] = 'B';
s[2] = 'C';
s[3] = '\0';
s[4] = 'D';
Depois da execução desse fragmento de código, o vetor s[0..3] contém a cadeia de caracteres ABC. O caractere nulo marca o fim dessa cadeia. A porção s[4..9] do vetor é ignorada.
O comprimento (= length) de uma string é o seu número de caracteres, sem contar o caractere nulo final.
O endereço de uma string é o endereço do seu primeiro caractere, da mesma forma que o endereço de um vetor é o endereço de seu primeiro elemento. Em discussões informais, é usual confundir uma string com o seu endereço. Assim, a expressão "considere a string s" deve ser entendida como "considere a string cujo endereço é s".
Para especificar uma string constante, basta embrulhar uma sequência de caracteres num par de aspas duplas. O caractere nulo final fica subentendido. Por exemplo, "ABC" é uma string constante e o fragmento de código
char *s; s = "ABC";
é equivalente ao que aparece na introdução desta página (exceto pelo fato de que a string "ABC" ocupa apenas 4 bytes na memória). O primeiro argumento das funções printf e scanf, é quase sempre uma string constante. Por exemplo,
scanf ("%d", &n);
printf ("O valor de n é %d", n);
A função abaixo conta o número de vogais em uma string. A função conta apenas as vogais não acentuadas, mas é muito fácil modificar o código para que todas as vogais sejam contadas.
int contaVogais (char s[]) {
int numVogais, i;
char *vogais;
vogais = "aeiouAEIOU";
numVogais = 0;
for (i = 0; s[i] != '\0'; ++i) {
char ch;
int j;
ch = s[i];
for (j = 0; vogais[j] != '\0'; ++j) {
if (vogais[j] == ch) {
numVogais += 1;
break;
}
}
}
return numVogais;
}
A biblioteca padrão string da linguagem C contém várias funções de manipulação de strings. Para usar essas funções, o seu programa deve incluir o arquivo-interface string.h:
#include <string.h>
No que segue, as strings serão tratadas como um novo tipo-de-dados:
typedef char *string;
1. A função strlen (abreviatura de string length) recebe uma string e devolve o seu comprimento. O código dessa função poderia ser escrito assim:
unsigned int strlen (string s) {
int i;
for (i = 0; s[i] != '\0'; ++i) ;
return i;
}
2. A função strcpy (abreviatura de string copy) recebe duas strings e copia a segunda (inclusive o caractere nulo final) para o espaço ocupado para a primeira. O conteúdo original da primeira string é perdido. Antes de chamar a função, o programador deve certificar-se de que o espaço alocado para primeira string é suficiente para acomodar a cópia da segunda. [Buffer overflow é uma das mais comuns origens de bugs de segurança!] O código dessa função poderia ser escrito assim:
void strcpy (string s, string t) {
int i;
for (i = 0; t[i] != '\0'; ++i)
s[i] = t[i];
s[i] = '\0';
}
(Na verdade, o código acima está ligeiramente incorreto, pois a função strcpy da biblioteca string devolve o endereço da primeira string. Mas os usuários da função usualmente só estão interessados no efeito da função e não n'o que ela devolve.)
A função strcpy pode ser usada para obter um efeito semelhante ao do exemplo que abriu esta página:
char s[10]; strcpy (s, "ABC");
3. A função strcmp (abreviatura de string compare) recebe duas strings e compara as duas lexicograficamente. Ela devolve um número negativo se a primeira string for lexicograficamente menor que a segunda, devolve 0 se as duas strings são iguais e devolve um número positivo se a primeira string for lexicograficamente maior que a segunda.
Embora os parâmetros da função sejam do tipo char *, a função se comporta como se eles fossem do tipo unsigned char *. Assim, por exemplo, "bb" é considerada lexicograficamente menor que "bbã" e "ba" é considerada lexicograficamente menor que "bã". O código da função poderia ser escrito assim:
int strcmp (string s, string t) {
int i;
unsigned char usi, uti;
for (i = 0; s[i] == t[i]; ++i)
if (s[i] == '\0') return 0;
usi = s[i]; uti = t[i];
return usi - uti;
}
Convém lembrar que o valor da expressão usi - uti é calculado em aritmética int (e não módulo 256).
A ordem lexicográfica entre strings é análoga à ordem das palavras em um dicionário. Ela se baseia na ordenação dos caracteres estabelecida na tabela ISO8859-1, da mesma forma que a ordem das palavras em um dicionário se baseia na ordenação das letras no alfabeto. Para comparar duas strings s e t, procura-se a primeira posição, digamos k, em que as duas strings diferem. Se s[k] vem antes de t[k] na tabela ISO então s é lexicograficamente menor que t. Se k não está definido então s e t são idênticas ou uma é prefixo próprio da outra; nesse caso, a string mais curta é lexicograficamente menor que a mais longa.
char a[8], b[8]; strcpy (a, "abacate"); strcpy (b, "banana");
char *a, *b; a = malloc (8); strcpy (a, "abacate"); b = malloc (8); strcpy (b, "banana");
char *a, *b; a = "abacate"; b = "banana";
char b[8], a[8];
strcpy (a, "abacate");
strcpy (b, "banana");
if (a < b)
printf ("%s vem antes de %s no dicionário", a, b);
else
printf ("%s vem depois de %s no dicionário", a, b);
char *b, *a;
a = "abacate";
b = "banana";
if (a < b)
printf ("%s vem antes de %s no dicionário", a, b);
else
printf ("%s vem depois de %s no dicionário", a, b);
char *a, *b;
a = "abacate";
b = "amora";
if (*a < *b)
printf ("%s vem antes de %s no dicionário", a, b);
else
printf ("%s vem depois de %s no dicionário", a, b);