Mudanças entre as edições de "SOP-strings"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
Linha 109: Linha 109:
  
 
... o programa funcionará sem erros. A diferença é que a variável ''senha'' agora aponta a mesma região de memória que a variável ''memoria'', à qual foram previamente alocados 1024 bytes.
 
... o programa funcionará sem erros. A diferença é que a variável ''senha'' agora aponta a mesma região de memória que a variável ''memoria'', à qual foram previamente alocados 1024 bytes.
 +
 +
Para tornar explícito que variáveis ''string'' contém na verdade endereços de memória, veja o exemplo abaixo:
 +
 +
<syntaxhighlight lang=c>
 +
int main() {
 +
  char * senha;
 +
  char memoria[1024];
 +
 +
  printf("Variável memoria aponta a posição de memória %p\n", memoria);
 +
  printf("Variável senha aponta a posição de memória %p\n", senha);
 +
 +
  senha = memoria;
 +
 +
  printf("Agora a variável senha contém o endereço %p (deveria ser o mesmo que a variável memoria)\n", senha);
 +
 +
  printf("Digite a senha: ");
 +
  scanf("%s", memoria);
 +
 +
  printf("Voce digitou %s\n", senha);
 +
 +
}
 +
</syntaxhighlight>
 +
 +
Nos três primeiros ''printf''  foi usado um formato ''%p'', que serve para mostrar endereços de memória. Assim, esses ''printf'' mostram os endereços de memória que estão guardados nas variáveis ''memoria'' e ''senha'', e pode-se ver que incialmente eles são diferentes. Após a operação de atribuição, a variável ''senha'' passa a conter o mesmo endereço que está na variável ''memoria''. Outro detalhe interessante no programa reside na leitura da ''string'' pelo teclado, a qual é armazenada na região de memória apontada pela variável ''memoria''. Em seguida, o último ''printf'' mostra a ''string'' apontada pela variável ''senha'', e deve aparecer na tela exatamente a mesma ''string'' que foi lida do teclado, já que ''senha'' agora aponta a mesma região de memória que ''memoria''. Veja abaixo a execução desse programa:
 +
 +
> ./teste
 +
Variável memoria aponta a posição de memória 0x7fff7187d260
 +
Variável senha aponta a posição de memória (nil)
 +
Agora a variável senha contém o endereço 0x7fff7187d260 (deveria ser o mesmo que a variável memoria)
 +
Digite a senha: KABOOM!!!
 +
Voce digitou KABOOM!!!
 +
 +
  
 
== Iniciando e copiando ''strings'' ==
 
== Iniciando e copiando ''strings'' ==

Edição das 16h20min de 4 de dezembro de 2009

Strings na linguagem C

Uma variável string representa uma cadeia de caracteres (ou sequência de caracteres). A própria palavra string pode ser traduzida para cadeia, no sentido de um encadeamento de coisas. Como não existe um tipo de dados string na linguagem C, strings são representadas por vetores de caracteres.

int main() {
  char palavra[16];

  printf("Digite uma palavra de até 15 letras: ");
  scanf("%s", palavra);

  printf("Você digitou %s\n", palavra);
}

No exemplo acima, foi declarada uma variável string chamada palavra, que pode conter até 15 caracteres. A quantidade de caracteres de que pode ser composta uma string é sempre uma unidade a menos que a capacidade do vetor, porque uma posição do vetor é reservada para assinalar o final da string. Olhando como uma cadeia de caracteres fica armazenada no vetor ajuda a entender isto, imaginando que foi digitado Teste:

<graphviz> digraph Frase { Frase [shape=Mrecord,label="<0>T|<1>e|<2>s|<3>t|<4>e|<5>\\0|<6> |<7> |<8> |<9> |<10> |<11> |<12> |<13> |<14> |<15> |<16> "] palavra [shape=record] palavra -> Frase:0 } </graphviz>

No diagrama acima, a caixa intitulada palavra corresponde à variável palavra, e esta contém a localização em memória onde está a sequência de caracteres que compõe a string (diz-se que palavra aponta a posição de memória onde inicia a string) . Note que depois do último e há um caractere \0. A barra invertida significa que o número mostrado naquela posição do diagrama corresponde ao código ASCII do caractere. O caractere de código 0 (zero) representa na verdade um caractere nulo (não visível e que não representa nenhum caractere real), e no caso serve para indicar onde está o final de string. Assim, pode-se perceber que as demais posições da variável palavra não são usadas, apesar de estarem ali disponíveis.

Uma outra forma de declarar strings, mostrada abaixo, não aloca memória previamente para conter a cadeia de caracteres.

int main() {
  char * senha;

  senha = "kaboom";

  printf("A senha é %s (não espalhe !)\n", senha);

}

O interessante nessa segunda forma de declarar string é o tipo da variável:

char * senha;

Essa declaração explicita que a variável senha serve para guardar endereços de memória. Esse tipo de variável se chama ponteiro, porque serve para apontar posições de memória que contém um determinado dado. No exemplo acima, a variável senha pode apontar uma posição de memória que contém um dado do tipo char. Mas inicialmente ela não aponta nenhuma posição em particular, uma vez que não foi inicializada. Mas quando a seguinte linha for executada:

senha = "kaboom";

... essa variável passará a apontar a posição de memória onde se encontra a string constante "kaboom". Assim, a relação entre a variável senha e a constante "kaboom" pode ser representada pelo diagrama:

<graphviz> digraph Frase { Frase [shape=Mrecord,label="<0>k|<1>a|<2>b|<3>o|<4>o|<5>m|<6>\\0"] senha [shape=record] senha -> Frase:0 } </graphviz>

Não há diferença de fato entre a primeira figura, que mostra a string que foi guardada na variável palavra, e a figura acima. Ambas mostram que variáveis string apontam posições de memória onde estão sequências de caracteres. A única diferença qualitativa entre esses exemplos é que no primeiro foi alocada (reservada) uma região de memória capaz de conter 16 caracteres, e seu endereço foi armazenado na variável palavra, e no segundo caso a variável não teve memória associada a si, mas foi usada para apontar uma área de memória onde estava a string constante "kaboom".

Uma consequência do que foi mostrado acima é que deve-se ter cuidado ao tentar guardar strings em variáveis declaradas da forma:

char * senha;

... porque inicialmente uma variável como essa não aponta uma região de memória válida. Por exemplo, se o seguinte programa for compilado e executado:

int main() {
  char * senha;

  printf("Digite a senha: ");
  scanf("%s", senha);

  printf("Voce digitou %s\n", senha);

}

... um erro aparecerá na tela:

> ./erro
Digite a senha: kaboom
Segmentation fault

Esse erro indica que o processo tentou acessar uma área de memória inválida (que não foi previamente alocada). Mas se ele for modificado da seguinte forma:

int main() {
  char * senha;
  char memoria[1024];

  senha = memoria;

  printf("Digite a senha: ");
  scanf("%s", senha);

  printf("Voce digitou %s\n", senha);

}

... o programa funcionará sem erros. A diferença é que a variável senha agora aponta a mesma região de memória que a variável memoria, à qual foram previamente alocados 1024 bytes.

Para tornar explícito que variáveis string contém na verdade endereços de memória, veja o exemplo abaixo:

int main() {
  char * senha;
  char memoria[1024];

  printf("Variável memoria aponta a posição de memória %p\n", memoria);
  printf("Variável senha aponta a posição de memória %p\n", senha);

  senha = memoria;

  printf("Agora a variável senha contém o endereço %p (deveria ser o mesmo que a variável memoria)\n", senha);

  printf("Digite a senha: ");
  scanf("%s", memoria);

  printf("Voce digitou %s\n", senha);

}

Nos três primeiros printf foi usado um formato %p, que serve para mostrar endereços de memória. Assim, esses printf mostram os endereços de memória que estão guardados nas variáveis memoria e senha, e pode-se ver que incialmente eles são diferentes. Após a operação de atribuição, a variável senha passa a conter o mesmo endereço que está na variável memoria. Outro detalhe interessante no programa reside na leitura da string pelo teclado, a qual é armazenada na região de memória apontada pela variável memoria. Em seguida, o último printf mostra a string apontada pela variável senha, e deve aparecer na tela exatamente a mesma string que foi lida do teclado, já que senha agora aponta a mesma região de memória que memoria. Veja abaixo a execução desse programa:

> ./teste
Variável memoria aponta a posição de memória 0x7fff7187d260
Variável senha aponta a posição de memória (nil)
Agora a variável senha contém o endereço 0x7fff7187d260 (deveria ser o mesmo que a variável memoria)
Digite a senha: KABOOM!!!
Voce digitou KABOOM!!!


Iniciando e copiando strings