COMEÇANDO A PROGRAMAR


  Nada melhor do que começar direto com a mão na massa! Desta maneira, o leitor poderá aprender fazendo e alterando os programas apresentados aqui.
  Primeiramente, será apresentada a estruturação padrão de um programa em Pascal, de modo que o leitor possa entender como organizar o código de seus programas.
  Em seguida, são propostos alguns problemas, acompanhados de suas respectivas da soluções, de forma a introduzir alguns conceitos que serão abordados em maior profundidade nos capítulos seguintes.



  ESTRUTURA DO PROGRAMA EM C

Parte do programa Descrição
#include <stdio.h> Chama as bibliotecas necessárias ao seu programa.
struct molde_ficha
{
  char *nome;
  char *endereco;
  int idade;
}ficha1; ficha[500];
Definição de estruturas.
int i, contador=0;
char tecla;
float media;
Declaração das variáveis globais.
int area(int a, int b, int c)
{
  return a*b*c;
)
Criação de funções. Podem ser criadas n funções aqui.
int main(int total_de_argumentos, char *argumento[])
{
  ficha1.nome = "Marcelo";
  ficha[0].nome = "MarMSX";
  return 1;
}
Corpo principal do programa. Gerencia as funções. Como toda função, deve retornar algo, mesmo que não seja usado, exceto para funções iniciadas por void. Ex: void main(void). Alguns compiladores C não aceitam o void como retorno de função do no main.


  Descrições gerais da linguagem C

  O programa em C é dividido em declaração de variáveis, funções e corpo principal.
  O corpo principal é onde o programa começa a executar, enquanto que as funções são sub-rotinas isoladas que têm como objetivo executar determinadas tarefas.
  Assim como em outras linguagens, o programa executa linha a linha, sempre começando pelas linhas do topo de cada estrutura.
  As linhas são delimitadas pelo caractere ponto e vírgula ";". Dessa forma, quando há duas expressões separadas por ponto e vírgula na mesma linha, é como se fossem duas linhas diferentes. Ex:
a=1; b=b+2;
  equivale a:
a=1;
b=b+2;

  Também podemos colocar expressões correspondentes a uma linha em diversas linhas. O compilador entenderá o bloco como uma linha. Ex:
int a[] = { 1,2,
            3,4 };
  equivale a:
int a[] = { 1,2,3,4 };

  As chaves ("{" e "}") delimitam o corpo de uma função ou estrutura. São semelhantes ao BEGIN e END do Pascal.
  Quando uma estrutura tiver somente uma linha, não é necessário indicar o seu inicio e fim com as chaves. Ex:
if (a == 8)
  c = c + 1;

  O MSX possui um interpretador Basic incluído na ROM. Dessa forma, ele possui recursos próprios para executar um programa. No caso do C, é necessário um pacote contendo um compilador C para gerar o arquivo executável, conforme foi visto no primeiro capítulo.
  O C é uma linguagem compilada, ou seja, o código fonte é convertido para código de máquina e depois é executado. O compilador Hi-Tech C possui o comando "c", no prompt do MSX-DOS. Ele gerencia todo o processo de compilação de um programa.
  Exemplo:
A:>c programa
  Irá gerar o arquivo "programa.com".

  Os arquivos fonte do C possuem a extensão ".c", enquanto que os executáveis possuem a extensão ".com".

  O C não possui funções e comandos básicos presentes diretamente no compilador como nas outras linguagens. Eles estão sempre localizados em bibliotecas, que são chamadas através do comando "#include". A biblioteca básica para o funcionamento do C é a "stdio.h".


  Comentários

  Os comentários servem para auxiliar os programadores a compreender o código do programa. Eles são feitos, utilizando-se duas formas:
  Exemplos:
// Esta função calcula o produto de dois números
int produto(int a, int b)
{
  return a*b;
}
/* Esta função calcula o produto de dois números */
int produto(int a, int b)
{
  return a*b;
}
  O texto dos comentários é totalmente ignorado pelo compilador.

  Exemplos em várias linhas:
// Esta função calcula
// o produto de dois
// números
/* Esta função calcula
   o produto de dois
   números */

  Obs: o compilador Hi-Tech C do MSX somente aceita os comentários na forma "/*" e "*/".


  Corpo principal

  O corpo principal de um programa em C é o primeiro trecho de código do programa a ser executado. Ele tem a estrutura de uma função, possui o nome "main" e pode ser declarado das seguintes formas:
int main(void)
{
  // Código
  return 1;
}
void main(void)
{
  // Código
}
main()
{
  // Código
}

  Quando desejamos obter dados da linha de comando do DOS, acrescentamos os seguintes parâmetros à função main, em substituição a palavra "void":
main(int total_de_argumentos, char *argumento[])
  Onde "total_de_argumentos" é o total de argumentos passados quando o programa é chamado pelo DOS e "*argumento[]" o vetor dos parâmetros passados.

  Por exemplo, seja o arquivo teste.com:
 A:>teste azul grande
  O valor passado para total_de_argumentos é 3, variando de 0 a 2. temos as seguintes configurações para o parâmetros argumento:

  argumento[0] = teste.com
  argumento[1] = azul
  argumento[2] = grande

  Caso não trabalhemos com passagem de parâmetros pela linha de comando, simplesmente colocamos main(void), conforme já tinha sido feito até o presente momento.

  O exemplo a seguir irá receber o nome de uma pessoa como argumento e escrevê-la na tela.
#include <stdio.h>

main(int argc, char *arg[])
{
  printf("Seu nome e': %s\n", arg[1]);
}

  Compilando:
A:>c nome.c

  Executando:
A:>nome MarMSX
Seu nome e': MarMSX

  Se você tentar usar strings com espaço em branco, somente a primeira string será escrita. Ex:
A:>nome Rio de Janeiro
Seu nome e': Rio

  Para contornar isso, utilize as aspas duplas para delimitar a string:
A:>nome "Rio de Janeiro"
Seu nome e': Rio de Janeiro


  Variáveis

  As variáveis servem para armazenar dados durante a execução de um programa. Assim como no Pascal, a declaração da variável é obrigatória antes do seu uso. Deve-se indicar o tipo de dado armazenado na variável em sua declaração e a alteração do tipo de dado declarado no decorrer do programa não é permitida.
  O capítulo 2 apresentou os principais tipos de variáveis do C.


  Estruturas

  As estruturas permitem a criação de variáveis mais complexas. Elas são abordadas no capítulo 7.


  Includes

  O C permite a inclusão de bibliotecas, contendo funções específicas para resolver determinados problemas. O capítulo 9 aborda esse assunto em detalhes.


  Funções

  As funções são sub-rotinas que executam em separado do restante do programa. Elas funcionam como uma "caixa-preta", onde recebem dados de entrada, realizam algum processamento e produzem uma resposta.
  A sintaxe para uma função é:
tipo_de_dado_de_retorno  nome_da_função(lista_de_parâmetros)
{
  // Código de processamento
  return dado_de_retorno;
}
  No Pascal, utilizamos o nome da função para atribuir o valor de retorno. No caso do C, utilizamos a palavra reservada "return", seguido do valor (ou expressão) a ser retornado.
  O uso do "return" é obrigatório para funções que retornam valor. Entretanto, é facultativo para funções que não retornam valor.

  Exemplo de função:
int dobro(int n)
{
  return n*2;
}
  Esta função recebe um valor inteiro, passado através da variável "n", e retorna outro valor inteiro. O valor retornado é a expressão "n*2", que é o dobro de "n".

  Para utilizar a função, deve-se declarar o nome da função, passando-se os parêmetros necessários e associar o resultado a uma variável. Ex:
int x;

main()
{
  x = dobro(4); // x recebe o resultado de n*2, que é 8
}
  A função "dobro" recebe o valor 4 em "n", multiplica por 2 e retorna o valor igual a 8. O resultado da conta é armazenado na variável "x".

  No Pascal, temos a "procedure", que é uma função que não retorna valor. Como o C somente possui funções, o equivalente para a procedure é:
void minha_procedure()
{
  printf("Minha procedure\n");
}
  Quando a função não retorna valor, ela pode ser chamada diretamente (sem a associação com uma variável). Ex:
minha_procedure();
  O mesmo pode ser aplicado a funções que retornam valores. Entretanto, o valor de retorno é perdido.

  As funções podem chamar outras funções ou a si mesmas (recursividade). Ex:
#include <stdio.h>

void func1()
{
  printf("Olá.\n");
}

void func2()
{
  func1();
}

main()
{
  func2();
}
  Saída:
  Olá.

  Não há limites para chamadas em cascata. Entretanto, a cada chamada de função, a função chamadora é colocada na pilha. O programa pára a execução, quando essa pilha estoura.


  Fluxo de execução

  Seja o programa abaixo:
#include <stdio.h>

int b;

main()
{
  b = 3+2;
  printf("Resultado: %d\n", b);
}
  O fluxo de execução desse programa, assinalado pelos números ao final da linha, é:
#include <stdio.h>

int b;

main()
{
  b = 3+2;                      1
  printf("Resultado: %d\n", b); 2
}
  Saída:
  Resultado: 5

  Seja esse outro programa abaixo:
#include <stdio.h>

int b;

int calcula(int a, int b)
{
  a = a+3;
  return a*b;
}

main()
{
  b = calcula(2,3);
  printf("Resultado: %d\n", b);
}
  O fluxo de execução desse programa, assinalado pelos números ao final da linha, é:
#include <stdio.h>

int b;

int calcula(int a, int b)
{
  a = a+3;                      2
  return a*b;                   3
}

main()
{
  b = calcula(2,3);             1
  printf("Resultado: %d\n", b); 4
}
  Saída:
  Resultado: 15



  EXERCÍCIOS

  A partir dos exemplos a seguir, serão apresentadas as principais cláusulas e funções da linguagem C.


  PROBLEMA 1 - Fazer um programa que receba as horas e dê bom dia, boa tarde ou boa noite.

  Solução:
#include <stdio.h>

int horas;

int main(void)
{
  printf("Qual a hora? ");
  scanf("%d",&horas);

  if ((horas >= 6) && (horas < 12))
    printf("Bom dia.");
  if ((horas >=12) && (horas < 19))
    printf("Boa tarde.");
  if ((horas >=19) || (horas < 6))
    printf("Boa noite.");

  return 1;
}

  DICA - VARIÁVEIS GLOBAIS E LOCAIS

  As variáveis globais são variáveis que podem ser lidas e escritas em qualquer trecho do programa. Elas são declaradas fora de qualquer estrutura. As variáveis globais ocupam espaço na memória, do princípio ao término do programa.
  As variáveis locais são variáveis que são criadas dentro de estruturas como funções. Elas são criadas quando a função que as contêm são chamadas, e destruídas assim que se encerra o processamento da função. Dessa forma, liberam o espaço de memória que ocuparam.
  As variáveis locais só podem ser acessadas de dentro da função em que ela se localiza. Ex:
#include <stdio.h>

// Declaração de variável global
int var_global;

void funcao_1()
{
   // Declaração de variável local
   int var_local;

   var_global = 1;
   var_local = 1;
}

int main(void)
{
  var_global = 2;
  var_local = 2;  // Erro! Inacessível daqui.

  return 1;
}

  DICA - IF

  A estrutura IF testa se uma condição é verdadeira ou falsa.
  Sintaxe:
if (condição)
{
  // Código para a condição verdadeira
}
else
{
  // Código para a condição falsa
}
  Obs: o uso do parêntesis para o IF é obrigatório.

  O uso do tratamento "else" é falcultativo, assim como o uso das chaves é facultativo, quando qualquer um dos tratamentos possuir apenas uma linha (delimitada pelo ";"). Ex:
if (a < 4)
  printf("Valor correto.\n");

  A "condição" pode receber vários testes como entrada, mas deve produzir uma única saída. É isso que é feito no exercício 1, onde são realizados três testes lógicos, produzindo uma saída. Veja como:
teste 1: horas >= valor_1     // Horas é maior ou igual ao valor_1 ?
teste 2: horas < valor_2      // Horas é menor que o valor_2 ?

teste 3: teste_1 E teste_2    // teste_1 e teste_2 são ambos verdadeiros ?
  Este teste verifica se o valor de "horas" está dentro de uma faixa que começa por valor_1 e termina por valor_2.


  DICA - PRINTF E SCANF

  A função "scanf" serve para ler dados do teclado e necessita que seja indicada que tipo de variável será lida. No caso do exemplo 1 a variável é inteira, representada por "%d". Caso a variável seja do tipo long, use "%ld".
  O "scanf" exige o símbolo "&" antes antes do nome da variável, uma vez que o parâmetro é do tipo ponteiro. Veja mais detalhes no problema 3 desse capítulo.

  Outra novidade que surgiu foi o comando "\n" no "printf". Ele faz saltar para a proxima linha, a partir do ponto que ele é colocado. Eis alguns comandos para o "printf":

Símbolo Significado
\n Nova linha.
\t Tabulação.
\b Backpace.
\f Salta página de formulário.
\0 Caractere nulo.
\xhh Caractere representado pelo ASCII hh, em hexa.
\nnn Byte na casa octal.
\\ Imprime "\"

Exemplo:

 printf("Isto será \n impresso assim \\");
  Saída:
  Isto será
  impresso assim \



  PROBLEMA 2 - Fazer um programa, onde uma função calcula a média aritimética de 3 notas fornecidas.

  Solução:
#include <stdio.h> 

#include 

float a,b,c; 

float media(float na, float nb, float nc)
{
  return (na+nb+nc)/3.0;
}

int main(void)
{
  printf("Entre com a nota 1: ");
  scanf("%f",&a);
  printf("Entre com a nota 2: ");
  scanf("%f",&b);
  printf("Entre com a nota 3: ");
  scanf("%f",&c);
  printf("A média final é: %.1f\n", media(a,b,c));

  return 1;
}
  Saída:
  Entre com a nota 1: 7
  Entre com a nota 2: 8
  Entre com a nota 3: 9
  A média final é: 8.0


  DICA - ENTENDENDO O PROGRAMA 2

  O objetivo do programa é receber do usuário 3 variáveis do tipo real (notas), passá-las à função "media" e retornar o resltado da média aritimética das 3 notas.

  As variáveis "a", "b" e "c" são passadas como parâmetros de entrada para a função "media". Elas se relacionam com as variáveis "na", "nb" e "nc" da seguinte maneira:
             a         b         c
media(float na, float nb, float nc)

  Essa função retorna um valor. Dessa forma, é recomendado que o resultado da função seja armazenado em uma variável do mesmo tipo do retorno da função.
  Qual a utilidade de uma função? Isolamento do problema, além de evitar a duplicidade de código.

  Eu posso utilizar uma variável com o mesmo nome da variável da lista de parâmetros ?
  Pode sim. O compilador C saberá distinguir as duas, uma vez que a varíavel da função é local e estará sempre um nivel abaixo da variável utilizada como passagem de parâmetro.

  Se eu alterar o valor de "na", ele será refletido na variável "a" ?
  No exemplo acima não irá alterar, uma vez que a passagem de parâmetros é do tipo valor. Veja o próximo problema.



  PROBLEMA 3 - Diferenciar passagem por referência e passagem por valor em uma função.

  Seja o seguinte programa:
#include <stdio.h>

int a=1;

void func1(int b)
{
  printf("%d\n", b);
}

main()
{
  func1(a);
}
  A passagem por valor é quando uma variável da lista dos parâmetros da função recebe uma cópia do valor da variável utilizada no chamamento da função. No exemplo acima, é quando "b" recebe uma cópia do valor de "a". Nesse caso, qualquer alteração em "b" não irá refletir em "a".
  Já a passagem por referência é quando uma variável da lista dos parâmetros da função faz referência à variável utilizada no chamamento da função, passando a se comportar como ela. No exemplo acima, "b" passa a se comportar como "a". Assim, qualquer alteração em "b" irá refletir em "a".

  Veja os exemplos a seguir:
/* Passagem por VALOR */

#include <stdio.h>

int a;

void teste(int b)
{
  b=5;
}

main()
{
  a = 4;
  teste(a);
  printf("O valor de a é: %d",a);
}
  Saída:
  O valor de a é: 4

  Uma vez que a variável "b" da função "teste" recebe uma cópia de "a", a variável global "a" NÃO É ALTERADA!!

/* Passagem por REFERÊNCIA */

#include <stdio.h>

int a;

void teste(int *b)
{
  *b = 5;
}

main()
{
  a = 4;
  teste(&a);
  printf("O valor de a é: %d",a);
}
  Saída:
  O valor de a é: 5

  Uma vez que a variável "b" da função "teste" é a própria variável "a", a variável global "a" É ALTERADA!!

  Na passagem por referência, é obrigatório chamar a função uilizando variáveis, conforme no exemplo acima.
  Já na passagem por valor, você pode tanto passar os dados utilizando variáveis, como com valores diretos. Por exemplo: soma(2,3).

  Como diferenciar esses mecanismos na declaração da função ?

  A declaração normal de uma variável da lista de parâmetros indica que ela irá fazer a passagem por valor. Ex:
void teste(int a)
  Quando é declarada uma variável do tipo ponteiro (símbolo de asterisco "*"), ela irá fazer a passagem por referência. Ex:
void teste(int *a)

  Quando uma variável comum (não ponteiro) é utilizada como dado de entrada na passagem por referência, deve-se utilizar o símbolo "&" antes do nome dela. Essa é a razão da função "scanf" exigir o símbolo "&" antes do nome da variável. Já no caso de uma string, não é necessário o símbolo "&", uma vez que ela é do tipo ponteiro. Ex:
#include <stdio.h>

char nome[20];

main()
{
  printf("Nome: ");
  scanf("%s",nome);

  printf("Seu nome é: %s\n", nome);
}
  O capítulo sobre ponteiros descreve em detalhes o funcionamento desse tipo de variável.


  DICA - RECEBENDO PARÂMETROS DE DIFERENTES TIPOS NA FUNÇÃO

  Os parametros de uma função são separados por vírgula. Ex:
 int rotate(int zoom, int x, int y, float alfa, float beta, char *mapa)



  PROBLEMA 4 - Fazer uma função que escreva "EU AMO O MSX" 100 vezes na tela.

  Solução:
#include <stdio.h> 

void repete100()
{
  int i;
  for (i=0; i<100; i++)
    printf("EU AMO O MSX\n");
}

void main(void)
{
  repete100();
}

  DICA - ESTRUTURAS DE REPETIÇÃO

  O C tem 3 tipos de laços de repetição: FOR, WHILE e DO-WHILE . Para estas estruturas, devemos colocar os delimitadores "{" e "}", toda vez que o código dentro da estrutura tiver mais que uma linha, conforme visto nos exemplos acima.
for (inicio; condição; passo)
{
  bla, bla, bla ....
}

while (condição)
{
  bla, bla, bla ...
}

do
  bla, bla, bla ...
} while (condição) 
  A condição é um teste lógico para a continuação do loop e é algo do tipo:

- a > 10
- b < c
- idade == 15
- etc.


  FOR

  Sintaxe para o FOR:
for (variável_de_controle = valor_inicial; teste_lógico; incremento/decremento)
{
  // Código
}

  A estrutura FOR do C é um pouco diferente das outras linguagens, no que diz respeito aos limites e passo.
  Primeiro, devemos informar qual o valor inicial da variável de controle. Caso a variável não tenha sido declarada, declare ela imediatamente antes do laço FOR. Depois, fornecemos um teste lógico, no qual o loop é mantido enquanto o resultado do teste for verdadeiro. Por fim, informamos o passo do incremento ou decremento da variável de controle do FOR. Os três campos são separados por ponto e vírgula.
  Exemplo:
#include <stdio.h>

int a;

int main(void)
{
  for (a=1; a<10; a=a+2)
    printf("%d\n", a);

  return 1;
} 
  Saída:
  1
  3
  5
  7
  9

  No exemplo, temos:   O comando Basic correspondente é:
FOR a=1 TO 10 STEP 2

  Deve-se tomar cuidado com o teste lógico, uma vez que situações absurdas podem ser criadas. Veja o exemplo:
unsigned int i;

for (i=1; i>0; i++)
  printf("%d\n", i);
  Irá rodar infinitamente, uma vez que a condição de continuidade (teste lógico) nunca se tornará falso.


  WHILE e DO-WHILE

  Também são estruturas de repetição como o FOR. Entretanto, o valor inicial e o incremento é feito pelo programador.
  O que ambas estruturas fazem é separar um trecho de código, realizar um loop, enquanto uma dada condição for verdadeira.
  Sintaxes:
while (condição)
{
  // Código
}
do
{
  // Código
} while (condição);

  No exemplo a seguir, vamos reescrever o programa do FOR adaptado ao WHILE:
int a;

main()
{
  a=1;

  while (a < 10)  
  {
    printf("%d\n", a);
    a = a + 2;
  }
}

  A diferença entre o WHILE e o DO-WHILE é que o primeiro realiza o teste no inicio do bloco de repetição, enquanto que o segundo faz o teste no final do bloco.



  PROBLEMA 5 - Fazer um programa que calcula o tamanho de uma palavra. Veja a biblioteca string.h.

  Solução:
#include <stdio.h>
#include <string.h>

char nome[20];

void main(void)
{ 
  printf("Entre o seu nome: ");
  scanf("%s",nome);
  printf("Seu nome tem %d letras.\n", strlen(nome));
}
  Saída:
  Entre o seu nome: Felipe
  Seu nome tem 6 letras.



  PROBLEMA 6 - Fazer um programa que receba o nome de 10 alunos e guarde em um vetor.

  Solução:
#include <stdio.h>

char *nome[20];

int i;

void main(void)
{ 
  for (i=1; i<=10; i++)
  {
    printf("Nome do aluno %d: ",i);
    scanf("%s", nome[i]);
  }
}


  DICA - VETORES

  Uma variável é capaz de armazenar somente um dado, no formato definido para ela. Entretanto, pode-se utilizar uma estrutura mais complexa para armazenar mais de um dado por variável. São os vetores.
  Um vetor é uma lista de dados do mesmo tipo, dispostos na memória de forma contígua.
  Deve-se utilizar os colchetes ("[" e "]"), preenchido com o tamanho da lista, para indicar que a variável é na realidade um vetor.
  Ex:
int a[5];
  Irá criar um vetor de números inteiros, com capacidade de 5 números.

  O capítulo de Listas e Matrizes aborda os vetores e matrizes em detalhes.


/MARMSX/CURSOS/C--