Entendimento e uso de variáveis em C# Variáveis representam locais de memória nos quais seus programas podem armazenar valores e acessá-los e/ou modificá-los durante a execução. Confuso? Vamos analisar melhor este cenário. Toda vez que você executa um aplicativo, o sistema operacional carrega as instruções deste programa para a memória principal de seu computador. Durante o processamento das diversas funções e cálculos, este aplicativo precisa armazenar valores temporariamente. Sem entrar em discussões técnicas sobre o funcionamento de hardware e memórias, podemos dizer que a memória principal de seu computador é dividida em posições de memória, cada posição possuindo um endereço único. Veja a ilustração a seguir: Ora, não seria nada prático acessar estas posições de memória usando seus endereços (representados por valores inteiros hexadecimais). Dependendo da quantidade de memória principal disponível, estes endereços podem chegar à casa dos bilhões. Em vez disso as linguagens de programação usam apelidos para estas posições de memória. Tais apelidos são conhecidos como variáveis. Uma variável possui cinco atributos muito importantes. São eles: 1) Nome – É o nome que identificará a variável. Este nome deve ser único dentro de seu escopo (espaço de atuação), ou seja, nada impede que classes e métodos tenham nomes semelhantes àqueles encontrados em outras classes e métodos. 2) Valor – É o valor contido na variável. Veremos mais adiante como atribuir ou alterar os valores contidos em variáveis. 3) Tipo – É o tipo de dados que será armazenado nas variáveis. Tipos de dados podem ser inteiro, string (texto), números de ponto flutuante, etc. Tipos de dados serão vistos mais adiante. 4) Visibilidade ou escopo – É o alcance de visibilidade, ou seja, os locais a partir dos quais esta variável poderá ser acessada pelas diversas partes do código. A discussão sobre escopo de variáveis será adiada até a nossa analise de classes, métodos e estruturas de repetição. 5) Endereço – Cada variável possui um endereço único. Este atributo terá sua importância destacada quando abordarmos código não seguro (unsafe code) usando ponteiros. Agora que já sabemos o suficiente sobre variáveis, vamos escrever um aplicativo exemplificando seu uso. Considere a listagem a seguir: using System; class Variaveis { static void Main() { int valor; valor = 10; Console.WriteLine("O valor é: {0}", valor); valor = 20; Console.WriteLine("O valor foi alterado para: {0}", valor); } } Compile este exemplo e observe o resultado de sua execução. Você terá as seguintes mensagens: O valor é: 10 O valor foi alterado para: 20 Vamos entender o que aconteceu aqui. Dentro do método Main temos a declaração de uma variável do tipo inteiro chamada valor. Em seguida atribuímos o valor 10 à esta variável. Tipos de dados serão vistos mais adiante. O operador de atribuição será apresentado na parte 3. A linha seguinte faz uso do método WriteLine da classeConsole para exibir o valor desta variável no console: Console.WriteLine("O valor é: {0}", valor); Aqui temos uma construção que merece muita atenção. Observe o símbolo {0} dentro das aspas ao redor do texto a ser exibido. Este símbolo é um lugar de marcação para os valores das variáveis localizadas após a vírgula. Atente para o fato de que você poderá ter um número ilimitado de nomes de variáveis após a vírgula e seus valores poderão ser exibidos usando {0}, {1}, {2} e assim por diante. A quarta linha do código: valor = 20; atribui um novo valor à variável valor. Para finalizar, uma nova chamada ao métodoWriteLine exibe o novo valor no console. A diferença entre declaração e definição de variáveis Para um perfeito entendimento e uso de variáveis, é necessário perceber uma sutil diferença entre declaração e definição de variáveis. Vejamos o significado de cada uma nas linhas seguintes. A declaração de uma variável informa o compilador sobre seu nome e seu tipo. Veja uma linha de código que declara uma variável chamada idade: int idade; A definição ou inicialização de variáveis ocorre quando as células de memória necessárias ao armazenamento destas variáveis são alocadas. Veja, por exemplo, um trecho de código que declara uma variável e em seguida a inicializa: int idade; idade = 20; Dependendo do contexto em que uma variável é declarada, o compilador a inicializa automaticamente com um valor padrão para o tipo de dados. Porém, variáveis locais nunca são inicializadas automaticamente. Uma variável local é uma variável declarada dentro de métodos e alguns outros blocos de código. Para demonstrar como o compilador C# se comporta quando uma variável local é declarada, mas ainda não definida (inicializada), vamos escrever o seguinte aplicativo: using System; class Variaveis { static void Main() { int idade; Console.WriteLine("Idade: {0}", idade); } } Este código está disponível no arquivo Variaveis2.cs. Experimente compila-lo e verá a seguinte mensagem de erro: Variaveis2.cs(9,37): error CS0165: Use of unassigned local variable 'idade' Esta mensagem de erro ocorreu porque a variavel idade foi declarada dentro do métodoMain do aplicativo e, portanto, é uma variável local. Variáveis locais devem sempre ser inicializadas antes de serem usadas. Observação C# permite que a declaração e definição de uma variável sejam feitas em apenas uma linha. Assim, é perfeitamente legal escrever o trecho de código seguinte: int idade; idade = 20; em uma forma mais reduzida: int idade = 20; Como usar constantes em C# Vimos no tópico anterior que variáveis podem ter seus valores alterados durante a execução do programa. Existe um tipo de variável que não permite que seu valor seja alterado após sua definição. Em C# esta variável é declarada com a palavra-chaveconst. Veja um exemplo de declaração e inicialização de uma constante cujo valor é um numero inteiro: const int idade = 30; Vamos escrever um aplicativo que demonstra o que acontece quando tentamos alterar o valor de uma constante declarada e já inicializada: using System; class Constantes { static void Main() { const int idade = 30; idade = 45; // causa erro de compilação Console.WriteLine("Idade: {0}", idade); } } Salve esta listagem como Constantes.cs. Ao tentarmos compilar este código obtemos a seguinte mensagem de erro: Constantes.cs(9,5): error CS0131: The left-hand side of an assignment must be a variable, property or indexer Esta mensagem nos diz que o lado esquerdo de uma operação de atribuição deve ser uma variável, propriedade ou indexer. Propriedades e indexers serão vistos nas próximas partes do curso. Vamos escrever um aplicativo que demonstra o que acontece quando tentamos alterar o valor de uma constante declarada e já inicializada: using System; class Constantes { static void Main() { const int idade = 30; idade = 45; // causa erro de compilação Console.WriteLine("Idade: {0}", idade); } } Salve esta listagem como Constantes.cs. Ao tentarmos compilar este código obtemos a seguinte mensagem de erro: Constantes.cs(9,5): error CS0131: The left-hand side of an assignment must be a variable, property or indexer Esta mensagem nos diz que o lado esquerdo de uma operação de atribuição deve ser uma variável, propriedade ou indexer. Propriedades e indexers serão vistos nas próximas partes do curso. Vamos escrever um aplicativo que demonstra o que acontece quando tentamos alterar o valor de uma constante declarada e já inicializada: using System; class Constantes { static void Main() { const int idade = 30; idade = 45; // causa erro de compilação Console.WriteLine("Idade: {0}", idade); } } Salve esta listagem como Constantes.cs. Ao tentarmos compilar este código obtemos a seguinte mensagem de erro: Constantes.cs(9,5): error CS0131: The left-hand side of an assignment must be a variable, property or indexer Esta mensagem nos diz que o lado esquerdo de uma operação de atribuição deve ser uma variável, propriedade ou indexer. Propriedades e indexers serão vistos nas próximas partes do curso. Regras e dicas para a escolha de nomes de variáveis e constantes Agora que você já sabe como usar variáveis e constantes em seus programas C#, é hora de aprender um pouco sobre as regras impostas pela linguagem em relação aos nomes que você poderia escolher para seus identificadores: a) O nome de um identificador pode conter apenas letras, dígitos e o caractere de sublinhado (_); b) O primeiro caractere deve obrigatoriamente ser uma letra. Ainda que o caractere de sublinhado seja permitido, seu uso não é recomendado devido ao fato de tornar o código mais difícil de ser entendido; c) O C# diferencia minúsculas de maiúsculas. Desta forma, CLIENTE, Cliente e cliente são identificadores distintos; d) Palavras-chave não podem ser usadas como identificadores. O tópico a seguir lista todas estas palavras em ordem alfabética. Para reforçar estas regras veja uma lista de identificadores considerados válidos: int valor; string _nomeCliente; float ValorTotal; double a3; short numero_conta; Os identificadores a seguir são considerados inválidos: string #nomeDoCliente; float 1_Valor; int $aumento; Existe um consenso entre programadores e autores que os nomes de constantes devam ser escritos usando apenas letras maiúsculas. Essa pratica é comum nas linguagens C, C++ e Java. Com freqüência você verá este estilo de nomeação sendo aplicado também em C#. Fique à vontade para escolher seu estilo. As observações nestas próximas linhas não são exigências, mas, uma forma de estimular o leitor a se adequar ao estilo de programação de vários programadores experientes ao redor do mundo. A primeira observação é o uso de letras minúsculas para os nomes de variáveis. Esta pratica é comum nas linguagens C, C++ e Java. Se o nome da variável for composto de mais de uma palavra, você pode adotar o que é conhecido como notaçãoCamel. Em tal notação o nome da variável seria nomeCliente (com a primeira palavra iniciando com letras minúsculas e as demais palavras iniciando com letras maiúsculas). Quando se trata de nomes de classes, métodos, interfaces e outros elementos da linguagem C#, é comum a adoção da notação Pascal. Neste estilo a inicial de cada palavra é escrita com letra maiúscula. Assim, uma classe que representa um relatório de vendas poderia ser nomeada RelatorioVendas. Este curso adota a notação Camel para variáveis e constantes e a notação Pascal para classes, interfaces e demais elementos. Palavras-chave e palavras reservadas da linguagem C# Palavras-chave são palavras que têm um significado especial para o compilador. Palavras reservadas são palavras que não estão em uso agora, mas há a chance de que estas possam ser incluídas na linguagem posteriormente. Em todo caso, você não poderá usar nenhuma das palavras listadas abaixo para nomear variáveis e constantes em seus códigos. Esta lista de palavras-chave consta da documentação da linguagem C# presente no framework .NET versão 1.1. abstract event new struct as explicit null switch base extern object this bool false operator throw break finally out true byte fixed override try case float params typeof catch for private uint char foreach protected ulong checked goto public unchecked class if readonly unsafe const implicit ref ushort continue in return using decimal int sbyte virtual default interface sealed volatile delegate internal short void do is sizeof while double lock stackalloc else long static enum namespace string Tipos de dados numéricos Agora que você já sabe como declarar variáveis e constantes, é hora de saber quais os tipos de dados que você pode usar eu seus aplicativos. Nos exemplos anteriores vimos que uma variável é declarada seguinte o modelo: Tipo_de_dados nome_da_variável Em alguns de nossos exemplos aprendemos a declarar variáveis do tipo inteiro usando a palavra chave int. int é parte de uma lista de tipos conhecidos como built-in types, ou seja, tipos de dados pré-definidos na linguagem. Os tipos de dados em C# podem ser divididos em quatro categorias: integrais,números de ponto-flutuante, decimal e boolean. Na categoria dos tipos de dados integrais (tipos que não apresentam partes fracionárias) temos os constantes na tabela seguinte: Tipo Faixa de Valores Tamanho sbyte -128 até 127 8 bits byte (sem sinal) 0 até 255 char (unicode) U+0000 até U+ffff 16 bits short -32.768 até 32.767 16 bits ushort (sem sinal) 0 até 65.535 16 bits int -2.147.483.648 até 2.147.483.647 32 bits uint (sem sinal) 0 até 4.294.967.295 32 bits long -9.223.372.036.854.775.808 até 9.223.372.036.854.775.807 64 bits ulong (sem sinal) 0 até 18.446.744.073.709.551.615 64 bits 8 bits Com certeza o leitor deve estar se perguntando qual é a real necessidade de se conhecer a faixa de valores possíveis e a quantidade de bits ocupados por um determinado tipo de dados. E qual é a diferença entre um tipo sinalizado (sbyte) de um tipo não sinalizado (byte)? A razão pela qual este curso apresenta tais informações ficará clara à medida que você progredir com seus estudos, não somente da linguagem C#, como também de outras linguagens e técnicas de programação. O apêndice A "Sistemas de Numeração" mostra a você os passos necessários para converter valores entre os sistemas decimais, binário, octal e hexadecimal. Fique à vontade para consultar este apêndice caso a explicação que faremos a seguir se torne um pouco confusa neste estágio do estudo. Inicialmente tomemos o valor 100 no sistema de numeração decimal. Convertendo este valor para o sistema de numeração binário temos 1100100. Suponha que decidíssemos armazenar este valor em uma variável do tipo sbyte (com sinal). Ora, como sabemos que este tipo de dados ocupa 8 bits, ou seja, 1 byte de memória, teríamos o cenário reproduzido na figura seguinte: Lembre-se do cálculo: 64 + 32 + 4 = 100. Como podemos ver na figura, o bit mais significativo (na cor cinza) deste byte é usado para sinalizar se o valor é positivo ou negativo. Se o bit mais significativo for 0, valor é positivo. Se for 1, o valor é negativo. Então, como este bit tem essa função exclusiva para os tipos de dados sinalizados, resulta que teremos apenas 7 bits para armazenar os valores desejados. Assim, se tivermos todos estes 7 bits com valores 1 e apenas o bit mais significativo com o valor 0: 0111 1111 chegaremos à conclusão de que o valor máximo a ser armazenado é realmente 127 (64 + 32 + 16 + 8 + 4 + 2 + 1 = 127). Tomemos agora o tipo de dados byte (sem sinal). Como este tipo de dados só armazenará valores positivos, não há a necessidade de se usar o bit mais significativo como sinalizador. Em vez disso, ele é considerado parte dos bits de dados e voltamos novamente a ter 8 bits à nossa disposição. Assim: 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255 Com este cálculo provamos que o tipo byte pode realmente armazenar valores que variarão de 0 a 255. O mesmo cálculo pode ser usado para os outros tipos de dados. Experimente efetuar este processo com os tipos de dados short (aceita valores positivos e negativos) e ushort (aceita somente valores positivos). Voltemos nossa atenção agora para os tipos de dados capazes de armazenar números depontoflutuante, ou seja, números que contêm partes fracionárias. C# fornece os tiposfloat e double. Veja suas características na tabela seguinte: Tipo float double Faixa de Valores Precisão Tamanho 1.5x10-45 até 3.4x1038 7 dígitos 32 bits 15-16 dígitos 64 bits -324 5.0×10 308 até 1.7×10 Para que você realmente entenda as faixas de valores e precisão dos tipos de dadosfloat e double, acrescentamos as seguintes observações: a) 1038 equivale a multiplicar o valor 10 por ele mesmo 37 vezes. O resultado será o numero 1 seguido de 38 zeros. 10-45 equivale a dividir o valor 10 por ele mesmo 44 vezes. O resultado será uma vírgula seguida pelo numero 1 precedido de 44 zeros. b) A precisão de um tipo de dados é a quantidade de dígitos que poderão ser representados como casas decimais, ou seja, a quantidade de dígitos significativos após a vírgula. Se o calculo realizado exceder a quantidade de dígitos permitidos após a vírgula, haverá arredondamento para o inteiro mais próximo. Use o tipo de dados double quando você estiver realizando cálculos que exigem um pouco mais de precisão no tocante às casas decimais. O tipo de dados float é usado quando um possível arredondamento não trará resultados indesejados ao resultado final. Existe, no entanto, uma opção quando o cálculo exige uma precisão levada ao extremo, por exemplo, em aplicações financeiras. Para estes cálculos o C# nos fornece o tipo de dados decimal. Veja suas características na tabela seguinte: Tipo decimal Faixa de Valores 1.0x10 -28 28 até 7.9x10 Precisão Tamanho 28 dígitos 128 bits Os tipos de dados char, string e referência Na tabela dos tipos integrais (tipos que não suportam partes fracionárias) tivemos a inclusão do tipo de dados char. A inclusão deste tipo na tabela citada se dá por questões acadêmicas. Na verdade, se você tentar atribuir um valor numérico a um char, como no exemplo seguinte: char letra = 45; você obterá, em tempo de compilação, a seguinte mensagem de erro: Char.cs(7,18): error CS0031: Constant value '45' cannot be converted to a 'char' Esta mensagem nos diz que o valor 45 não pode ser convertido para um char. Uma alternativa é efetuar uma conversão explicita de dados usando um artifício conhecido como casting (e que será estudado mais adiante). Veja uma nova versão do exemplo anterior: char letra = (char) 71; Ao executar esta linha de código o valor 71 é convertido para o caractere Unicode correspondente e ele é atribuído à variável letra. Para que você veja o resultado, considere a listagem seguinte: using System; class Caractere { static void Main() { char letra = (char) 71; Console.WriteLine("A letra é: {0}", letra); } } Este código está disponível no arquivo Char.cs. Compile-o e, ao executa-lo você terá o seguinte resultado: A letra é: G Caracteres em C# ocupam 16 bits (2 bytes). Isso quer dizer que seus programas poderão exibir caracteres cujos códigos variarão de 0 até 65.535, ou seja, os caracteres e símbolos da maioria das linguagens já conhecidas. O apêndice B "Conjunto de Caracteres ASCII" servirá como referência quando você precisar consultar o código decimal que representa um determinado caractere. O tipo de dados char é usado quando precisamos trabalhar com texto de forma separada, ou seja, um caractere por vez. Quando dois ou mais caracteres precisam ser representados, entra em cena um tipo de dados comum a quase todos os aplicativos já desenvolvidos. Este tipo de dados se chama string. O tipo de dados string é um tipo de referência, ou seja, todas as vezes que uma variável deste tipo é declarada em seus programas, o que temos na verdade é uma referência a um objeto que encapsula um conjunto de caracteres. Mas, como objetos serão vistos mais adiante, vamos apenas escrever um exemplo que demonstra seu uso. Considere a listagem seguinte: using System; class Leitura { static void Main() { string nome; Console.WriteLine("Digite seu nome:"); nome = Console.ReadLine(); Console.WriteLine("Seu nome é: {0}", nome); } } Compile este código e experimente executa-lo. Você verá uma mensagem solicitando que digite seu nome. Ao digitar seu nome e pressionar Enter uma nova mensagem confirma o valor informado. Vamos ver como isso aconteceu. O primeiro passo foi declarar uma variável do tipo string: string nome; Em seguida temos uma chamada ao método WriteLine da classe Console para exibir a mensagem que sugere a digitação do nome: Console.WriteLine("Digite seu nome:"); O próximo passo é obter o valor que foi digitado. Isso é feito com o método ReadLine da classe Console, que atribui à variável nome, todo o conteúdo digitado pelo usuário antes de pressionar a tecla Enter: nome = Console.ReadLine(); Para finalizar exibimos o resultado: Console.WriteLine("Seu nome é: {0}", nome); C# não aplica restrições à quantidade de caracteres que podem estar contidos em uma string. A documentação oficial nos informa que esta quantidade pode variar de 0 à 2 bilhões de caracteres Unicode. Se sabemos que cada caractere ocupa 16 bits (2 bytes), então podemos afirmar que nossas strings poderão ser tão longas quanto a memória principal disponível suportar. Antes de prosseguirmos tenha em mente que string é um tipo de dados referência a objetos. Outros tipos de referência são object, class, interface e delegate. Estes tipos serão apresentados mais adiante. Entendendo o tipo de dados bool O tipo de dados bool é usado quando queremos atribuir apenas os valores true ou falsea uma variável. Uma contração da palavra boolean (presente em muitas linguagens), este tipo ocupa apenas um bit de memória e seu uso pode ser exemplificado na listagem seguinte: using System; class Boolean { static void Main() { bool aprovado = true; Console.WriteLine("Foi aprovado: {0}", aprovado); } } Este código está disponível no arquivo Boolean.cs. Ao executá-lo temos o seguinte resultado: Foi aprovado: True Experimente alterar o valor da variável aprovado para false e veja o resultado. Literais Este tópico aborda literais e a importância de se entender e usar corretamente este recurso, presente em praticamente todas as linguagens de programação. Cabe, no entanto, uma observação. Você não precisa, obrigatoriamente, ler o conteúdo deste tópico antes de prosseguir com o estudo das demais partes. Mas, caso o faça, é importante escrever e compilar alguns exemplos a fim de entender o funcionamento de cada literal apresentado e observar o comportamento do compilador C# em algumas situações que passariam despercebidas aos olhos dos iniciantes em programação. Um literal é um valor que definimos quando escrevemos nosso código, ou seja, é o oposto de um valor que poderia ser calculado e atribuído a uma variável em tempo de execução. Desta forma, estivemos usando literais na maioria dos exemplos apresentados até este momento. Observe o seguinte trecho de código: bool aprovado = true; Aqui true é um literal do tipo bool (boolean) sendo atribuído à variável aprovado. Outro exemplo de literal poderia ser um literal string, mostrado a seguir: string site; site = "Arquivo de Códigos"; Lembre-se de que um literal string pode conter seqüências de escape (ilustradas mais adiante neste tópico). Desta forma, podemos causar uma quebra de linha em uma string de forma bem fácil. Veja um exemplo: string frase = "Número 1\nNúmero 2"; A saída deste exemplo será: Número 1 Número 2 Como podemos ver, uma quebra é causada pela inserção da seqüência "\n" no ponto onde desejamos que a quebra de linha ocorra. Quando falamos de literais do tipo boolean e string, tudo é muito simples e sob controle. A atenção deve ser redobrada quando estamos lidando com literais integrais e depontoflutuante. Comecemos com os literais integrais. Primeiramente veja o que acontece quando tentamos atribuir um valor maior que aquele permitido a um determinado tipo de dados: byte valor = 400; Ora, como sabemos que o máximo valor que pode ser armazenado em uma variável do tipo byte é 255, é de se esperar que esta definição fosse rejeitada pelo compilador, uma vez que o literal 400 é no mínimo do tipo short. E é isso que acontece. Veja a mensagem de erro de compilação que nos é exibida: Numero.cs(7,18): error CS0031: Constant value '400' cannot be converted to a 'byte' Existem algumas regras bem fáceis de serem entendidas quando estamos lidando com literais integrais. Vamos a elas: 1) Literais integrais podem ser definidos em dois tipos de sistemas de numeração: decimal e hexadecimal. Para definir um literal integral em hexadecimal, seu valor deverá ser precedido pela seqüência "0x". Veja um exemplo: int valor = 0x43; Ao exibirmos o valor da variável usando a forma que já conhecemos, veremos que o valor exibido é 67, ou seja, o valor hexadecimal é convertido para decimal antes de ser exibido. Nos próximos capítulos você aprenderá como exibir valores de variáveis em hexadecimal usando as opções de formatação de string. 2) Se o valor do literal for maior que aquele suportado pelo tipo de dados da variável a qual este valor será atribuído, um erro de compilação ocorrerá. O maior valor definido para um literal integral não poderá ser superior ao maior valor suportado pelo tipoulong. 3) Se o literal não possui sufixo, ele será do primeiro tipo que suportar seu valor, seguindo a ordem: int, uint, long, ulong. 4) Se o literal possui o sufixo U ou u, ele será do primeiro tipo que suportar seu valor, seguindo a ordem: uint, ulong. Lembre-se de que os sufixos U ou u são usados para definir um literal integral sem sinal. Veja um exemplo: uint valor = 143U; 5) Se o literal possui o sufixo L ou l (letra "L" minúscula), ele será do primeiro tipo que suportar seu valor, seguindo a ordem: long, ulong. Para facilitar a leitura do sufixo, encorajamos o uso apenas do sufixo L (a letra "L" minúscula se parece muito com o numero 1). Veja um exemplo deste tipo de literal: long valor = 623465L; 6) Se um literal possui os sufixos UL, Ul, uL, ul, LU, Lu, lU ou lu, ele será do tipo ulong. Por ora você não encontrará nenhuma aplicação prática dos conceitos apresentados nesta parte do texto. Porém, procure, sempre que puder rever estas anotações. Elas serão muito úteis durante o seu desenvolvimento. Veja agora uma das situações clássicas de erro de compilação envolvendo literais. Observe o trecho de código a seguir: float valor = 6.2; A primeira vista esta definição está correta. Temos um literal de ponto flutuante sendo atribuído a uma variável do tipo float. Porém, ao tentarmos a compilação obtemos a seguinte mensagem de erro: Valores.cs(7,19): error CS0664: Literal of type double cannot be implicitly converted to type 'float'; use an 'F' suffix to create a literal of this type Esta mensagem de erro nos avisa que um literal do tipo double não pode ser implicitamente convertido para o tipo float. E sugere que usemos o sufixo F após o valor do integral. Façamos isso então: float valor = 6.2F; Ao tentar compilar o código novamente vemos que a mensagem de erro se foi. Desta experiência concluímos que: 1) Se o literal de ponto-flutuante não possuir sufixo, ou possuir os sufixos D ou d, ele será do tipo double. 2) Se o literal possuir os sufixos F ou f, ele será do tipo float. 3) Se o literal possuir os sufixos M ou m, ele será do tipo decimal. De posse desta informação, nem precisamos de muito esforço para saber que o trecho de código: decimal valor = 40.5; resultará em um erro de compilação, mesmo sabendo que uma variável do tipo decimalpode perfeitamente acomodar o valor de um literal do tipo double. Literais do tipo char podem ser definidos usando-se aspas simples em torno do caractere desejado. Veja um exemplo: char letra = 'A'; Outra forma de fornecer um valor a um literal char é usar valores inteiros na faixa que vai de 0 até 65.535 (lembre-se de que o tipo char ocupa 16 bits na memória e não possui sinal). Veja um exemplo: char letra = (char ) 104; Esta técnica foi exemplifica no tópico "Os tipos de dados char, string e referência". Existe, no entanto, uma outra forma de atribuir valores a um literal char. Esta forma não é tão freqüente e consiste em atribuir ao literal o caractere desejado usando-se um valor hexadecimal que representa o valor Unicode do caractere. Este valor deverá ser precedido por "\n". Veja um exemplo: char letra = '\u0067'; Aqui o literal letra conterá a letra "g". O apêndice A "Sistemas de Numeração" mostrará a você como converter entre os sistemas de numeração decimais e hexadecimais. Para finalizar vamos analisar as seqüências de escape disponíveis na linguagem C#. Veja a tabela a seguir: Sequencia Nome do Caractere Valor Unicode \' Aspas Simples 0x0027 \" Aspas Duplas 0x0022 \\ Barra Invertida 0x005C \b Retrocesso 0x0008 \f Avanço de Página 0x000C \n Nova Linha 0x000A \r Voltar 0x000D \t Tabulação Horizontal 0x0009 \v Tabulação Vertical 0x000B Esta tabela de seqüências de escape tem sua importância compreendida quando precisamos exibir frases que contém aspas simples ou duplas. Por exemplo, se quiséssemos exibir a seguinte frase: Então ela falou: "Estou muito cansada" A maneira usual seria escrever um trecho de código assim: string frase = "Então ela falou: "Estou muito cansada""; Porém, ao tentarmos executar tal código temos uma mensagem de erro semelhante à mostrada a seguir: testes.cs(7,39): error CS1002: ; expected testes.cs(7,51): error CS1002: ; expected testes.cs(7,58): error CS1002: ; expected Esta mensagem de erro não ajuda em nada. Mas, já sabemos o que fazer. Basta "escapar" as aspas internas. Veja como o código deve ser escrito: string frase = "Então ela falou: \"Estou muito cansada\""; Como usar corretamente o método Main com ou sem argumentos Todo programa C# tem um ponto de entrada, que é um método Main definido na classe principal, ou seja, a classe responsável por controlar o fluxo de execução do programa. Em todos os exemplos que escrevemos até este momento, vimos o método Main com a seguinte assinatura: static void Main() { // mais linhas de código aqui } A palavra static é um modificador que pode ser usado com classes, métodos, variáveis, etc, e será abordado mais adiante. Apenas para que você não siga desinformado, saiba que um método definido com este modificador pode ser acessado sem que uma instância da classe na qual o método foi definido precise ser criada. A palavra void é usada para indicar que o método não retorna nenhum valor após a sua execução. Como você aprenderá mais adiante, métodos podem retornar todos os tipos de dados que estudamos, incluindo referencias a tipos de dados definidos pelo usuário. É comum em C# uma assinatura do método Main que retorna um inteiro. Veja um exemplo: using System; class VoidPorInt { static int Main() { Console.WriteLine("Trocando void por int"); return 0; } } Este código está disponível no arquivo VoidPorInt.cs. Veja que agora o método Mainretorna um valor inteiro. Observe também o uso da instrução return como ultima linha a ser executada. Em C e C++, ao retornarmos o valor 0 para o sistema operacional estamos informando-o que a execução e encerramento do programa ocorreu sem maiores problemas. Experimente agora substituir int por void novamente. Ao tentar compilar o código você verá a seguinte mensagem de erro: VoidPorInt.cs(9,5): error CS0127: Since 'VoidPorInt.Main()' returns void, a return keyword must not be followed by an object expression Esta mensagem nos diz que, uma vez que o metodo Main está retornando void (nada), a palavra-chave return não deve ser seguida por uma expressão. Troque: return 0; por return; e compile o código novamente. Você verá que agora a mensagem de erro não é exibida. Esta experiência nos mostra que, quando um método define void como seu tipo de retorno, o compilador fará o possível para que esta regra seja obedecida. É possível usar o método Main para fornecer valores ao programa via linha de comando. Para tanto você deve usar a seguinte assinatura: static void Main(string[] args) { // mais código aqui } Aqui nos temos um parâmetro para o método Main. Este parâmetro é um array do tipo string. Arrays são estruturas de dados que consistem em itens de dados relacionados do mesmo tipo e indexados com valores inteiros maiores ou igual a 0. Os valores fornecidos na linha de comando são separados por espaços e acessados usando-se args[0], args[1], args[2] e assim por diante. Veja um exemplo onde o usuário informa seu primeiro nome e idade na linha de comando do programa: using System; class LinhaComando { static void Main(string[] args) { Console.WriteLine("Seu primeiro nome é {0} e você tem {1} anos", args[0], args[1]); } } Este código está disponível no arquivo LinhaComando.cs. Após sua compilação experimente executa-lo usando os seguintes argumentos: LinhaComando Augusto 21 Você obterá o seguinte resultado: Seu nome é Augusto e você tem 21 anos Experimente informar seu nome completo e a idade na linha de comando. Poderia ser algo assim: LinhaComando Augusto Santos de Souza 21 Após a execução você concordará comigo que o resultado não foi o que esperávamos. Mas pode ser contornado. Basta informar o nome completo entre aspas duplas. Assim: LinhaComando "Augusto Santos de Souza" 21 Arrays e as técnicas usadas para evitar erros em tempo de execução, como aquele causado quando você tentar executar estes exemplos recentes sem fornecer valores na linha de comando, serão estudados mais adiante. Introdução às interfaces gráficas do C# Até este ponto de nosso estudo, todos os resultados da execução de nossos exemplos foram exibidos no console, em modo texto. Acreditamos que este seja o momento adequado para fazermos uma introdução às capacidades gráficas do C#. O próximo programa mostrará a você como fazer uso da classe MessageBox (que está sob o namespace System.Windows.Forms) para exibir mensagens mais amigáveis em seus programas. Considere a listagem a seguir: using System.Windows.Forms; class Mensagem { static void Main(string[] args) { string frase = "Este é um exemplo do uso da classe MessageBox"; MessageBox.Show(frase, "Meu Aplicativo"); } } Este código está disponível no arquivo Mensagem.cs. Compile-o e experimente executá-lo. Você a seguinte caixa de mensagem: O método Show da classe MessageBox possui uma grande variedade de parâmetros. Para este exemplo escolhemos os parâmetros que permitem definir os textos para a mensagem e para o título da caixa de mensagem: MessageBox.Show(string text, string caption) Como exercício recomendamos que você investigue os demais parâmetros deste método na documentação da plataforma .NET. Dicas & Truques C# static void Main(string[] args) { // cria e inicializa um array de strings string[] cidades = {"Goiânia", "São Paulo", "Rio de Janeiro", "Curitiba"}; Console.WriteLine("Ordem original:"); for (int i = 0; i < cidades.Length; i++) Console.WriteLine(cidades[i]); StringComparer ordenar = StringComparer.CurrentCultureIgnoreCase; Array.Sort(cidades, ordenar); Console.WriteLine(); Console.WriteLine("Ordem alfabética:"); for (int i = 0; i < cidades.Length; i++) Console.WriteLine(cidades[i]); // pausa o programa Console.ReadKey(); } Palavras-chaves: de, o, =, ordenar, ; , args, alfabética, original, e, int, strings , , WriteLine, Sort, programa , Paulo", pausa, , cria, <, inicializa, Console, Main, ; , ", 0;, cidades, StringComparer, Array, ReadKey, "Ordem, CurrentCultureIgnoreCase; , void, "Rio, "Goiânia", Length;, i++, array, i, "São, "Curitiba", string, Janeiro", um, for, static Como criar, atribuir valores e percorrer um array de duas dimensões em C# static void Main(string[] args) { // cria um array de duas dimensões: 4 linhas // e duas colunas int[,] matriz = new int[4, 2]; // atribui o valor 15 para a célula na // primeira linha e primeira coluna matriz[0, 0] = 15; // atribui o valor 30 para a célula na // quarta linha e segunda coluna matriz[3, 1] = 30; // imprime a matriz for (int i = 0; i <= matriz.GetUpperBound(0); i++) { for (int y = 0; y <= matriz.GetUpperBound(1); y++) { Console.Write(matriz[i, y] + " "); } Console.WriteLine(); } // pausa o programa Console.ReadKey(); } Palavras-chaves: imprime, na , programa , 30; , +, Write, ; , pausa, primeira, quarta, args, 15; , 2, int, o, um, array, linhas , duas, e, i++, 1, 0, coluna , matriz, , 15, i, ; , valor, para, 4, ;, GetUpperBound, linha, <=, , WriteLine, Main, string, colunas , a, new, , de, 0;, ", segunda, 30, matriz , atribui, y++, static, dimensões, void, =, for, cria, ReadKey, y, 3, Console, célula Como escrever um método C# que retorna um array (matriz) Em algumas situações precisamos escrever um método C# que retorna uma matriz. Esta dica mostra como isso pode ser feito: static void Main(string[] args){ // vamos obter um array do método abaixo int[] valores = obterValores(); // vamos imprimir o conteúdo do array obtido for(int i = 0; i < valores.Length; i++){ System.Console.WriteLine(valores[i]); } // pausa o programa System.Console.Write("\nPressione qualquer tecla para sair..."); Console.ReadKey(); } static int[] obterValores(){ // vamos criar um array de cinco inteiros int[] matriz = {1, 2, 3, 4, 5}; // vamos retornar este array para o chamador deste método return matriz; } Palavras-chaves: args, , 5, algumas, ", este, 1, 4, Como, criar, int, programa , static, cinco, pode, Main, Em, de, precisamos, , tecla, matriz, ; , para, matriz; , return, do, que, isso, 2, abaixo , obtido , array, Length;, método , obter, <, imprimir, como, escrever, deste, retorna, pausa, sair, chamador, mostra, 3, uma, =, Esta, retornar, 0;, ; , ReadKey, o, static, for, obterValores, qualquer, void, feito, i, System, inteiros , string, vamos, > , um, Write, ser, situações, i++, C#, valores, método, Pressione, WriteLine, > Como inverter a ordem dos elementos de um array static void Main(string[] args) { // cria e inicializa um array de strings string[] cidades = {"Goiânia", "São Paulo", "Rio de Janeiro", "Curitiba"}; Console.WriteLine("Ordem original:"); for (int i = 0; i < cidades.Length; i++) Console.WriteLine(cidades[i]); // inverte a ordem dos elementos Array.Reverse(cidades); // exibe os elementos na ordem inversa Console.WriteLine(); Console.WriteLine("Ordem inversa:"); for (int i = 0; i < cidades.Length; i++) Console.WriteLine(cidades[i]); // pausa o programa Console.ReadKey(); } Palavras-chaves: <, =, static, Main, Janeiro", inversa , programa , elementos , for, , Paulo", dos, Console, inversa, a, Length;, array, na, string, ; , os, "Curitiba", exibe, strings , um, o, args, inicializa, "Goiânia", elementos, i, "São, ", original, Reverse, "Ordem, "Rio, inverte, i++, cidades, ordem, ReadKey, cria, e, , void, pausa, Array, 0;, de, ; , WriteLine, int Aprenda a declarar e usar variáveis em C# Aprenda a declarar e usar variáveis em C# Variáveis são apelidos que damos aos blocos de memória que podem ser usados para armazenar dados durante a execução de um programa. Podemos guardar informações dos mais variados tipos em variáveis, a saber: valores inteiros, valores de número flutuante (com casas decimais), palavras, frases, textos e até mesmo referências a objetos de classes (fornecidas pela linguagem C# ou nossas próprias). Uma variável é declarada, em sua forma mais simples, informando o tipo de dados (int, float, double, string, etc) e então o nome da variável. Veja: // uma variável usado para armazenar um valor inteiro int valor; Uma vez declarada a variável, podemos definir o valor que será armazenado inicialmente. Isso é chamado de "atribuir um valor inicial à variável". Veja: static void Main(string[] args){ // declara e inicializa uma variável do tipo double double salario = 2345.32; // exibe o valor da variável Console.WriteLine("Salário: {0}", salario); Console.WriteLine("\n\nPressione uma tecla para sair..."); Console.ReadKey(); } É possível declarar mais de uma variável do mesmo tipo. Basta separá-las por vírgulas. Veja: // declara três variáveis do tipo char char a, b, c; Variáveis são realmente úteis quando as estamos usando em cálculos ou outras operações importantes para o correto funcionamento do programa. Veja: static void Main(string[] args){ // declara três variáveis do tipo int int a, b, soma; // inicializa as duas primeiras variáveis a = 20; b = 10; // inicializa a terceira variável usando os valores // das duas anteriores soma = a + b; // exibe o resultado Console.WriteLine("Resultado: {0}", soma); Console.WriteLine("\n\nPressione uma tecla para sair..."); Console.ReadKey(); } Para finalizar, lembre-se de uma variável C# possui atributos importantes e que devem ser lembrados com frequencia durante o planejamento de suas aplicações. Alguns destes atributos são: tipo, nome, valor, posição na memória, escopo (global ou local) e visibilidade (pública ou privada). Palavras-chaves: int , planejamento, cálculos, damos, das, quando, sair, b; , ; , na, , finalizar, dados, visibilidade, b, número, inicialmente, saber, palavras, local, atributos, informando, as, operações, guardar, e, declarar, c; , da, aos, estamos, durante, realmente, variável , dos, importantes, salario, variados, Variáveis, lembrados, valor; , com, usar, Basta, Isso, flutuante, "Resultado, definir, etc, variável, Aprenda, apelidos, primeiras, separá-las, , possui, variáveis , inteiros, vírgulas, vez, um, posição, ", será, fornecidas, ReadKey, valores, double, programa, nome, tecla, sua, Para, usados, Veja, resultado , valores , soma; , aplicações, WriteLine, blocos, char char, 20; , float, outras, informações, "atribuir, casas, 0, valor, Console, double , lembre-se, É, inicializa, mesmo, declarada, por, anteriores , três, tipo, args, de, duas, referências, Main, frequencia, exibe, simples, linguagem, o, decimais, podem, declara, então, Uma, devem, tipos, global, a, uma, inicial, é, à, execução, nossas, ou, escopo, , que, soma, static, int, mais, Pressione, forma, até, os, próprias, Podemos, suas, do, pública, 10; , 2345, objetos, chamado, +, void, memória, inteiro int, privada, podemos, variáveis, classes, ser, úteis, pela, destes, correto, variável", armazenar, funcionamento, em, terceira, frases, C#, para, textos, ; , usado, "Salário, Alguns, string, são, =, possível, armazenado, 32; , usando Comandos básico GNU_Linux Comandos de Controlo e Acesso exit Terminar a sessão, ou seja, a shell (mais ajuda digitando man sh ou man csh) logout Deslogar, ou seja, terminar a sessão actual, mas apenas na C shell e na bash shell passwd Mudar a password do nosso utilizador rlogin Logar de forma segura noutro sistema Unix/Linux ssh Sessão segura, vem de secure shell, e permite-nos logar num servidor através do protocolo ssh slogin Versão segura do rlogin yppasswd Mudar a password do nosso utilizador nas páginas amarelas (yellow pages) Comandos de Comunicações mail Enviar e receber emails mesg Permitir ou negar mensagens de terminal e pedidos de conversação (talk requests) pine Outra forma de enviar e receber emails, uma ferramenta rápida e prática talk Falar com outros utilizadores que estejam logados no momento write Escrever para outros utilizadores que estejam logados no momento Comandos de Ajuda e Documentação apropos Localiza comandos por pesquisa de palavra-chave find Localizar ficheiros, como por exemplo: find . name *.txt -print, para pesquisa de ficheiros de texto por entre os ficheiros da directoria actual info Lança o explorador de informações man Manual muito completo, pesquisa informação acerca de todos os comandos que necessitemos de saber, como por exemplo man find whatis Descreve o que um determinado comando é whereis Localizar a página de ajuda (man page), código fonte, ou ficheiros binários, de um determinado programa Comandos de Edição de Texto emacs Editor de texto screen-oriented pico Editor de texto screen-oriented, também chamado de nano sed Editor de texto stream-oriented vi Editor de texto full-screen vim Editor de texto full-screen melhorado (vi improved) Comandos de Gestão de Ficheiros e Directorias cd Mudar de directoria actual, como por exemplo cd directoria, cd .., cd / chmod Mudar a protecção de um ficheiro ou directoria, como por exemplo chmod 777, parecido com oattrib do MS-DOS chown Mudar o dono ou grupo de um ficheiro ou directoria, vem de change owner chgrp Mudar o grupo de um ficheiro ou directoria cmp Compara dois ficheiros comm Selecciona ou rejeita linhas comuns a dois ficheiros seleccionados cp Copia ficheiros, como o copy do MS-DOS crypt Encripta ou Desencripta ficheiros (apenas CCWF) diff Compara o conteúdo de dois ficheiros ASCII file Determina o tipo de ficheiro grep Procura um ficheiro por um padrão, sendo um filtro muito útil e usado, por exemplo um cat a.txt | grep ola irá mostrar-nos apenas as linhas do ficheiro a.txt que contenham a palavra “ola” gzip Comprime ou expande ficheiros ln Cria um link a um ficheiro ls Lista o conteúdo de uma directoria, semelhante ao comando dir no MS-DOS lsof Lista os ficheiros abertos, vem de list open files mkdir Cria uma directoria, vem de make directory” mv Move ou renomeia ficheiros ou directorias pwd Mostra-nos o caminho por inteiro da directoria em que nos encontramos em dado momento, ou seja apathname quota Mostra-nos o uso do disco e os limites rm Apaga ficheiros, vem de remove, e é semelhante ao comando del no MS-DOS, é preciso ter cuidado com o comando rm * pois apaga tudo sem confirmação por defeito rmdir Apaga directorias, vem de remove directory stat Mostra o estado de um ficheiro, útil para saber por exemplo a hora e data do último acesso ao mesmo sync Faz um flush aos buffers do sistema de ficheiros, sincroniza os dados no disco com a memória, ou seja escreve todos os dados presentes nos buffersda memória para o disco sort Ordena, une ou compara texto, podendo ser usado para extrair informações dos ficheiros de texto ou mesmo para ordenar dados de outros comandos como por exemplo listar ficheiros ordenados pelo nome tar Cria ou extrai arquivos, muito usado como programa de backup ou compressão de ficheiros tee Copia o input para um standard output e outros ficheiros tr Traduz caracteres umask Muda as protecções de ficheiros por defeito uncompress Restaura um ficheiro comprimido uniq Reporta ou apaga linhas repetidas num ficheiro wc Conta linhas, palavras e mesmo caracteres num ficheiro Exibição ou Impressão de Ficheiros cat Mostra o conteúdo de um ficheiro, como o comando type do MD-DOS, e é muito usado também para concatenar ficheiros, como por exemplo fazendo cat a.txt b.txt > c.txt” para juntar o ficheiro a.txt e b.txt num único de nome c.txt fold Encurta, ou seja, faz um fold das linhas longas para caberem no dispositivo de output head Mostra as primeiras linhas de um ficheiro, como por exemplo com head -10 a.txt, ou usado como filtro para mostrar apenas os primeiros x resultados de outro comando lpq Examina a spooling queue da impressora lpr Imprime um ficheiro lprm Remove jobs da spooling queue da impressora more Mostra o conteúdo de um ficheiro, mas apenas um ecrã de cada vez, ou mesmo output de outros comandos, como por exemplo ls | more less Funciona como o more, mas com menos features, menos características e potenciais usos page Funciona de forma parecida com o comando more, mas exibe os ecrãs de forma invertida ao comandomore pr Pagina um ficheiro para posterior impressão tail Funciona de forma inversa ao comando head, mostra-nos as últimas linhas de um ficheiro ou mesmo do output de outro comando, quando usado como filtro zcat Mostra-nos um ficheiro comprimido xv Serve para exibir, imprimir ou mesmo manipular imagens gv Exibe ficheiros ps e pdf xpdf Exibe ficheiros pdf, usa o gv Comandos de Transferência de Ficheiros ftp Vem de file transfer protocol, e permite-nos, usando o protocolo de transferência de ficheirosftp, transferir ficheiros entre vários hosts de uma rede, como aceder a um servidor de ftp para enviar ou puxar ficheiros rsync Sincroniza de forma rápida e flexível dados entre dois computadores scp Versão segura do rcp Comandos de Notícias ou Rede netstat Mostra o estado da rede rsh Corre umam shell em outros sistemas UNIX ssh Versão segura do rsh nmap Poderoso port-scan, para visualizarmos portas abertas num dado host ifconfig Visualizar os ips da nossa máquina, entre outras funções relacionadas com ips ping Pingar um determinado host, ou seja, enviar pacotes icmp para um determinado host e medir tempos de resposta, entre outras coisas Comandos de Controlo de Processos kill Mata um processo, como por exemplo kill -kill 100ou kill -9 100 ou kill -9 %1 bg Coloca um processo suspenso em background fg Ao contrário do comando bg, o fg traz de volta um processo ao foreground jobs Permite-nos visualizar jobs em execução, quando corremos uma aplicação em background, poderemos ver esse job com este comando, e termina-lo com um comando kill -9 %1, se for o jobnúmero 1, por exemplo top Lista os processos que mais cpu usam, útil para verificar que processos estão a provocar um uso excessivo de memória, e quanta percentagem decpu cada um usa em dado momento ^y Suspende o processo no próximo pedido de input ^z Suspende o processo actual Comandos de Informação de Estado clock Define a hora do processador date Exibe a data e hora df Exibe um resumo do espaço livre em disco du Exibe um resumo do uso do espaço em disco env Exibe as variáveis de ambiente finger Pesquisa informações de utilizadores history Lista os últimos comandos usados, muito útil para lembrar também de que comandos foram usados para fazer determinada acção no passado ou o que foi feito em dada altura last Indica o último login de utilizadores lpq Examina a spool queue manpath Mostra a path de procura para as páginas do comando man printenv Imprime as variáveis de ambiente ps Lista a lista de processos em execução, útil para saber o pid de um processo para o mandar abaixo com o comando kill, entre outras coisas pwd Mostra-nos o caminho por inteiro da directoria em que nos encontramos em dado momento, ou seja apathname set Define variáveis da sessão, ou seja, da shell, na C shell, na bash ou na ksh spend Lista os custos ACITS UNIX até à data time Mede o tempo de execução de programas uptime Diz-nos há quanto tempo o sistema está funcional, quando foi ligado e o seu uptime w Mostra-nos quem está no sistema ou que comando cada job está a executar who Mostra-nos quem está logado no sistema whois Serviço de directório de domínios da Internet, permite-nos saber informações sobre determinados domínios na Internet, quando um domínio foi registado, quando expira, etc whoami Diz-nos quem é o dono da shell Comandos de Processamento de Texto abiword Processador de Texto Open Source addbib Cria ou modifica bases de dados bibliográficas col Reverte o filtro a line feeds diction Identifica sentenças com palavras diffmk Marca diferenças entre ficheiros dvips Converte ficheiros TeX DVI em ficheiros PostScript explain Explica frases encontradas pelo programa diction grap Preprocessador pic para desenhar gráficos, usado em tarefas elementares de análises de dados hyphen Encontra palavras com hífenes ispell Verifica a ortografia de forma interactiva latex Formata texto em LaTeX, que é baseado no TeX pdfelatex Para documentos LaTeX em formato pdf latex2html Converter LaTeX para html lookbib Encontra referências bibliográficas macref Cria uma referência cruzada listando ficheiros de macros nroff/troff ndx Cria uma página de indexação para um documento neqn Formata matemáticas com nroff nroff Formata texto para exibição simples pic Produz simples imagens para troff input psdit Filtra um output troff para a Apple LaserWriter ptx Cria uma indexação permutada mas não em CCWF refer Insere referências de bases de dados bibliográficas roffbib Faz o run off de uma base de dados bibliográfica sortbib Ordena uma base de dados bibliográfica spell Encontra erros de ortografia style Analisa as características superficiais de um documento tbl Formata tabelas para nroff/troff tex Formata texto tpic Converte ficheiros pic source em comandos TeX wget Permite-nos fazer o download completo de páginas web, com todos os ficheiros, de forma fácil e não interactiva, sem exigir por isso presença do utilizador, respeitando também o ficheirorobots.txt Web html2ps Conversor de html para ps latex2html Conversor de LaTeX para html lynx Navegador web baseado em modo de texto, ou seja, é um web browser que nos permite abrir todo o tipo de páginas visualizando apenas os textos elinks, não vendo assim as imagens, e sendo por isso bastante rápido, mas requere prática para ser manuseado netscape Navegador web da Netscape sitecopy Aplicação que nos permite manter facil e remotamente web sites weblint Verificador de sintaxes e de estilos html