Por que as strings C são lentas e como os ponteiros as corrigem

2

C não se importa com strings. Na verdade.

Ele os trata como matrizes de caracteres. Apenas bytes na memória. Se quiser usá-los de maneira eficaz, você precisa de dicas. Não porque seja divertido. Mas porque sem eles, você está fazendo um trabalho extra.

Uma string em C é apenas char str[100]. Parece espaço para 100 caracteres. Não é. É espaço para 99 caracteres mais um terminador. C usa strings terminadas em nulo. Cada string termina com o valor ASCII 0. Escrito como '\0'.

Isso muda tudo.

Outras linguagens lidam com strings de maneira diferente. Pascal usa um byte de comprimento. Ele sabe exatamente quantos caracteres estão armazenados. Pergunte o comprimento? Ele retorna esse byte. Imediatamente.

C tem que contar. Ele lê até atingir '\0'. Isso torna C mais lento em alguns casos. Mais rápido em outros. Depende do que você está fazendo.

Não há suporte interno para strings em C. Você depende de bibliotecas. lida com entrada e saída como gets e puts. lida com manipulação. Alguns sistemas usam . Você tem que gerenciar a memória sozinho. Você não pode simplesmente atribuir um array a outro.

É isso. Você copia elemento por elemento. Ou você usa strcpy. A função de biblioteca faz o trabalho pesado.

strcpy está em todo lugar em C. Ele inicializa strings. Ele copia dados.

Após a execução, s1 contém “hello” e s2 contém “hello”. A matriz armazena valores ASCII. Inteiros. h é 104. e é 101. C pensa em bytes. Você pensa em texto. A máquina não se importa.

A comparação usa strcmp. Ele retorna um número inteiro.

Zero significa igual. Negativo significa que a primeira string é menor. Positivo significa que é maior.

Existem outras funções. strlen retorna comprimento. strcat concatena. Leia a página de manual se precisar de mais.

Mas como essas funções realmente funcionam nos bastidores? Vejamos strlen.

Uma abordagem ingênua é assim:

A maioria dos programadores C odeia isso. Parece ineficiente. Eles preferem ponteiros.

Você pode compactá-lo ainda mais.

Um verdadeiro especialista provavelmente poderia torná-lo mais curto.

Eu compilei isso em um MicroVAX com gcc. Sem otimização. Executado cada um 20.000 vezes em uma sequência de 120 caracteres.

Primeira versão: 12,3 segundos.
Segunda versão: 12,3 segundos.
Terceira versão: 12,9 segundos.

Os ponteiros nem sempre vencem.

Escreva um código que você entenda. A legibilidade é mais importante do que alguns microssegundos. A menos que você esteja em um circuito apertado. Então talvez otimize.

strcpy segue uma evolução semelhante.

Comece com o óbvio:

Observe o <=. Ele copia o '\0'. Se você pular, a string não terá fim. Comprimento desconhecido. Erros mais tarde. Difícil de encontrar.

Esta versão é ineficiente. strlen executa cada iteração. Ligue uma vez.

Agora dicas.

Comprima-o.

Limpo. Rápido. Perigoso se você não verificar os limites.

É assim que as cordas C funcionam. Sem mágica. Apenas memória e ponteiros. E muita contagem cuidadosa.

Ponteiros vs. Desempenho em strcpy

Você poderia escrever tecnicamente while (s1++ = s2++); para lidar com a cópia de strings. A diferença de desempenho entre implementações ingênuas e otimizadas é impressionante.

Pegue strcpy. A primeira versão leva 415 segundos para copiar uma sequência de 120 caracteres 10.000 vezes. A segunda versão? 14,5 segundos. O terceiro cai para 9,8 segundos. O quarto é fixado em 10,3 segundos.

Essa não é uma diferença marginal. É um grande impulso. Os ponteiros fornecem velocidade aqui porque evitam sobrecarga desnecessária.

Tipos de retorno e ponteiros de string

O protótipo de srcpy na biblioteca de strings revela sua intenção:

A maioria das funções de string retorna um ponteiro para uma string. strcpy retorna o valor de s1 como resultado. Isso permite operações de encadeamento ou uso imediato da string copiada sem uma segunda pesquisa.

Removendo espaços em branco iniciais sem mover dados

Usar ponteiros com strings geralmente resulta em melhorias definitivas na velocidade. Você pode tirar vantagem disso se pensar um pouco sobre eles.

Suponha que você queira remover espaços em branco iniciais de uma string. O instinto é mudar os caracteres, substituindo os espaços em branco. Em C, você pode evitar completamente o movimento.

Isso é muito mais rápido que a técnica de movimento. Especialmente para cordas longas. Você não está mudando bytes. Você está apenas alterando o ponteiro inicial. Os dados permanecem inalterados. A saída muda.

Pegando truques

Você aprenderá muitos outros truques com cordas à medida que avança. Você lerá outro código. Você verá como os outros lidam com a memória.

A prática é a chave. Não há atalho para leitura de código. Basta ver como isso é feito e entender por que funciona. Os ganhos de desempenho são reais. A curva de aprendizado é íngreme. Mas os resultados falam por si.