sexta-feira, 13 de novembro de 2015

C: Sobre strings e uma pequena eliminação de strlen, strcpy

Existem alguns truques que podem ser usados para acelerar processamento de strings, mas exigem uma compreensão de como funcionam as strings em C.

As strings em C são chamadas de Null Terminated Strings, ou strings terminadas por nulo. O caractere null, que é equivalente ao número inteiro zero (note, não é o caractere zero), estará logo após do último caractere da string, marcando que a string terminou.

E o conceito de string se confunde com o array de caracteres. Na realidade, é um array de caracteres, e o que vai ditar se é uma string ou um array de caracteres banal é a forma com que o programador fez o código lidar com ela.

Então, se você quer armazenar uma string de um tamanho, com uma quantidade de caracteres, tem que acrescentar um caractere para armazenar o zero, o null, que marca o final da string. O array tem que ter o tamanho para caber a sua string e um caractere a mais para o nulo. Por exemplo, para armazenar 20 caracteres tem que criar um array de 21 caracteres.

char   *str[21] ;

Assim você pode armazenar os 20 caracteres que quer armazenar, e tem o espaço para o null que marca o fim desta string.

Tem como criar e trabalhar com strings sem ter que reservar um Byte a mais para o null? Tem sim, mas não é tão simples, prático, e eficiente.

Com esta definição de string mostrada acima, pode-se armazenar qualquer quantidade caracteres até 20 caracteres.

Existe um grande conjunto de funções para manipular strings, entre elas a strlen() que é usada para saber o tamanho da string. Mas nem sempre realmente queremos saber o tamanho da string. Tem vezes que queremos saber se ela tem alguma coisa, se não está vazia, como no exemplo abaixo.

if( strlen( str ) > 0 )
{
}

Se uma string tem 3 caracteres, mesmo que tenha sido alocado 21 caracteres para ela, o quarto caractere será nulo, e os outros 17 não terão importância. As funções de string irão parar o seu tratamento assim que encontrar o null, ignorando todo o resto.

E se a string tiver zero caracteres, nenhum caractere, o null estará no seu primeiro elemento, no primeiro elemento do array que a armazena. Em C todos os arrays começam pelo elemento de índice 0. Então um array de 21 caracteres tem seus índices válidos de 0 a 20. Tentar acessar fora da faixa gera riscos extraordinariamente loucos, e, em especial, aleatórios.

if( str[0] == '\0' ) // A string está vazia?
{
}

Assim podemos testar o primeiro caractere, e se este for null, que no exemplo acima é mostrado em uma das suas representações, como caractere. Se for null, a string está vazia, e não for, ela não está vazia, mas não se sabe o tamanho dela. Este é um teste simples, rápido, e bem direto. Tão direto que existe o risco de alguns programadores menos experientes não entenderem, portanto é aconselhável colocar comentários em casos assim.

Outra forma mais direta, que significa a mesma coisa, está abaixo.

if( str[0] ) // A string está vazia?
{
}

E como o zero, ou null, como resultado de uma operação lógica é false, e qualquer valor diferente de zero é verdadeiro, basta pegar o primeiro caractere da string. Se o primeiro caractere não for null, a string é maior que zero. Se for null a string é de tamanho zero.

Em analogia, se quer fazer uma ação se a string tiver tamanho zero:

if( strlen( str ) == 0 )
{
}

Pode ser substituído por:

if( ! str[0] )
{
}

Negamos o primeiro caractere da string, assim, se for null, o resultado do if será verdadeiro, se não for null, sera verdadeiro.

E como zeramos o conteúdo da string?

strcpy( str,"" );

Como o que tem depois do null, independente de sua posição, não tem importância, só precisamos atribuir null ao primeiro caractere.

str[0] = '\0' ; // Esvaziando a string.

Assim "limpamos" uma string de uma forma rápida e simples.

Os truques mostrado acima são bem eficientes, gerando menos código do que a chamada à função. Mas alguns compiladores, quando acham estas funções no código, já que elas são muito comuns, eles não colocam a chamada à elas, e sim, constroem o código delas nos pontos onde elas são chamadas. Isto é eficiente, pois permite fazer alguns atalhos, inclusive elimina todo o mecanismo de chamada e retorno da função. E, pelo que já vi em alguns compiladores, não duvido que alguns modifiquem os códigos para que fiquem parecidos com estes códigos alternativos ensinados acima. Mas não conte com isto. Não atribua uma inteligência ao compilador que deveria ser sua.

Nenhum comentário:

Postar um comentário