domingo, 28 de setembro de 2014

Estrutura de Dados - Alocação Estática e Dinâmica de Memória

Alocação de Memória


Ao criar um programa em “C” usualmente temos que especificar as variáveis que vamos usar antes
de começar a executar o programa, reservando assim um espaço na memória.
As variáveis que são alocadas em posições fixas da memória são chamadas de variáveis estáticas, e as
variáveis que não possuem uma posição fixa e que são criadas e destruídas durante a execução 
do programa são chamadas de variáveis dinâmicas.

A alocação de memória no computador pode ser dividida em dois grupos principais:
  • Alocação Estática: os dados tem um tamanho fixo e estão organizados sequencialmente na memória do computador. Um exemplo típico de alocação estática são as variáveis globais, e os vetores (estáticos).
  • Alocação Dinâmica: os dados não precisam ter um tamanho fixo, pois podemos definir para cada dado quanto de memória que desejamos usar. Sendo assim vamos alocar espaços de memória (blocos) que não precisam estar necessariamente organizados de maneira sequencial, podendo estar distribuídos de forma esparsa na memória do computador. Na alocação dinâmica, vamos pedir para alocar/desalocar blocos de memória, de acordo com a nossa necessidade, reservando ou liberando blocos de memória durante a execução de um programa. Para poder “achar” os blocos esparsos na memória usamos as variáveis do tipo Ponteiro (indicadores de endereços de memória). As variáveis locais e os parâmetros passados por valor são alocados dinamicamente.

Alocação Estática de Memória:


As estruturas de dados para armazenar um conjunto de dados (exemplo: um cadastro com
vários registros), podem ser organizadas de formas diferentes, de acordo com a maneira que os
dados são inseridos e retirados da memória do computador. As formas mais usuais são: as listas
lineares sequenciais (vetores simples), as filas, as pilhas e os deques.

Listas lineares sequenciais:


Uma maneira interessante de manipular este tipo de estruturas de dados, é através da
construção de um conjunto de rotinas genéricas e modulares de manipulação de listas seqüenciais.
Vamos aqui descrever uma possível proposta de um conjunto de rotinas empregadas para este fim.
Rotinas básicas de manipulação de Vetores:
- Estruturas de dados com alocação estática
- Inserção no final do vetor
- Remoção lógica dos elementos
Aplicação típica:
- Pequenos cadastros

Estrutura de dados: 
         typedef int Tipo_Dado;
         typedef struct {
                                 Tipo_Dado Dado [MAX_VETOR];
                                 int Excluido [MAX_VETOR];
                                 int Inicio, Fim;
         } Tipo_Vetor;

Rotinas:
  void inicializa_vetor (Tipo_Vetor *V);
  int insere_vetor (Tipo_Vetor *V; Tipo_Dado Dado);
  int consulta_vetor (Tipo_Vetor V; int Indice; Tipo_Dado *Dado);
  int acha_vetor (Tipo_Vetor V; Tipo_Dado Dado; int *Indice);
  void lista_vetor (Tipo_Vetor V);
  int exclui_vetor (Tipo_Vetor *V; int Indice);
  int atualiza_vetor (Tipo_Vetor *V; int Indice; Tipo_Dado Novo_Dado);
  void compacta_vetor (Tipo_Vetor *V);
  int vazio_vetor (Tipo_Vetor V);
  int quantidade_vetor (Tipo_Vetor V);

Exemplo: inserção de dados no vetor
 int insere_vetor (V, Dado)
 Tipo_Vetor *V;
 Tipo_Dado Dado;
 {
   if (V->Fim < MAX_VETOR) /* Vetor nao esta cheio ? */
     {
       V->Dado[V->Fim]=Dado;
       V->Excluido[V->Fim]=FALSO;
      (V->Fim)++;
       return(OK);
      }
   else
     return(ERRO);
  }
                                    

Filas – FIFO = “First In, First Out”:

Construção de um conjunto de rotinas genéricas e modulares de manipulação de filas.
Vamos aqui descrever uma possível proposta de um conjunto de rotinas empregadas para este fim.
Rotinas básicas de manipulação de FILAS usando vetores:
- Estruturas de dados com alocação estática
- Inserção no final da fila
- Remoção do início da fila
- Fila circular

Aplicação típica:
- Lista de elementos a espera de um tratamento

Estrutura de dados:
 typedef int Tipo_Dado;
 typedef struct {
                          Tipo_Dado Dado [MAX_FILA];
                          int Inicio, Fim;
                         } Tipo_Fila;

Rotinas:
 void inicializa_fila (Tipo_Fila *F);
 int insere_fila (Tipo_Fila *F; Tipo_Dado Dado);
 int retira_fila (Tipo_Fila *F; Tipo_Dado *Dado);
 void lista_fila (Tipo_Fila F);
 int consulta_fila (Tipo_Fila F; int Indice; Tipo_Dado *Dado);
 int cheia_fila (Tipo_Fila F);
 int vazia_fila (Tipo_Fila F);
 int quantidade_fila (Tipo_Fila F);
 int acha_fila (Tipo_Fila F; Tipo_Dado Dado; int *Indice);

Exemplo: inserção de dados na fila
 int insere_fila (F, Dado)
 Tipo_Fila *F;
 Tipo_Dado Dado;
 {
   int prox;
   prox=F->Fim+1;
   if (prox == MAX_FILA)
        prox=0;
   if (prox == F->Inicio)
       return(ERRO);
   else
        {
          F->Dado[F->Fim]=Dado;
          F->Fim=prox;
          return(OK);
        } 
  }

Pilhas – LIFO = “Last In, First Out”:

Construção de um conjunto de rotinas genéricas e modulares de manipulação de pilhas.
Vamos aqui descrever uma possível proposta de um conjunto de rotinas empregadas para este fim.
Rotinas básicas de manipulação de PILHAS usando vetores:
- Estruturas de dados com alocação estática
- Inserção no topo da pilha
- Remoção do topo da pilha
Aplicação típica:
- Lista de “tarefas pendentes”, passagem de parâmetros nas linguagens de programação

Estrutura de dados:
 typedef int Tipo_Dado;
 typedef struct {
                         Tipo_Dado Dado [MAX_PILHA];
                         int Base, Topo;
                        } Tipo_Pilha;
Rotinas:
 void inicializa_pilha (Tipo_Pilha *P);
 int insere_pilha (Tipo_Pilha *P; Tipo_Dado Dado);
 int retira_pilha (Tipo_Pilha *P; Tipo_Dado *Dado);
 void exibe_pilha (Tipo_Pilha P);
 int quantidade_pilha (Tipo_Pilha P);
 int cheia_pilha (Tipo_Pilha P);
 int vazia_pilha (Tipo_Pilha P);
 void esvazia_pilha (Tipo_Pilha *P);

Exemplo: inserção de dados na pilha
 int insere_vetor (P, Dado)
 Tipo_Vetor *P;
 Tipo_Dado Dado;
 {
   if (V->Fim < MAX_VETOR) 
     {
       P->Dado[P->Fim]=Dado;
       P->Excluido[P->Fim]=FALSO;
      (P->Fim)++;
       return(OK);
      }
   else
     return(ERRO);
  }

Deque – “Double Ended Queue”:


Construção de um conjunto de rotinas genéricas e modulares de manipulação de deques.
Vamos aqui descrever uma possível proposta de um conjunto de rotinas empregadas para este fim.

Rotinas básicas de manipulação de DEQUES usando vetores:
- Estruturas de dados com alocação estática
- Inserção no início ou no final do deque
- Remoção do início ou do final do deque
- Estrutura de dados “circular”

Aplicação típica:
- Lista de elementos com múltiplas formas de considerar/manipular a ordem destes

Estrutura de dados:
 typedef int Tipo_Dado;
 typedef struct {
                         Tipo_Dado Dado [MAX_DEQUE];
                          int Inicio, Fim;
                        } Tipo_Deque;
Rotinas:
 void inicializa_deque (Tipo_Deque *D);
 int insere_inicio_deque (Tipo_Deque *D; Tipo_Dado Dado);
 int insere_final_deque (Tipo_Deque *D, Tipo_Dado Dado);
 int retira_inicio_deque (Tipo_Deque *D; Tipo_Dado *Dado);
 int retira_final_deque (Tipo_Deque *D; Tipo_Dado *Dado);
 void lista_deque (Tipo_Deque D);
 int acha_deque (Tipo_Deque D; Tipo_Dado Dado; int *Indice);
 int cheio_deque (Tipo_Deque D);
 int vazio_deque (Tipo_Deque D);
 int quantidade_deque (Tipo_Deque D);
 void apaga_deque (Tipo_Deque *D);


Alocação de Dinâmica de Memória:


As principais características da alocação dinâmica de memória são:
- Os dados se encontram espalhados na memória do computador em vários blocos;
- Geralmente as estruturas de dados são compostas por registros que incluem um campo
do tipo ponteiro (elo/link), o que nos permite encadear os dados e indicar onde está o
dado seguinte na memória (visto que os dados estão espalhados na memória do
computador);
- Podemos ir solicitando mais e mais memória a medida em que precisarmos de mais
espaço para armazenar as informações. Isso nos permite criar programas que usam
apenas a memória necessária... e por conseqüência, podemos rodar outros programas,
em uma mesma máquina, sem que um único programa monopolize toda a memória
disponível desta.
- Podemos liberar espaços de memória quando estes não forem mais necessários ao
programa.

Estas estruturas criadas com registros que são encadeados através do uso de ponteiros, que
estes blocos espalhados pela memória, vão resultar em estruturas denominadas de “listas
encadeadas” de alocação dinâmica. A figura abaixo mostra um exemplo de lista encadeada,
baseada na estrutura de dados descrita logo mais abaixo:


Listas encadeadas simples:

Construção de um conjunto de rotinas genéricas e modulares de manipulação de listas
encadeadas simples. Vamos aqui descrever uma possível proposta de um conjunto de rotinas
empregadas para este fim.
Rotinas básicas de manipulação de listas encadeadas simples:
- Estruturas de dados com alocação dinâmica
- Inserção no inicio da lista, no final da lista, ou de modo ordenado
- Remoção de qualquer elemento da lista (início, final, ou elemento especificado)

Aplicação típica:
- Lista de elementos de tamanho variável

Estrutura de dados:
 typedef int Tipo_Dado;
 typedef struct bloco {
                                   Tipo_Dado Dado;
                                   struct bloco *Proximo;
                                   } Nodo;
Rotinas:
 void inicializa_lista (Nodo **N);
 int insere_inicio_lista (Nodo **N, Tipo_Dado Dado);
 int insere_fim_lista (Nodo **N, Tipo_Dado Dado);
 int insere_ordenando_lista (Nodo **N, Tipo_Dado Dado);
 int remove_inicio_lista (Nodo **N, Tipo_Dado *Dado);
 int remove_fim_lista (Nodo **N, Tipo_Dado *Dado);
 int remove_elemento_lista (Nodo **N, Tipo_Dado Dado);
 int quantidade_lista (Nodo *N);
 void exibe_lista (Nodo *N);
 int pesquisa_lista (Nodo **N, Tipo_Dado Dado);
 int percorre_lista (Nodo **N, Tipo_Dado *Dado);
 void apaga_lista (Nodo **N);

Exemplo: inserção de dados no inicio da lista encadeada
 int insere_inicio_lista (N, Dado)
 Nodo **N;
 Tipo_Dado Dado;
 {
   Nodo *novo;
    novo = (Nodo *) calloc ( 1, sizeof (Nodo) );
    if ( novo == NULL )
         return (ERRO); /* Não conseguiu alocar espaço na memória */
         novo -> Dado = Dado;
         novo -> Proximo = *N;
        *N = novo;
         return (OK);
  }

Exemplo: inserção de dados no final da lista encadeada
 int insere_fim_lista (N, Dado)
 Nodo **N;
 Tipo_Dado Dado;
{
  Nodo *aux, *novo;
  novo = (Nodo *) calloc ( 1, sizeof (Nodo) );
  if ( novo == NULL )
       return(ERRO);
       novo -> Dado = Dado;
       novo -> Proximo = NULL;
  if ( *N == NULL )
       *N = novo;
  else {
           aux = *N;
           while ( aux -> Proximo != NULL )
                      aux = aux -> Proximo;
                      aux -> Proximo = novo;
         }
  return (OK)
 }

Listas duplamente encadeadas

Construção de um conjunto de rotinas genéricas e modulares de manipulação de listas
duplamente encadeadas. Vamos aqui descrever uma possível proposta de um conjunto de rotinas
empregadas para este fim.

Rotinas básicas de manipulação de listas duplamente encadeadas:
- Estruturas de dados com alocação dinâmica
- Inserção no inicio da lista, no final da lista, ou de modo ordenado
- Remoção de qualquer elemento da lista (início, final, ou elemento especificado)

Aplicação típica:
- Lista de elementos de tamanho variável, permite percorrer a lista nos dois sentidos
Estrutura de dados:
 typedef int Tipo_Dado;
 typedef struct bloco_ld {
                                        Tipo_Dado Dado;
                                        struct bloco_ld *Proximo, *Anterior;
                                       } Nodo_LD;

Rotinas:
 void inicializa_ld (Nodo_LD **LD);
 void posiciona_inicio_ld (Nodo_LD **LD);
 void posiciona_fim_ld (Nodo_LD **LD);
 int insere_antes_ld (Nodo_LD **LD, Tipo_Dado Dado);
 int insere_depois_ld (Nodo_LD **LD, Tipo_Dado Dado);
 int insere_inicio_ld (Nodo_LD **LD, Tipo_Dado Dado);
 int insere_fim_ld (Nodo_LD **LD, Tipo_Dado Dado);
 int insere_ordenando_ld (Nodo_LD **LD, Tipo_Dado Dado);
 int pesquisa_ld (Nodo_LD **LD, Tipo_Dado Dado);
 int remove_nodo_ld (Nodo_LD **LD, Tipo_Dado *Dado);
 int remove_dado_ld (Nodo_LD **LD, Tipo_Dado *Dado);
 int quantidade_ld (Nodo_LD *LD);
 void exibe_ld (Nodo_LD *LD);
 int percorre_lista (Nodo_LD **LD, Tipo_Dado *Dado);
 void apaga_ld (Nodo_LD **LD);

Exemplo: posiciona o ponteiro no início da lista duplamente encadeada
 void posiciona_inicio_ld (LD)
 Nodo_LD **LD;
{
  if ( *LD != NULL )
                                 {
                                   while ( (*LD) -> Anterior != NULL )
                                 *LD = (*LD) -> Anterior;
                                  }
}

Exemplo: inserção de dados antes da posição apontada na lista duplamente encadeada
int insere_antes_ld (LD, Dado)
Nodo_LD **LD;
Tipo_Dado Dado;
{
 Nodo_LD *novo, *aux;
 novo = (Nodo_LD *) calloc ( 1, sizeof (Nodo_LD) );
 if ( novo == NULL )
                                 return (ERRO);
                                 novo -> Dado = Dado;
if ( *LD == NULL )
                                {
                                  *LD = novo;
                                   novo -> Anterior = NULL;
                                   novo -> Proximo = NULL;
}
else
     {
      aux = (*LD) -> Anterior;
      (*LD) -> Anterior = novo;
      novo -> Proximo = (*LD)
      novo -> Anterior = aux;
      if ( aux != NULL )
      aux -> Proximo = novo;
     }
return (OK);
}

Exemplo: inserção de dados no início da lista duplamente encadeada
int insere_inicio_ld (LD, Dado)
Nodo_LD **LD;
Tipo_Dado Dado;
{
  posiciona_inicio_ld(LD);
  return ( insere_antes_ld (LD, Dado) );
}

Filas, Pilhas, Deques e Ordenação usando alocação dinâmica:

As filas, pilhas e deques podem ser facilmente implementadas usando rotinas genéricas de
manipulação de listas, sejam estas simples ou duplamente encadeadas. Uma vez que podemos
implementar facilmente rotinas de inserção no início e/ou no fim de uma lista encadeada, e também
podemos implementar facilmente rotinas de remoção do início e/ou do fim de uma lista encadeada
com alocação dinâmica, por conseqüência, podemos criar rotinas de manipulação destas outras
estruturas de dados baseadas nas rotinas descritas anteriormente. É importante salientar que em
alguns casos talvez seja interessante criar rotinas mais otimizadas, como por exemplo, na inserção
de nodos no final de uma lista. Neste caso, seria interessante que fosse evitada a necessidade de
percorrer toda a lista até encontrar o nodo final, cada vez que um novo nodo fosse adicionado no
final desta lista.
Filas:
- Insere no início
- Retira do fim
Pilhas:
- Insere no fim
- Retira do fim
Deques:
- Insere no início ou no fim
- Retira do início ou do fim
Ordenação: 
- A inserção pode ser feita em qualquer posição, o que facilita a ordenação

Caso queiram ter uma menor abstração e aprimorar os conceitos do conteúdo abordado neste post, recomendo os videos abaixo: 

Estrutura de dados - Lista estática


Estrutura de dados - Pilhas, Filas e Deque


Estrutura de dados - Alocação dinâmica de memória


quarta-feira, 24 de setembro de 2014

S T R U C T


Struct em linguagem C


Uma struct é uma variável especial que contém diversas outras variáveis normalmente de tipos diferentes.

As variáveis internas contidas pela struct são denominadas membros da struct.

Podemos dizer que as structs da linguagem C são o equivalente ao que se denomina registros em outras linguagens de programação.

A palavra reservada struct indica ao compilador que está sendo criada uma estrutura.


Abaixo a sintaxe e modo de utilização de uma  S t r u c t :


  " struct nome_da_estrutura { tipo_de_dado nome_do_membro; }; "


struct data {

int dia;

int mes;

int ano;

};
int main (void){

data hoje;

hoje.dia = 24;

hoje.mes = 9;

hoje.ano = 2014;

}





Inicialização dos campos da estruturas


A inicialização dos campos de uma estruturas é semelhante à inicialização de um arranjo. Os valores para cada um dos membros são escritos entre chaves e separados por vírgula, na ordem em que foram declarados.

Exemplo 1 :
struct funcionario

{ char nome[50];

double salario;

} x, y, z;

struct funcionario x = {“Jõao da Silva”, 370.00};

struct funcionario y = {“Fernando de Souza Junior”, 450.00};

struct funcionario z = {“Geremias dos Santos”, 1530.00};
 


Exemplo 2 :
struct data {

int dia;

int mes;

int ano;

} hoje;

struct data hoje={24,09,2014};


Se ainda surgir dúvidas sobre o assunto  STRUCT  basta assistir o vídeo abaixo para ajudá-lo a desenvolver melhor o conceito de estruturas em C . 








Espero que tenham gostado do assunto.


Em breve mais informações sobre linguagem C e estruturas de dados .


Ponteiros

PONTEIROS

Os conceitos de endereço e ponteiro são fundamentais em qualquer linguagem de programação (embora sejam mais visíveis em C que em outras linguagens).  O conceito de ponteiro é muito útil mas difícil; seu domínio exige um certo esforço.

Da mesma maneira que existem em C variáveis do tipo char, int e float, existem variáveis do tipo ponteiro. As variáveis do tipo ponteiro armazenam endereços de memória e são utilizadas por 3 razões específicas na programação:

·                     permitem a modificação de argumentos de funções: permitem que uma função altere valores de variáveis não globais e não locais a ela através da referência ao endereço de memória da variável passada como parâmetro para a função;

·                     permitem o uso de rotinas de alocação dinâmica de memória: alocação e desalocação de memória em tempo de execução conforme a necessidade do programa;

·                     aumento de eficiência em determinadas rotinas.

O ponteiro nada mais é do que uma variável que guarda o endereço de uma outra variável. A forma de declaração de uma variável ponteiro é:

tipo  *nome_variável      //tipo = char, int ou float

onde tipo é o tipo de variável apontada pela variável ponteiro.

Por exemplo:
float  *p;      // p é um ponteiro de float

Ou seja, p apontará para uma região de memória que armazena um valor float. 

A declaração de ponteiro não tem o mesmo significado da declaração de uma variável. Ela indica apenas o tipo de objeto de dados apontado e, desde que contém endereço de memória, o tamanho em bytes que ocupa não tem relação com o tamanho do objeto apontado. O tamanho do ponteiro é fixo e depende apenas do modelo de memória do sistema (2 bytes ou 4 bytes, normalmente).

Para declarar mais de um ponteiro por linha, usa-se um operador indireto (*) para cada

char *ch1, *ch2; (são ponteiros para o tipo char).

Se um operador for omitido (exemplo: char *ch1, ch2;), a variável correspondente não será ponteiro e, certamente, provocará erro de execução se usada como tal.

O ponteiro pode ser declarado para qualquer tipo legal de variável em C (charintfloatdouble, etc), além de void, que seria um genérico, podendo apontar para qualquer tipo de dado.

INICIALIZANDO UM PONTEIRO

A simples declaração de um ponteiro não o faz útil. É necessária a indicação da variável para a qual ele aponta.


int var;
int *ptr;
var = 10;
ptr = &var;





Na seqüência acima, são declarados uma variável tipo int (var) e um ponteiro para o mesmo tipo (ptr). A terceira linha atribui o valor 10 a var e a última linha inicializa o ponteiro ptr.

Observa-se o uso do operador de endereçamento (&) para inicialização do ponteiro. Isso significa, no código ptr = &var;, que ptr passa a conter o endereço de var, não o seu valor.

Supondo que o sistema é endereçado por 2 bytes, a Figura 01 acima dá uma idéia gráfica dessa associação: o conteúdo de ptr é 4052, que é o endereço do primeiro byte da variável var (ptr ocupa 2 bytes por causa do endereçamento do sistema e var também ocupa 2 bytes, mas por ser do tipo int).
O valor 4052 para a posição de memória de var é apenas ilustrativo. Na prática, dependerá do local de memória onde o programa foi carregado.

Com ptr apontando para var, é possível realizar operações com esta última de forma indireta, a partir de ptr. Exemplos a seguir.

Acrescentando a linha:

int newVar = *ptr;

ao código anterior, o valor de newVar é 10, que é o valor de var lido indiretamente através de ptr.

E a linha:

*ptr = 20;

modifica o valor de var para 20, ou seja, altera de forma indireta através de ptr.

É importante lembrar que um ponteiro declarado e não inicializado poderá ter conteúdo nulo ou aleatório, a depender da alocação sistema. Nessa condição, se o conteúdo apontado for modificado, algumas posições de memória terão seus valores indevidamente alterados e as consequências serão imprevisíveis.

CONCLUSÃO


Um ponteiro é uma variável que guarda um endereço de uma outra variável. Sabemos como declara-las e que antes de utiliza-las é necessário atribuir um endereço válido. Podemos utilizar ponteiros para ponteiros. O uso de ponteiro é importante em muitos casos e que se deve tomar muito cuidado ao usa-los.

quinta-feira, 18 de setembro de 2014

Matrix... perdão. Matriz, vetor e array.

VETORES, ARRAY e MATRIZES



Conforme prometido, continuamos a falar da linguagem C, uma linguagem propícia para tratar do assunto "estrutura de dados".

Vamos abordar o tema de vetores e matrizes, ou seja os arrays. O que são vetores?

Vamos responder assim, em diversas situações apenas os tipos básicos de dados (int, char, float, double...), não servem para representar alguma informação. 

Existe a possibilidade de criarmos tipos de dados a partir da composição ou abstração de tipos de dados primitivos. Estes tipos são denominados a estrutura de dados, que define como os tipos de dados estão organizados, logo, quando esta estrutura for composta por conjuntos de dados do mesmo tipo, teremos um conjunto homogêneo.

Estas variáveis compostas homogêneas unidimensionais, são arranjos para representar elementos unidimensionais (linhas), do mesmo tipo, ou seja, representar um Vetor.

Assim sendo podemos afirmar que uma Matriz(Array) que seja Unidimensional é um Vetor, portanto uma matriz multidimensional são vários vetores organizados através de índices.

Podemos acessar então os dados de um vetor através de um índice, no qual estes dados estão ordenados. Os índices por sua vez, começam em 0.

Para poder visualizar melhor, vemos o exemplo abaixo, um vetor contendo os nomes dos alunos e, uma matriz contendo a nota dos alunos por trimestre.



A ilustração mostra os índices como: 1 a 4 e 1 a 50.

Porém não podemos esquecer que o 1º índice é o 0, então se quisermos 50 índices, eles serão de 0 a 49.

Veremos um pouco da sintaxe

Para declarar um vetor de inteiros fazemos:

int vet[5];  //este vetor é do tipo inteiro e tem 5 elementos de 0 a 4.

Para declarar uma matriz bidimensional:

int mtz[5][2];

Agora vamos fornecer valores para um vetor e uma matriz de números reais do tipo float:

float vet[4]={1.5,5.5,8.0,6.2};//Entre chaves, cada número separado por ','

float mtz[2][2]={{0.1,0.2},{1.1,1.2}} 


STRINGS - VETORES DE CHAR

Isso mesmo, as strings que são do tipo mais comum dentre os arrays, são conjuntos ordenados homogêneos de caracteres (char), ou seja, são vetores de char.

Em C as bibliotecas padrão possuem diversas funções para manipulação de strings como <string.h>.

Não podemos esquecer que uma string tem como seu último elemento o '\0', isto é, o número inteiro zero.

Declaração de string:


char nome_da_string[tamanho_da_string];

Exemplo:

char string[50];

char matriz[20][12];

As strings devem ser igualadas elemento a elemento não podemos então fazer:

string1=string2;

Existem diversas maneiras de se tratar e manipular este tipo de arranjo, 

Ficam aqui os comandos mais utilizados:


  • gets /* Pega os caracteres digitados pelo teclado e organizam na string correspondente */ 
Ex: gets(string1);

  • strcpy /* Copia uma string em outra string, a string1(origem) recebe a string2(destino)*/
Ex: strcpy(string2, string1);

  • strcat /*Concatena duas strings, a string1 de origem, permanece inalterada, mas seu conteúdo será anexado ao fim da string2 de destino.*/
Ex: strcat(string2, string1);

  • strlen /* Retorna um valor inteiro correspondente ao tamanho da string em questão, serve para medir o número de elementos*/
Ex: tamanho = strlen(string1); //a variável int tamanho recebe o valor inteiro

  • strcmp /* Compara duas strings, se as duas strings forem idênticas, ela retorna o valor 0, se não forem idênticas o valor retornado será diferente de 0*/
Ex: 

if ( (strcmp(string1, string2) == 0)
{
printf("Acesso liberado");
}
else
{
printf("Acesso negado");
}

Reparem que neste trecho de código, eu comparei duas strings, o que poderiam ser uma string representando a senha armazenada em banco de dados, e a outra representando a senha digitada pelo usuário. Ao comparar as duas, se forem idênticas, a mensagem de acesso liberado aparece, pois foi digitada a senha correta. Caso contrário, se não forem iguais, a senha obviamente está errada e a mensagem aparece de acesso negado.

Segue uma vídeo aula bastante clara sobre strings, caso haja alguma dúvida sobre o tema.


















quinta-feira, 4 de setembro de 2014

Linguagem C


#include<stdio.h>
#include<stdlib.h>

int main ()
{

char aula03[11] = {'L', 'i', 'n', 'g', 'u', 'a', 'g', 'e', 'm', ' ', 'C'};


         printf("\n  A NOSSA TERCEIRA AULA :\t %s", aula03);

getch ();

return 0;

}


A Linguagem C, foi criada em 1972 por Dennis Ritchie e, é uma linguagem estruturada que permite um excelente controle de estrutura de dados, a linguagem C tem cientificidade e oferece ao programador alto controle granular.

C é uma linguagem compilada, ou seja, o código fonte é inteiramente transformado em um arquivo executável antes do programa começar a rodar, nesta fase, se houver qualquer tipo de erro, o programa não será compilado.

Para começar a programar em C, temos que conhecer o formato da sua sintaxe.

Primeiro se declaram as bibliotecas que serão usadas, seguido das funções. Dentro de cada função declaramos as variáveis, os comandos e as operações que vão executar e, por fim, o valor que as funções retornam.

O início de cada função é dado pela abertura de chave "{", e o final pelo seu fechamento "}".

A Função principal é chamada "main", declaramos ela de forma padrão como "int main".

Dois comandos que são muito utilizados em C são, o printf e o scanf. Que são comandos de entrada e saída de dados. O scanf capta as informações digitadas no teclado e o printf exibe informações na tela.

Diferente do C++ (cin e cout), printf e scanf  fazem clara alusão ao conceito de ponteiros, que é muito importante para entender a matéria Estrutura de Dados e com certeza veremos em breve. Trata-se de reservar um espaço na memória e depois apontar um valor para aquele espaço reservado.

Vamos ver um programa básico no vídeo abaixo, para entender melhor como um código em C funciona.


Estes são os conceitos básicos da linguagem C.