STRINGS

Um string nada mais é que uma seqüência especial de caracteres. Em C, eles são colocadas entre ". Assim, "oba", "teste\n" (que usamos muito no printf) são exemplos de string.

Agora não confunda: 'x' é o CARACTER x, enquanto que "x" é o STRING x. E qual a diferença? Já vamos ver.

O C, infelizmente, não tem um tipo string pré-definido. Ou seja, ele tem que representar string de outra forma. E como ele representa? Como um vetor de caracteres terminado pelo caracter '\0'. Sendo assim, a única diferença entre um vetor de caracteres e uma string é a obrigatoriedade do '\0' no final da string. Só como curiosidade, o código ASCII do '\0' é 0 (faça printf("%d\n",'\0'); para ver).

Agora sim, podemos ver a diferença entre 'x' e "x". Quando escrevemos "x" o compilador, na verdade, cria um vetor com 2 caracteres: 'x' e '\0'. Por isso você não deve fazer confusão.

Escrevendo strings

Como escrevemos na tela uma string?

	printf("Minha string é: %s", "string");
		

E isso imprime:

	Minha string é: string
		

Declarando strings

Como vimos, strings são, na verdade, vetores terminados em '\0'. Então é de se esperar que eles sejam declarados como vetores:

	char str[11];
		

Aqui declaramos uma string de 10 caracteres. 10? Como 10? Lá tá 11! Ô! e o '\0'? Não conta? São 10 caracteres mais o '\0', ou seja, 11 no total, mas somente 10 úteis para nós.

Inicializando strings

Beleza, declaramos... e como inicializamos a coisa? Temos duas maneiras. A primeira, é como faríamos com um vetor:

	char str[11] = {'m','e','u',' ','s','t','r','i','n','g','\0'};
		

Olha o '\0' aí gente! Meio maçante isso não? Bom, funciona, mas tem algo melhor:

	char str[11] = "meu string";
		

Bem mais fácil, e sem precisar por o '\0' - o compilador faz isso prá você. Também há outro modo:

	char str[] = "meu string";
		

E qual a diferença entre os 2 últimos modos? A mesma diferença que há com vetores: no primeiro, reservo memória para 11 caracteres e abasteço o string neste espaço; no segundo, o compilador conta o número de caracteres do string (incluindo o '\0') e aloca memória suficiente somente para este string.

Até agora trocamos seis por meia-dúzia. Mas imagine a seguinte situação:

	char str1[20] = "meu string"; /*reserva espaço para 20 caracteres*/
	char str2[] = "meu string";   /*reserva espaço para 11 caracteres*/
		

Suponha que, por algum motivo, queremos adicionar mais uma letra ao final do nosso string. Com str1, tudo bem, tem espaço. Mas, ops, str2 não tem mais espaço pra isso... tome muito cuidado com situações assim.

Agora só nos falta escrevermos nosso string na tela:

int main() {
	char str[] = "meu string";   /*reserva espaço para 11 caracteres*/

	printf("%s",str);
}
		

Acessando caracteres no string

Como fazemos para acessar um determinado elemento do string? Como num vetor:

	char str[] = "meu string";
	char letra;

	printf("%c\n",str[2]); /*imprime o 3o caracter*/

	letra = str[8];

	printf("%c\n",letra); /*imprime o 9o caracter*/
		

E para mudar o valor deste elemento?

int main() {
	char str[] = "meu string";   /*reserva espaço para 11 caracteres*/

	/* mudo o 6o caracter */
	str[5] = 'd';

	printf("%s",str);
}
		

E isso imprime:

	meu sdring
		

E se agora quisermos colocar um caracter no final do string. Aí complica um pouco, pois podemos não saber qual a posição final do string. Porém, sabemos que no final há um '\0'. Então, temos que:

  1. Achar a posição do '\0'
  2. Colocar o novo caracter lá
  3. Escrever o '\0' na posição seguinte a esta

Note que, antes de mais nada, temos que verificar se o string comporta este novo caracter, ou seja, se há espaço alocado para ele. Se o string foi inicializado com [], aí nem tente seguir o algoritmo acima.

Vamos por em prática:

#include <stdio.h>

int main() {
	char str[12] = "meu string"; /*reserva espaço para 12 caracteres*/
	int pos;                     /*posição do \0*/
	char novo = '!';             /*caracter a ser incluído*/

	/* acho a posição do \0 */
	pos = 0;
	while (str[pos] != '\0') pos++;

	/* coloco o novo caracter nessa posição */
	str[pos] = novo;

	/* coloco o \0 no final do novo string */
	str[pos+1] = '\0';

	printf("%s",str);
}
		

E isso imprime:

	meu string!
		

Note que, quando inicializamos o string, tomamos o cuidado de dar a ele mais espaço do que precisava...

Lendo strings do teclado

Da mesma forma que usamos printf para escrever um string, você deve estar supondo que usamos scanf para lê-lo. Pois bem, vejamos:

#include <stdio.h>

int main() {
	char str[12]; /*reserva espaço para 12 caracteres*/

	printf("Seu string: ");
	scanf("%s",str);

	printf("%s\n",str);
}
		

Note que não usamos o & antes do str. Isto porque não é uma variável. Lembra de vetores, que quando queríamos poder modificar o vetor como um todo passávamos somente seu nome como parâmetro das funções? Pois com string é a mesma coisa. Como queremos que scanf modifique o string, passamos seu nome no parâmetro (sem o &).

E qual a saída deste programa?

	Seu string: oba!
	oba!

	Seu string: oba oba!
	oba
		

Ops! O que houve? O problema foi com printf. Printf lê a entrada até encontrar um espaço, um "enter" ou uma tabulação, ou seja, até encontrar ' ', '\n' ou '\t'.

E como resolvemos este problema? Com gets():

#include <stdio.h>

int main() {
	char str[12]; /*reserva espaço para 12 caracteres*/

	printf("Seu string: ");
	gets(str);

	printf("%s\n",str);
}
		

gets(), definida também em stdio.h, lê até um "enter", ou seja, até um '\n'. A saída do programa agora é:

	Seu string: oba!
	oba!

	Seu string: oba oba!
	oba oba!
		

Quando você compilar isso, provavelmente o compilador irá lhe avisar que gets() é perigosa. E é verdade. Mas por que ela é perigosa? Ela é perigosa porque não checa o limite do string. Com isso, algum usuário sem-vergonha pode digitar uma porrada de caracteres, estourando o limite da sua string e, ou sobrescrevendo parte dos dados do seu programa, ou capotando ele. Então, não use gets para fins profissionais (mais adiante veremos, juntamente com arquivos, um coxambre para o gets). Porém, para nossos fins didáticos, gets está de bom tamanho.

Funções de manipulação de strings

Como você faz para copiar um string? Bom, da mesma forma que copiava vetores. Só que em vez de fazer uma função para isso, alguém já fez para você, veja:

#include <stdio.h>
#include <string.h>

int main() {
	char str1[12]; /*reserva espaço para 12 caracteres*/
	char str2[12]; /*reserva espaço para 12 caracteres*/

	printf("Seu string: ");
	gets(str1);

	/* copio o conteúdo de str1 para str2 */
	strcpy(str2,str1);

	printf("%s\n",str1);
	printf("%s\n",str2);
}
		

Vamos ver como concatenar dois strings, ou seja, como grudar um ao final do outro:

#include <stdio.h>
#include <string.h>

int main() {
	char str1[24]; /*reserva espaço para 24 caracteres*/
	char str2[12]; /*reserva espaço para 12 caracteres*/

	/* carrego o primeiro string */
	strcpy(str1,"oba oba");

	/* carrego o segundo string */
	strcpy(str2,"eba");

	/* concateno str2 ao final de str1 */
	strcat(str1, str2);

	printf("%s\n",str1);
}
		

E a saída é:

	oba obaeba
		

E se quisermos comparar dois strings? strcmp(s1,s2). Esta função retorna 0 se os strings forem iguais, um número < 0 se s1 < s2 e > 0 se s1 > s2. Vamos ver o uso:

#include <stdio.h>
#include <string.h>

int main() {
	char str1[12]; /*reserva espaço para 12 caracteres*/
	char str2[12]; /*reserva espaço para 12 caracteres*/

	/* carrego o primeiro string */
	strcpy(str1,"oba oba");

	/* carrego o segundo string */
	strcpy(str2,"oba oba");

	if (!strcmp(str1,str2)) printf("iguais\n");
	else printf("diferentes\n");

	/* mudo o valor de str2 */
	strcpy(str2,"oba ");

	if (!strcmp(str1,str2)) printf("iguais\n");
	else printf("diferentes\n");

	/* vejo qual é maior (alfabeticamente) */
	if (strcmp(str1,str2)>0) printf("\"%s\" maior que \"%s\"\n",str1,str2);

	/* mudo o valor de str2 */
	strcpy(str2,"oba obb");

	/* vejo qual é menor (alfabeticamente) */
	if (strcmp(str1,str2)<0) printf("\"%s\" menor que \"%s\"\n",str1,str2);
}
		

Notou que a comparação se dá caracter a caracter? E a saída será:

	iguais
	diferentes
	"oba oba" maior que "oba "
	"oba oba" menor que "oba obb"
		

Mais do que isso, ele compara usando a tabela ascii, olhe este programa:

#include <stdio.h>
#include <string.h>

int main() {
	char str1[12]; /*reserva espaço para 12 caracteres*/
	char str2[12]; /*reserva espaço para 12 caracteres*/

	/* carrego o primeiro string */
	strcpy(str1,"oba oba");

	/* carrego o segundo string */
	strcpy(str2,"oba oba");

	printf("%d\n",strcmp("a","A"));
	printf("a = %d\n",'a');
	printf("A = %d\n",'A');
}
		

Cuja saída é:

	32
	a = 97
	A = 65
		

Ou seja, "oba" é maior que "Oba". Note que o programa retornou, na verdade a diferença entre as letras...

Por fim, a função strlen retorna o número de caracteres de um string (sem contar o '\0'):

#include <stdio.h>
#include <string.h>

int main() {
	char str[12]; /*reserva espaço para 12 caracteres*/

	/* carrego o string */
	strcpy(str,"oba oba");

	printf("%d\n",strlen(str));
}
		

Saída:

	7
		

Um exemplo

Vamos ver um exemplo. Suponha que você receba um string contendo um nome, e queira ter certeza de que o nome possui iniciais maiúsculas. Como faria? Uma solução seria:

#include <stdio.h>
#include <string.h>

int main() {
	char nome[50];
	int i = 0; /*contador*/
	int pos_espaco = 1; /*indica se a letra veio após um espaço*/

	/* leio o nome */
	printf("nome: ");
	gets(nome);

	while (nome[i]!='\0') {
		/* se veio após um espaço, deixo maiúscula */
		if (pos_espaco) nome[i] = toupper(nome[i]);

		pos_espaco = nome[i] == ' ';

		i++;
	}

	/* mostro o string */
	printf("%s\n",nome);
}
		

Esse programa usa uma variável para determinar se uma letra vem após um espaço. A idéia é que se ela veio imediatamente após um espaço deve ser transformada em maiúscula. A linha

	pos_espaco = nome[i] == ' ';
		

faz essa variável ser verdadeira somente se o caracter analisado no momento for um espaço. Note que, se o nome contiver vários espaços, o programa fica tentando passar espaços para maiúscula... daí sua ineficiência. Porém, como menciono no programa, ele fica mais fácil de entender assim. Veja algumas saídas dele:

nome: Adolfo dias
Adolfo Dias

nome:    rolando Caio da    rocha
   Rolando Caio Da    Rocha

nome: Jacinto Dores
Jacinto Dores
		

Notou que independe do número de espaços? Mas e o que é o toupper()? A função toupper tem o seguinte cabeçalho (é definida assim):

	int toupper(int ch);
		

e oficialmente faz parte da biblioteca ctype.h (muito embora, no gcc dispense a inclusão dessa biblioteca). Basicamente, ela pega um caracter e devolve seu equivalente maiúsculo. Caso o caracter já for maiúsculo ou não for letra, devolve o próprio caracter. Um modo de implementar essa função poderia ser:

int meu_toupper(int ch) {
	if ((ch >= 'a') && (ch <= 'z')) {
		/* é letra minúscula, mudo para maiúscula */
		return (ch - 'a' + 'A');
	}

	/* não é minúscula, mantenho a letra */
	return(ch);
}
		

Caso você queira uma função que faça o mesmo que toupper mas, em vez de maiúscula, retorne minúscula, use tolower, cujo cabeçalho é

	int tolower(int ch);
		

Vetores de strings

Às vezes, se faz necessário guardar vários strings, como em um vetor. Bom, uma vez que um string nada mais é que um vetor de caracteres, podemos implementar um vetor de strings simplesmente como uma matriz de strings. Assim, nossa matriz seria algo assim:

	char vet[numero_de_strings][tamanho_dos_strings];
		

E pronto. Por exemplo:

#include <stdio.h>
#include <string.h>

int main() {
	char vet[5][21]; /*espaço para 5 strings de 21 caracteres cada*/
	int i;           /*contador*/

	/* peço ao usuário para fornecer os 5 strings */
	for (i=0; i<5; i++) {
		printf("Entre string número %d: ",i);
		gets(vet[i]);
	}

	/* escrevo na tela os 5 strings */
	for (i=0; i<5; i++)
		printf("Seu string: %s\n",vet[i]);
}
		

E se quiséssemos inicializar nossa matriz logo de início?

#include <stdio.h>

int main() {
	char vet[5][21] = {"meu primeiro string",
				"segundão da lista",
				"terceiro",
				"to quase lá...",
				"o último!"};
	int i;

	/* imprimo o vetor */
	for (i=0; i<5; i++) {
		printf("vet[%d] =  %s\n",i,vet[i]);
	}
}
		



Copyright© 2005 Norton Trevisan Roman - Direitos Autorais Reservados.