Voltar a pagina inicial
D3_Artigos D3_Projetos D3_Membros D3_Feedback D3_Forum

 
Artigo
 
Autor: NeoRevolutions
Categoria: Programação / Linguagem C/C++
Criado em: 13-11-2007 19:58:09
Atualizado em: 10-03-2008 19:58:09
Media: 10.0
Visitas: 578

Clique aqui para exibir o modo de impressão.

Tutorial C++ Lição 3


Usando arrays


Pode-se imaginar um array como sendo um multi-variável ou então como sendo uma vetor ou ainda um armário, com diversas gavetas. Este armário teria um nome e suas gavetas teriam um índice, variando de 0 (zero) a n (total de gavetas).

Podemos também pensar no array como sendo um livro, cada página é como se fosse uma variável. Para acessar uma variável, recorremos ao índice. Olhamos sua página e a acessamos diretamente. O nome do array seria o nome do livro.

Para esse conceito ficar um pouco mais claro, vejamos um exemplo real em C. Na programação, são muito usados para se relacionar vários dados do mesmo tipo com um mesmo nome, que são apenas diferenciados por um índice numérico, sendo que este índice inicia-se no zero, ou seja, o primeiro elemento tem o índice zero.

// um array chamado "var", contendo 5 elementos.

int var[5];

No exemplo acima, criamos um array ou vetor contendo 5 elementos.

Declarando arrays


Para se criar um vetor, ou array, procede-se da mesma forma que na declaração de uma variável normal, apenas informando o número de elementos que o vetor irá apresentar entre colchetes. Veja:

char MeuVetor[10]; // declarando um vetor de 10 elementos do tipo char


Neste exemplo, temos dez variáveis do tipo char com o nome de MeuVetor. Note que colocamos o número de elementos entre colchetes.

Você pode declarar um vetor de qualquer tipo de dado. Normalmente, quando criamos um vetor do tipo char, ele é chamado de string ou uma seqüência de caracteres. Veremos strings mais adiante.

Acessando arrays


Para poder ter acesso a cada um dos elementos do vetor acima, podemos indexá-lo através de um numero, que não pode ultrapassar e nem igualar o numero total de elementos. Veja com obter o primeiro elemento do vetor MeuVetor.

// declarando um vetor de 10 elementos do tipo char

char MeuVetor[10];

// Imprimindo o primeiro elemento

printf("primeiro elemento: %c", MeuVetor[0]);

Deste modo você pode acessar qualquer elemento, sendo que o ultimo índice é sempre um numero a menos que o total, ou seja, no nosso exemplo, o ultimo seria 9.

Inicializando arrays


Para atribuir um valor a um vetor, você deve utilizar os índices, veja:

MeuVetor[0] = 'R';

Você não pode atribuir um valor a um vetor diretamente, sem especificar um índice, pois um vetor é um conjunto de dados e o operador de atribuição somente atribui um elemento de cada vez. Veja um erro de programação:

// ERRO!!! Não foi especificado um índice para o vetor

MeuVetor = 'R';

Você também poderia escrever assim:

// ERRO!!! Índice fora dos limites (maior do que 9)

MeuVetor[20] = 'R';

O exemplo acima não iria gerar um erro, pois isso ocorre por que o C não verifica se o índice que você está usando está fora dos limites. Você deve prestar muita atenção na hora de utilizar os índices para não acessar variáveis de outras partes de memória. Caso isso aconteça, geralmente seu programa trava e é terminado.

Utilizando o loop for você pode atribuir um valor para todos os membros do vetor, veja:

 1  #include <stdio.h>
 2  int main(void)
 3  {
 4      char vector[10];           // Vetor com 10 elementos

 5      int index;
 6      for (index=0; index < 10; index++)  // De 0 a 9

 7      {
 8          // 'A'+1 = B // 'A'+2 = C // e assim por diante...

 8          vector[index] = 'A'+index;
 9          printf("%c", vector[index]);
10      }
11      return 0;
12  }

Até a linha 7 você já deve ter entendido, agora, a partir da linha 8 temos um pequeno código diferente: vector[index] indica que estamos acessando um elemento no índice representado por index, que pode variar entre 0 e 9, então estaremos acessando todos os elementos do vetor.

Em seguida temos 'A'+index. Como a variável index varia entre 0 e 9, então temos A+0 até A+9. De acordo com a tabela ASCII a letra A é representada pelo numero 65, então A+5 é igual a 70, ou F no ASCII. Com isso, determinamos que será apresentado a seqüência: ABCDEFGHIJ.
Veja mais um exemplo de vetores:

#include <stdio.h>
int main ()
{
    /* Declara um vetor de inteiros de 100 posicoes */
    int num[100];
    int count=0;
    int index;

    do
    {
        printf ("\nEntre com um numero (-999 p/ terminar): ");
        scanf ( "%d", &num[count] );
        count++;
    } while ( num[count-1]!=-999 );

    printf ("\n\t Os números que você digitou foram:\n\n");

    for (index = 0; index < count; index++)
        printf (" %d",num[ index ]);

    return(0);
}

No exemplo acima, o inteiro count é inicializado em 0. O programa pede pela entrada de números até que o usuário entre com o número -999. Os números são armazenados no vetor num. A cada número armazenado, o contador do vetor é incrementado para na próxima iteração escrever na próxima posição do vetor.

Quando o usuário digita o número -999, o programa abandona o primeiro loop e por fim, todos os números são impressos. É bom lembrar aqui que nenhuma restrição é feita quanto a quantidade de números digitados. Se o usuário digitar mais de 100 números, o programa tentará ler normalmente, mas o programa os escreverá em uma parte não alocada de memória, pois o espaço alocado foi para somente 100 inteiros. Isto pode resultar nos mais variados erros no instante da execução do programa.

Declarando e inicializando arrays


Você também pode declarar e já inicializar o array inteiro, bastando a você fazer da seguinte maneira:

// primeiro modo

char nome[8] = "Rogerio";

// segundo modo

char nome[8] = {'R','o','g','e','r','i','o','\0'};
int valores[4] = { 0, 10, 200, 3000 };

Temos dois métodos para se declarar e inicializar numa mesma linha um array. O primeiro método é valido somente com o uso do tipo char, ou seja, uma cadeia de caracteres.

O segundo método é válido para qualquer tipo de dado. Note o '\0' no final da linha. Ele indica que a sequencia de caracteres terminou. Isso é valido apenas numa string (cadeia de caracteres, ou seja, um array de chars). Por isto, no segundo exemplo do segundo método não apresenta '\0' no final.

Strings em C


String é um vetor de variáveis do tipo char, ou seja, um conjunto de caracteres. Eles podem armazenar palavras ou frases. É o uso mais comum dos vetores, visto que uma palavra é formada por diversos caracteres.

Criando uma string


Para se criar uma string, primeiro você declara um vetor do tipo char com quantos elementos quiser, desde que não falte elementos para se colocar a palavra desejada. Você também só pode atribuir diretamente uma string na sua declaração. Veja um exemplo:

char nome[10] = "Rogerio";

Após a declaração da string, não podemos mais atribuir um outro texto ou palavra diretamente como fizemos acima. Se quiséssemos atribuir um outro valor, deverá utilizar uma função específica do C. Veja um erro comum:

// ERRO! sobrenome não é um vetor

char sobrenome = nome;

char nome2[20];
// CUIDADO! Não é aconselhável atribuir diretamente!

nome2 = nome;

Estes exemplos mostram erros de programação que não podem ser feitos. Isso ocorre por que eles são um tipo especial de variável, chamados de ponteiros, os quais veremos mais adiante.

Copiando strings


Para atribuir uma string a um vetor ou fazer cópias de strings, utilizamos a função strcpy, que também necessita do cabeçalho string.h. Veja um exemplo utilizando a copia:

char nome[20];
char outro_nome[20];

// copia um texto para uma variável

strcpy( nome, "copia de string" );

// copia nome para dentro de outro_nome

strcpy( nome2, nome );

Imprimindo strings


Para se imprimir strings, podemos utilizar a função printf, mas devemos colocar %s no formato para poder imprimir a string inteira. Veja:

printf("%s", nome);

Você também poderá imprimir somente caracteres da string, veja:

printf("%c", nome[0]); // imprime somente a primeira letra


Comprimento da string


O comprimento da string pode ser calculado com a função strlen, que retorna o número de caracteres presente em uma determinada string. Veja um exemplo:

#include <stdio.h>

// Cabeçalho necessário para utilizar strlen

// strcpy e outros

#include <string.h>

int main(void)
{
    int length = 0;
    char nome[15] = "Minha String";

    // length agora contém o numero de caracteres contidos na string

    length = strlen(nome);

    printf("String: %s\n", nome);
    printf("Numero de caracteres: %d", length);  // imprime o valor de length


    return 0;
}

Este programa simples mostra a quantidade de caracteres existente na string,. Para utilizar a função strlen, você precisa incluir o cabeçalho string.h.

Strings em C++


A linguagem C++ possúi um modo mais seguro e simples de se utilizar strings. Ela faz parte de um conjunto de funções e objetos chamada STL (Standard Template Library). O STL é a biblioteca padrão do C++.

Uma biblioteca nada mais é que um conjunto de código feito para nos facilitar a programação. O printf, por exemplo, faz parte da biblioteca padrão do C. Sem ela, teríamos muito mais trabalho para se mostrar um texto na tela. Teriamos que criar nós mesmo esta função, o que não seria fácil para qualquer iniciante.

Antes de mais nada, você precisa adicionar: #include <string>

Note que não há ".h" no final, sendo diferente de "string.h". Os arquivos de cabeçalho do STL não possuem extensão.

Declarando


Declarar uma string em C++ é igual declarar qualquer outra variável. Veja:

std::string meuTexto;

Note o std:: no inicio. Ela está lá apenas para identificar o namespace. Namespace é uma maneira eficiente de se evitar conflito entre nomes de funções ou variáveis entre bibliotecas. Poderei explicar sobre namespaces mais adiante, mas por enquanto, não há necessidade de se preocupar com eles. Apenas os use da forma como são mostradas.

Atribuição de valores


O STL facilita muito o uso de strings, tanto é que você pode tratá-la como sendo uma variável simples. A atribuição de valores é feita diretamente, sem o uso de funções adicionais como strcpy. Veja:

std::string meuTexto;

meuTexto = "Meu ";
meuTexto += "primeiro ";
meuTexto += "texto.";

Veja como é fácil utilizar strings desta maneira. Na realidade, a string STL é internamente equivalente a usar strcpy ou strlen, mas a diferença é que não precisamos nos preocupar com estas funções, tudo é feito automaticamente para o programador, deixando-o livre para focalizar em partes mais importantes do seu projeto.

Copiando


No C uma string não pode ser diretamente copiada para outra string, é necessario utilizar-se de funções especiais para esse processo. No C++ isso é facilitado. Veja:

std::string a = "abc";
std::string b = "xyz";
std::string c = a + b;

Note como o uso é altamente simplificado. Veja agora como poderia ser feito utilizando-se C normal.

char a[100] = "abc";
char b[100] = "xyz";
char c[100];

// copiando a em c

for (it = 0; it < strlen(a); it++)
    c[ it ] = a[ it ];

// copiando b em c

for (it = 0; it < strlen(b); it++)
    c[ it + strlen(a) ] = b[ it ];

O processo ficaria mais complicado e mais demorado para se digitar esse código. Pode não parecer muita linha de código, mas certamente faria a diferença num projeto de grande escala.

Comparando


Para se comparar duas strings apenas utilize-se de ==, como se fossem dois numeros. Veja:

// C++

std::string chave = "abc";
if (chave == "abc")
    printf("acertou");

// C

char chave[4] = "abc";
if ( strcmp(chave, "abc" ) == 0 )
    printf("acertou");

Veja como o codigo fica mais limpo e fácil de entender utilizando-se C++.

Outra coisa que ainda não mencionei é que o tamanho da std::string é aumentado automaticamente para você. Não é necessário dar um tamanho inicial a ele. No C isso deveria ser feito com o uso de ponteiros, que é um assunto mais adiante. O uso de ponteiros é muito dificil no inicio e até mesmo programadores experientes tem seus problemas com eles. Então utilizar a string da STL seria mais prático e com menos chance de gerar erros.

Escopo de variaveis


Toda variável tem um escopo, o que significa que ela tem um alcance de visibilidade. Podemos ter variáveis locais e globais.

Variabeis locais somente são visiveis dentro do bloco de código na qual foi criada, como por exemplo, dentro de uma função. Fora desta função a variável não existe.

Uma variável declarada fora de qualquer função seria tida como global e poderia ser vista por qualquer função. Mas o problema dela é que pode gerar conflito de nomes ou até mesmo erros no programa. Deve-se evitar utilizar variáveis globais ao máximo.

Para ficar ainda mais claro este conceito, vou mostrar um exemplo.

#include <stdio.h>

int variavel_global = 1;

void func()
{
    int variavel_local_1 = 2;

    // correto

    printf("%d", variavel_global);

    // correto

    printf("%d", variavel_local_1);

    // erro

    printf("%d", variavel_local_2);
}

int main()
{
    int variavel_local_2 = 3;

    // correto

    printf("%d", variavel_global);

    // erro

    printf("%d", variavel_local_1);

    // correto

    printf("%d", variavel_local_2);

    return 0;
}

Veja que variavel_global pode ser vista dentro das duas funções: func e main. Mas a variavel_local_1 pode ser vista apenas dentro da função func e a variavel_local_2 pode ser vista apenas dentro da função main, pois elas foram declaradas com escopo reduzido, ou seja, localmente. Para o resto do programa, estas variáveis não existem.

Variáveis locais em blocos


Outro meio de se criar variáveis locais em C++ é colocando-as em blocos delimitados por chaves { e }.
Veja:

// Somente em C++


int main()
{
    int var_1 = 111;

    // inicio do bloco

    {
        var_2 = 222;

        // correto

        printf("var_1 = %d", var_1);

        // correto

        printf("var_2 = %d", var_2);
    }
    // fim do bloco


    // correto

    printf("var_1 = %d", var_1);

    // erro - variável não existe fora do bloco

    printf("var_2 = %d", var_2);

    return 0;
}

Como pode observar, criamos um bloco separado dentro da função main. Dentro deste bloco declaramos uma variável chamada var_2. Ela somente é visivel dentro do bloco, caso tente acessá-la fora dele, gerará um erro de compilação.

Quando o bloco termina de ser executado, todas as variáveis declaradas dentro dele serão retiradas da memória e ficarão inacessíveis para qualquer código de fora.

Variáveis locais no loop for


Seguindo-se o mesmo conceito anterior, pode-se criar uma variável local somente para o loop for. Veja:

// Somente em C++


int main()
{
    for (int count=0; count < 10; count++)
    {
        printf("%d", count);
    }

    // erro - variável não existe fora do bloco

    printf("%d", count);

    return 0;
}

A variavel count não pode ser vista fora do bloco for. Se fosse tentar compilar este pequeno código, geraria um erro de compilação.

Funções com argumentos


Você já aprendeu a utilizar diversos tipos de código e instruções da linguagem, agora estamos chegando ao final deste tutorial e iremos voltar ao assunto sobre funções. Você já aprendeu como criar funções simples, mas neste artigo irei mostrar como extender suas funcionalidades, utilizando-se de parametros e retornos.

Utilizar parametros em uma função é extremamente simples após se saber como criar uma função básica. Primeiro vamos a um exemplo e depois irei a explicação.

// criando uma função com parametro

void mostrarNumero( int num )
{
    printf( "seu numero é: %d", num );
}

// chamando a função acima

mostrarNumero( 123 );

Veja que foi adicionado algo dentro dos parenteses na criação da função. Dentro temos: int num.

Isso significa que a função precisa de um número para funcionar. Este número é representado por uma variável do tipo int.

Você pode não ter percebido antes, mas utilizou diversas funções com parametros. Sendo que printf é uma delas.

Na linha: mostrarNumero( 123 ) estamos chamando a função, e passando um valor a ela. Este valor é atribuido para a variável num, que é então utilizada dentro do corpo da função.

Mas você não está limitado a somente um parametro. Pode-se utilizar muitos parametros, mas é indicado não mais que 5 ou 7 parametros. Mais do que isso pode complicar o seu uso ou dificultar o entendimento. Veja outro exemplo:

void soma( int a, int b )
{
    // voce poderia fazer assim

    printf( "O resultado da soma é: %d", a+b );

    // ou assim

    int resultado = a + b;
    printf( "O resultado da soma é: %d", resultado );

    // ou assim

    printf( "O resultado de %d + %d é %d", a, b, a+b );

    // ou ainda de qualquer outra forma

}

Neste exemplo utilizamos dois parametros, com três modos de uso. Mas são apenas exemplos de como você poderia utilizá-los. Você poderia chamar assim: soma(10, 20). Neste caso, a função iria somar 10 e 20.

Note também que os parametros não precisam ser do tipo int. Eles poderiam ser de qualquer tipo existente na linguagem.

Distinção entre argumento e parâmetro


Na computação, geralmente se fala sobre estas duas palavras, mas alguns programadores as utilizam de forma igual. Na realidade o significado é diferente.

Parametro são variaveis os quais recebem valores em uma função.

Argumentos são os valores passados quando se chama uma função.

Argumentos por referencia


Os argumentos são passados por valor na função. Isso significa que uma cópia da variavel é gerada e então passada para a função. Mesmo que uma função modifique o parametro recebido, a variavel original ainda permanecerá a mesma. Veja:

void soma( int a, int b, int resultado)
{
    resultado = a + b;
}

// testando

int calculado = 0;
soma( 10, 20, calculado );

// irá mostrar o resutado 0 e não 30, como esperado

printf( "%d", calculado );


// exemplo de como seria o código interno

int calculado = 0;

// chamando a função soma

// soma( 10, 20, calculado );

// soma(  a,  b, resultado );

int a = 10;
int b = 20;
int resultado = calculado;
resultado = a + b;
// fim da função


printf( "%d", calculado );

Se formos testar esta função, não obteríamos o resultado desejado. Lembre-se que é feita uma cópia da variável calculado quando a função é executada. É esta cópia que estamos manipulando dentro do corpo da função. De uma forma mais simples, estamos manipulando a variavel resultado ao invés da variável calculado.

Para se obter o resultado desejado, devemos passar o argumento por referencia. Veja:

// note o sinal & antes do parametro resultado

void soma( int a, int b, int &resultado)
{
    resultado = a + b;
}

// testando

int calculado = 0;
soma( 10, 20, calculado );

// irá mostrar o resutado 30

printf( "%d", calculado );

O sinal & antes do parametro indica que este parametro está sendo passado por referencia, ou seja, ele passa o endereço de memória da variavel ao invés do valor. Isso significa que quando você chamar a função, o parametro resultado será visto como um apelido para a variável calculado.

Se voce modificar uma referencia, seria a mesma coisa que modificar a variavel que está sendo referenciada. Veja:

int a = 20;
int &b = a;

// mostra 20 20

printf( "%d %d", a, b );

b = 30;

// mostra 30 30

printf( "%d %d", a, b );

A variavel a contém o valor 20. Já a variavel b contém a referencia de a e não um valor direto. Se você modifica b, está modificando a.

Isso acontece porque toda variável tem um endereço de memória. A variável a tem um endereço. A referencia b está apontando para o endereço de a. Então na verdade é como se fossem a mesma variável, mas com outro nome. Eu digo é como se fosse, mas na realidade não é. Talvez isso fique mais claro no próximo artigo, onde falaremos sobre ponteiros.

Funções com retorno


As funções podem ter um retorno (como visto na lição anterior), o que quer dizer que elas podem serem executadas e dar algo em troca. Seria como se fosse um moedor de carne. Você gira a manivela, ou seja, a função é executada e no final ela lhe devolve carne moida.

Vamos ver se fica mais claro depois deste exemplo.

int soma( int a, int b)
{
    return a + b;
}

// res irá ter o valor 30

int res = soma( 10, 20 );

Note que não estamos mais usando VOID no inicio, mas o tipo INT. Ela indica que tipo de retorno a função deve fornecer. Neste caso, iremos obter um resultado do tipo int.

Observe também a palavra return. Ela é uma instrução usada para se terminar a função e retornar um valor ou não. Isso porque esta instrução quando é acionada, faz com que a função termine. Caso a função precisa retornar algo, então deve se especificar o valor a ser retornado.

Poderiamos muito bem fazer uma função do tipo:

void soma( int a, int b)
{
    return;
    printf( "%d", a + b );
}

Executando a função acima não daria em nada, pois antes mesmo de se executar o printf, a instrução return faria com que a função terminasse. Note que não adicionamos nenhum valor depois de return. Isso porque não precisamos, pois a função soma não possui nenhum valor que precisa ser retornado. Note que temos void como tipo a ser retornado. Este tipo significa vazio ou nenhum tipo. Mesmo que a função não retorne nada, ela precisa conter o void no inicio.

Caso o void fosse substituido por um tipo qualquer, digamos um int, então o return deveria ser seguido por um valor, mesmo que fosse um valor qualquer.

Retornando strings


Strings criados com std::string podem ser retornados normalmente, como nos exemplos anteriores. Veja

std::string getName_A()
{
   std::string name = "abc";
    return name;
}

std::string getName_B()
{
    return "abc";
}

std::string getName_C()
{
    return std::string("abc");
}

int main()
{
    // correto

    std::string my_name_a = getName_A();

    // correto

    std::string my_name_b = getName_B();

    // correto

    std::string my_name_c = getName_C();

    return 0;
}

Todas as funções estão corretas e podem ser utilizadas normalmente. No exemplo 2 (getName_B) o que está acontecendo é uma conversão de uma constante para uma std::string. Antes da função retornar o valor, ele é transformado em uma string stl e só então o retorna, para ser compatível com o tipo de retorno. Seria a mesma coisa nos três casos (A, B e C).

Função e rotina


Até o presente artigo, eu estive falando sobre funções, mas não sobre rotinas. Na computação elas se diferenciam pelo fato de função ser um bloco de código que retorna um valor, enquanto que rotina não.

Mas para facilitar, estarei chamando rotinas e funções da mesma maneira que estive até agora, ou seja, como funções.




Todos os artigos da Developers3Soft podem ser copiados e redistribuidos livremente.
Apenas considere que os creditos devem ser mantidos e que não se cobre nenhuma taxa pelos textos, em parte ou em sua totalidade. Podem ser também inseridos em sua página se assim desejar ou criar um conjunto de textos selecionados em um unico arquivo.
Qualquer alteração deve ser indicada, assim como a data de modificação. A única restrição de alteração é manter os creditos originais e a origem do texto.
Faça bom proveito.

De sua nota para este artigo.
 

Developers3