minerva ufrj

Ponteiros

Em Construção, com vi!!!
copyright © Adriano Cruz 1999

Barra Horizontal Azul

  1. Introdução
  2. Operações com Ponteiros
    1. Declaração de Ponteiros
    2. Os Operadores de Ponteiros
    3. Aritmética de Ponteiros
  3. Ponteiros e Vetores
    1. Ponteiros e Strings
    2. Alocação Dinâmica de Memória
    3. Ponteiros e Matrizes
    4. Vetores de Ponteiros
    5. Ponteiros para Ponteiros
  4. Exercícios
Barra Horizontal Azul

Introdução

Ponteiros são usados em situações em que é necessário conhecer o endereço onde está armazenada a variável e não o seu conteúdo.

Um ponteiro é uma variável que contém um endereço de memória e não o conteúdo da posição.

 A memória de um computador pode ser vista como uma sequência de bytes cada um com seu próprio endereço. Não há dois bytes com o mesmo endereço. O primeiro endereço é sempre 0 e o último geralmente é uma potência de 2. Por exemplo um computador com memória igual a 16 Mbytes tem 16x1024x1024 bytes.

A figura abaixo mostra um mapa de um trecho de memória que contém duas variáveis (num, res) inteiras de tipo longo (4 bytes cada uma). Observar que os endereços estão pulando de quatro em quatro já que as variáveis são inteiras de tipo longo. Uma possível declaração destas variáveis dentro de um programa C poderia ser:

long int  num=10, res=120;
Endereços 
Conteúdo 
Variável 
996 
--- 
--- 
1000 
10 
num 
1004 
120 
res

Tabela 8.1 Mapa de Memória

Ponteiros são importantes por exemplo quando se deseja que uma função retorne mais de um valor.

Por exemplo, uma função pode receber não os valores dos parâmetros mas sim ponteiros que apontem para seus endereços. Assim esta função pode modificar diretamente os conteúdos destas variáveis.

 Uma outra aplicação importante de ponteiros é apontar para áreas de memória que são admnistradas durante a execução do programa. Com ponteiros é possível alocar as posições de memória necessárias para armazenamento de vetores somente quando o programa estiver rodando. O programador pode reservar o número exato de posições que o programa requer.

Barra Horizontal Azul

Operações com Ponteiros

Barra Horizontal Azul

Declaração de Ponteiros

Antes de serem usados os ponteiros, como as variáveis, precisam ser declarados. A forma geral da declaração de um ponteiro é a seguinte:
 
 
tipo *nome;
Onde tipo é qualquer tipo válido em C e nome é o nome da variável ponteiro. Por exemplo:
int *res;       /* ponteiro para uma variavel inteira */
float *div;     /* ponteiro para uma variavel de ponto flutuante */

Barra Horizontal Azul

Os Operadores de Ponteiros

Existem dois operadores especiais para ponteiros: * e &. Os dois operadores são unários, isto é requerem somente um operando.

 O operador & devolve o endereço de memória do seu operando. Por exemplo,

pint = &soma;   /* o endereco de soma e carregado em pint */
No exemplo seguinte considere a Tabela 8.1. Após a execução do trecho de programa abaixo a variável ponteiro p termina com o valor 1000.
p = #
O operador * é o complemento de &. O operador * devolve o valor da variável localizada no endereço que o segue. Por exemplo, o comando
num = *p;
significa que a variável num recebe o valor apontado por p. Estes operadores não devem ser confundidos com os já estudados em capítulos anteriores. O operador * para ponteiros não tem nada a ver com o operador multiplicação. O operador ponteiro * é unário e, como o operador &, tem precedência maior que do que todos os operadores aritméticos. Barra Horizontal Azul

Aritmética de Ponteiros


Atribuição de Ponteiros

 Do mesmo modo que uma variável comum o conteúdo de um ponteiro pode ser passado para outro ponteiro do mesmo tipo. As variáveis ponteiro devem sempre apontar para os tipos de dados corretos. Uma variável ponteiro declarada como apontador de dados inteiros deve sempre apontar para dados deste tipo.

Observar que em C é possível atribuir qualquer endereço a uma variável ponteiro. Deste modo é possível atribuir o endereço de uma variável do tipo float a um ponteiro inteiro. No entanto, o programa não irá funcionar da maneira correta.

 Por exemplo, no trecho de programa abaixo c8atribp.c o endereço do terceiro elemento do vetor v é carregado em p1 e o endereço da variável i é carregado em p2. Além disso no final o endereço apontado por p1 é carregado em p2. Os comandos printf imprimem os valores apontados pelos ponteiros respectivos.
 
 

void main(void)
{
    int vetor[] = { 10, 20, 30, 40, 50 };
    int *p1, *p2;
    int i = 100;

    p1 = &vetor[2];
    printf("%d\n", *p1);
    p2 = &i;
    printf("%d\n", *p2);
    p2 = p1;
    printf("%d\n", *p2);
}

Acessando os Endereços

 O trecho de programa abaixo faz com que o endereço da variável x seja carregado no ponteiro p. Em seguida o programa imprime o que está apontado por p.

void main(void)
{
   float x=3.14; float *p;

   p = &x;
    printf("*p = %f", *p);
}

Incrementando e Decrementando Ponteiros

 O exemplo (c8incrp.c) abaixo mostra que operações de incremento e decremento podem ser aplicadas em operandos. O primeiro printf imprime 30 o segundo 40 e o terceiro 50.

void main(void)
{
    int vetor[] = { 10, 20, 30, 40, 50 };
    int *p1;
    
    p1 = &vetor[2];
    printf("%d\n", *p1);
    p1++;
    printf("%d\n", *p1);
    p1 = p1 + 1;
    printf("%d\n", *p1);
}
Pode parecer estranho que um endereço que aponte para um número inteiro que é armazenado em dois bytes seja incrementado por um e passe para apontar para o próximo número inteiro. A resposta para isto é que sempre que um ponteiro é incrementado (decrementado) ele passa a apontar para a posição do elemento seguinte (anterior). Do mesmo modo somar três a um ponteiro faz com que ele passe apontar para o terceiro elemento após o atual. Portanto, um incremento em um ponteiro que aponta para um valor que é armazenado em n bytes faz que n seja somado ao endereço.

 É possível se usar o seguinte comando

*(p+1)=10;
Este comando armazena o valor 10 na posição seguinte àquela apontada por p. É possível somar-se e subtrair-se inteiros de ponteiros. A operação abaixo faz com que o ponteiro p passe a apontar para o terceiro elemento após o atual.
p = p + 3;
A diferença entre ponteiros fornece quantos elementos do tipo do ponteiro existem entre os dois ponteiros. No exemplo (c8difp.c) abaixo é impresso o valor 3.
void main(void)
{
        float vetor[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
        float *p1, *p2;
    
        p1 = &vetor[2];         /* endereco do terceiro elemento */
        p2 = &vetor;            /* endereco do primeiro elemento */
    printf("Diferenca entre ponteiros %d\n", p1-p2);
}
Não é possível multiplicar ou dividir ponteiros, e não se pode adicionar ou subtrair o tipo float ou o tipo double a ponteiros.


Comparação de Ponteiros

 É possível comparar ponteiros em uma expressão relacional. Só é possível comparar ponteiros de mesmo tipo. O trecho de programa abaixo ilustra um exemplo deste tipo de operações.

char *c, *v;

scanf("%c %c", c, v);
if (c == v) 
    printf("As variáveis estao na mesma posicao.\n");
else
    printf("As variaveis nao estao na mesma posicao.\n");

Barra Horizontal Azul

Ponteiros e Vetores

Ponteiros e Vetores estão fortemente relacionados na linguagem C. O nome de um vetor é um ponteiro que aponta para a primeira posição do vetor e todas as operações já mencionadas para ponteiros podem ser executadas com um nome de vetor. Por exemplo, a declaração

int v[100];


declara um vetor de inteiros de 100 posições e a partir dela temos que v é um ponteiro equivalente ao da declaração abaixo

int *v;

Por esta razão as seguintes declarações são idênticas e podem ser intercambiadas independemente do modo como v foi declarado:

v[i] == *(v+i)
&v[i] == v+i


O exemplo (c8vetpon.c) ilustrado abaixo mostra as duas notações sendo usadas para imprimir o mesmo vetor.

void main(void)
{
    float v[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
    int i;
    for (i=0; i<9; i++) printf("%.1f ", v[i]);
    printf("\n");
    for (i=0; i<9; i++) printf("%.1f ", *(v+i));
}

Existe uma diferença fundamental entre declarar um conjunto de dados como um vetor ou através de um ponteiro. Na declaração de vetor a compilador automaticamente reserva um bloco de memória para que o vetor seja armazenado. Quando apenas um ponteiro é declarado a única coisa que o compilador faz é alocar um ponteiro para apontar para a memória, sem que espaço seja reservado.

 O nome de um vetor é chamado de ponteiro constante e, portanto, não pode ter o seu valor alterado. Assim, os comandos abaixo não são válidos:

void main(){
    int list[5], i;

    /* O ponteiro list nao pode ser modificado recebendo o endereco de i */
    list = &i
    /* O ponteiro list nao pode ser incrementado */  
    list++; 
}

Para percorrer um vetor além da maneira mostrada no exemplo (c8vetpon.c) é possível usar um ponteiro variável como ilustrado no exemplo (c8povar.c) abaixo.

void main(void)
{
        
    float v[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
    int i;
    float *p;

    for (i=0; i<9; i++) printf("%.1f ", v[i]);
    printf("\n");
    for (i=0; i<9; i++) printf("%.1f ", *(v+i));
    printf("\n");
    for (i=0, p=v; i<9; i++, p++) printf("%.1f ", *p);
}

Observe como o ponteiro p recebe seu valor inicial e a maneira que ele é incrementado.

------------------------------------------------------------------------

Ponteiros e Strings

Um string constante é escrito como no exemplo:

 "Este e um string".

Até agora um dos usos mais comuns de strings constantes tem sido na função printf, como no exemplo abaixo

printf("Acabou o programa.\n");
Quando um string como este é enviado para a função o que é passado é o ponteiro para o string. É possível então carregar o endereço do string em um ponteiro do tipo char.
void main(void)
{
    char *lista;

    lista = "Ola como vai?";
    printf("%s", lista);
}
No exemplo c8postr.c aparece uma função que conta o número de caracteres de um string. Observe o ponteiro para o string constante e na função o ponteiro *(s+tam++) apontando caracter a caracter.
 
 
int strtam(char *s);

void main(void)
{
    char *lista="1234567890";

    printf("O tamanho do string \"%s\" e %d caracteres.\n", lista, strtam(lista));
    printf("Acabou.");
}

int strtam(char *s){
    int tam=0;

    while(*(s + tam++) != '\0');
    return tam-1;
}
Um outro exemplo (c8posta.c) ilustrado abaixo mostra uma função que copia um string para outro.
int strcop(char *d, char *o);

void main(void)
{
    char destino[20];
    char  *origem="string de origem";
    strcop(destino, origem);  /* copia o string origem para o destino */
    printf("%s\n", origem);
    printf("%s\n", destino);
    printf("Acabou.\n");
}

int strcop(char *d, char *o){
    while ((*d++ = *o++) != '\0');
    return 1;
}

------------------------------------------------------------------------

Alocação Dinâmica de Memória

As funções básicas de alocação de memória são malloc(), calloc() e free(). Estas funções são encontradas na biblioteca stdlib.h.

  O exemplo (c8call1.c) abaixo ilustra o uso das função calloc e free.

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

void main(void)
{
    float *v;
    int i, tam;

    printf("Qual o tamanho do vetor? ");
    scanf("%d", &tam);
    v = calloc(tam, sizeof(float));
    if (v){
        for (i=0; i<tam; i++){
            printf("Elemento %d ?", i);
            scanf("%f", v+i);
            printf("Li valor %f \n", *(v+i));
        }
        free(v);
    }
    else
        printf("Nao consegui alocar memoria.");
}

Um outro exemplo, agora empregando a função malloc() está mostrado no exemplo maior.c. Observe que neste exemplo também mostramos exemplos onde um endereço de variável foi passado para uma função de modo que a função main possa receber um valor (vezes).

void LeVetor (float *v, int tam);
float  ProcuraMaior (float *v, int tam, int *vezes);

int main(void)
{
    float *v, maior;
    int i, tam, vezes;

    printf("Qual o tamanho do vetor? ");
    scanf("%d", &tam);
    v = (float *) malloc(tam * sizeof(float));
    if (v){
        LeVetor(v, tam);
        maior = ProcuraMaior (v, tam, &vezes);
        printf("O maior elemento e %f e aparece %d vezes.\n.", maior, vezes);
        free(v);
    }
    else {
        printf("Nao consegui alocar memoria.");
        exit(1);
    }
    exit(0);
}

void LeVetor (float *v, int tam) {
   int i;

   for (i=0; i<tam; i++){
            printf("Elemento %d ?", i);
            scanf("%f", v+i);
            printf("Li valor %f \n", *(v+i));
        }
}

float ProcuraMaior (float *v, int tam, int *vezes) {
   int i;
   float maior;

   maior = v[0]; *vezes = 1;
   for (i=1; i<tam; i++) {
      if (v[i] > maior) {
         maior = v[i];
         *vezes = 1;
      }
      else if (maior == v[i]) *vezes=*vezes+1;;
   }
   return maior;
}

------------------------------------------------------------------------

Ponteiros e Matrizes

Um ponteiro aponta para uma área de memória que é endereçada de maneira linear. Deste modo, é necessário mapear o endereço de cada elemento na matriz, que é dado por linha coluna, em um endereço linear.

Considere uma matriz chamada matriz de tamanho LIN,COL que poderia ser declarada e ter um de seus elementos lidos da seguinte maneira:

#define LIN 3
#define COL 4
void main(){
    int matriz[LIN][COL];

   for(i=0; i<LIN; i++){
        for (j=0; j<COL; j++){
            printf("Elemento %d %d = ", i, j);
            scanf("%d", matriz[i][j]);
        }
    } 
}

Caso o programa utilizasse ponteiros ao invés de notação de matrizes o trecho de programa ficaria da seguinte maneira:

#define LIN 3
#define COL 4

void main(void)
{
    int *matriz;
    int i, j;
    
    matriz = malloc(LIN*COL*sizeof(int));
    if (!matriz){
        printf("Nao consegui alocar a memoria suficiente.\n");
        exit(1);
    }
    for(i=0; i<LIN; i++){
        for (j=0; j<COL; j++){
            printf("Elemento %d %d = ", i, j);
            scanf("%d", matriz+(i*COL+j));
        }
}

Observe que o endereço de cada elemento da matriz teve de ser calculado explicitamente. O programa completo que mostra como a matriz poderia ser impressa está indicada no exemplo c8pomat.c.

Uma outra possibilidade é utilizar vetores de ponteiros, onde cada linha corresponde a um vetor que é apontado por um ponteiro.
No item seguinte (Vetores de ponteiros) detalhamos este exemplo.

------------------------------------------------------------------------

Vetores de Ponteiros

Como ponteiros também são variáveis é possível então criar vetores de ponteiros e utilizá-los. O programa exemplo c8vepon.c mostra um programa onde é utilizado um vetor de ponteiros para linhas de caracteres.
 
#define LINHAS 10
#define COLUNAS 60

/* prototipos das funcoes */
void alocaespaco(char *linha[]);
void lelinhas (char *linha[]);
void imprimelinhas (char *linha[]);
void ordenalinhas (char *linha[]);

void main(void)
{
    char *linha[LINHAS];
    alocaespaco(linha);
    lelinhas(linha);
    imprimelinhas(linha);
    ordenalinhas(linha);
    imprimelinhas(linha);
}
/* Esta rotina aloca espaco para as linhas */
void alocaespaco(char *linha[]){
    int i;
   
    for (i=0; i<LINHAS; i++){
        if (!(linha[i] = malloc(COLUNAS*sizeof(int)))){
            printf("Nao consegui alocar o vetor %d.\n", i);
            exit(i);
        }
    }
}

/* Esta rotina le linhas */
void lelinhas (char *linha[]){
    int i;

    for (i=0; i<LINHAS; i++){
        printf("Entre com a linha %d.\n", i);
        gets(linha[i]);
    }
}

/* Esta rotina imprime as linhas */
void imprimelinhas (char *linha[]){
    int i;

    for (i=0; i<LINHAS; i++){
        printf("Linha %d %s.\n", i, linha[i]);
    }
}

void ordenalinhas( char *linha[]){
     char trocou;
     char *p;
     int i;

     do {
        trocou = 0;
        for (i=0; i<LINHAS-1; i++){
            if (strcmp(linha[i], linha[i+1]) >0){
               p = linha[i];
               linha[i] = linha[i+1];
               linha[i+1] = p;
               trocou = 1;
            }
        }
     } while (trocou);


}

Observe na rotina main a declaração

char *linha[LINHAS];

que define um vetor de tamanho LINHAS. Este vetor contem ponteiros e não valores. Até este momento temos apenas posições reservadas para armazenar ponteiros. A alocação de espaço e a inicialização dos ponteiros é feita na rotina alocaespaco.

Como cada elemento do vetor é um ponteiro o ponteiro retornado pela função malloc é armazenado em cada um dos elementos do vetor. Portanto linha[i]é um ponteiro é pode ser usado como parâmetro das funções gets e printf.

Um ponto importante da ordenação das linhas é que a troca de posição das linhas involve somente a troca dos ponteiros das linhas a serem trocadas e não o seu conteúdo, o que é muito mais rápido.

-------------------------

Ponteiros para Ponteiros

No exemplo anterior podemos observar que o número de linhas da matriz é fixa, e portanto, há uma mistura de notação de ponteiros com matrizes. Vamos considerar um exemplo onde tanto o número de linhas como o de colunas é desconhecido. Neste exemplo iremos criar um vetor de ponteiros que irá armazenar o endereço inicial de cada linha.  Portanto, para obter um elemento da matriz primeiro devemos descobrir onde está a linha no vetor que armazena os endereços das linhas, em seguida procuramos na linha o elemento. A figura 8.1 ilustra como será feito o armazenamento desta matriz.

Matriz armazenada com vetor de ponteiros

O programa exemplo (c8pp.c), listado a seguir, irá pedir ao usuário que digite o número de linhas e colunas da matriz. Em seguida lerá todos os elementos da matriz e por último irá trocar duas linhas da matriz de posição. Observe que agora foi criado um ponteiro para ponteiro chamado de **matriz. O programa primeiro pergunta o número de linhas da matriz para poder alocar espaço para armazenar os ponteiros para cada uma das linhas. Em seguida é alocado espaço para armazenar cada uma das linhas. Notar que a troca de linhas da matriz involve simplesmente a troca de dois ponteiros e não a troca de todos os elementos das linhas. Esta solução é muito mais rápida do que a anterior, especialmente para matrizes grandes.

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

void main () {

     int **matriz;   /* ponteiro para os ponteiros de cada uma das linhas */
     int lin, col;   /* número de linhas e colunas */
     int i, j;
     int linha1, linha2; /* linhas da matriz que serao trocadas */
     char linha[80]; /* linha de caracteres com os dados */
     int *temp;

     do {
        puts("Qual o numero de linhas?");
        gets(linha);
        lin = atoi(linha);
     } while (lin<=0);
     printf("Numero de linhas = %d\n", lin);
     printf("Alocando espaço para armazenar os ponteiros para as linhas.\n");
     matriz = (int **) malloc (lin * sizeof(int *));
     if (!matriz) {
        puts("Nao há espaço para alocar memória");
        exit(1);
     }

     do {
        puts("Qual o numero de colunas?");
        gets(linha);
        col = atoi(linha);
     } while (col<=0);
     printf("Numero de colunas = %d\n", lin);
     printf("Alocando espaço para armazenar os vetores de linhas.\n");
     for (i=0; i<lin; i++)
     {
        *(matriz +i) = (int *) malloc(col * sizeof (int));
        if (! *(matriz+i) ){
           printf("Não há espaço para alocar a linha %d", i);
           exit(1);
        }
     }
     puts("Entre com os dados");
     for (i=0; i<lin; i++)
     {
        printf("Entre com a linha %d\n", i);
        for (j=0; j<col; j++)
        {
            printf("Elemento %d %d\n", i, j);
            scanf("%d", *(matriz +i) +j);
        }
     }
     puts("Dados lidos");
     for (i=0; i<lin; i++)
     {
        for (j=0; j<col; j++)
        {
            printf("%7d ", *(*(matriz +i) +j));
        }
        printf("\n");
     }
     getchar();

     do {
        puts("Qual a primeira linha a ser trocada?");
        gets(linha);
        linha1=atoi(linha);
     } while (linha1 >=lin);

     do {
        puts("Qual a segunda linha a ser trocada?");
        gets(linha);
        linha2=atoi(linha);
     } while (linha2 >=lin);
 
     temp = *(matriz + linha1);
     *(matriz + linha1) = *(matriz + linha2);
     *(matriz + linha2) = temp;
 
     puts("Dados trocados.");
     for (i=0; i<lin; i++)
     {
        for (j=0; j<col; j++)
        {
            printf("%7d ", *(*(matriz +i) +j));
        }
        printf("\n");
     }

}
 

A seguir mostramos (c8ppf.c) o exemplo anterior modificado para utilizar funções. O propósito é mostrar como ficam as chamadas e as definições das funções que utilizam ponteiros para ponteiros.

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

int **aloca_linhas(int );
void aloca_colunas (int **, int, int);
void le_dados(int **, int, int );
void imprime_matriz(int **, int, int );
void troca_linhas (int **, int, int);

void main () {
     int **matriz;   /* ponteiro para os ponteiros de cada uma das linhas */
     int lin, col;   /* número de linhas e colunas */
     int linha1, linha2; /* linhas da matriz que serao trocadas */
     char linha[80]; /* linha de caracteres com os dados */

     do {
        puts("Qual o numero de linhas?");
        gets(linha);
        lin = atoi(linha);
     } while (lin<=0);
     printf("Numero de linhas = %d\n", lin);

     printf("Alocando espaço para armazenar os ponteiros para as linhas.\n");
     matriz = aloca_linhas(lin);

     do {
        puts("Qual o numero de colunas?");
        gets(linha);
        col = atoi(linha);
     } while (col<=0);
     printf("Numero de colunas = %d\n", lin);
 
     printf("Alocando espaço para armazenar os vetores de linhas.\n");
     aloca_colunas(matriz, lin, col);

     le_dados(matriz, lin, col);

     puts("Imprimindo dados lidos");
     imprime_matriz(matriz, lin, col);

     getchar();

     do {
        puts("Qual a primeira linha a ser trocada?");
        gets(linha);
        linha1=atoi(linha);
     } while (linha1 >=lin);

     do {
        puts("Qual a segunda linha a ser trocada?");
        gets(linha);
        linha2=atoi(linha);
     } while (linha2 >=lin);

     troca_linhas(matriz, linha1, linha2);

     puts("Imprimindo dados trocados.");
     imprime_matriz(matriz, lin, col);

}

int **aloca_linhas(int lin) {

  int **m;
     m = (int **) malloc (lin * sizeof(int *));
     if (!m) {
        puts("Nao há espaço para alocar memória");
        exit(1);
     }
     return m;
}

void aloca_colunas(int **matriz, int lin, int col)
{
  int i;
     for (i=0; i<lin; i++)
     {
        *(matriz +i) = (int *) malloc(col * sizeof (int));
        if (! *(matriz+i) ){
           printf("Não há espaço para alocar a linha %d", i);
           exit(1);
        }
     }
}

void le_dados (int **matriz, int lin, int col)
{
  int i, j;
     puts("Entre com os dados");
     for (i=0; i<lin; i++)
     {
        printf("Entre com a linha %d\n", i);
        for (j=0; j<col; j++)
        {
            printf("Elemento %d %d\n", i, j);
            scanf("%d", *(matriz +i) +j);
        }
     }
}

void imprime_matriz (int **matriz, int lin, int col)
{
     int i, j;

     for (i=0; i<lin; i++)
     {
        for (j=0; j<col; j++)
        {
            printf("%7d ", *(*(matriz +i) +j));
        }
        printf("\n");
     }
}

void troca_linhas ( int **matriz, int linha1, int linha2)
{

  int *temp;

  temp = *(matriz + linha1);
  *(matriz + linha1) = *(matriz + linha2);
  *(matriz + linha2) = temp;
}
 
 

------------------------------------------------------------------------

Exercícios

  1. O que será impresso pelo progama nome.c assumindoque a entrada fornecida é o seu nome completo. Assuma que não há nenhum espaço em branco antes do início do nome.


  2. Escreva um programa que gere um vetor de três dimensões (X, Y e Z) em que cada posição guarda a soma de suas coordenadas. As dimensões da matriz deverão ser determinadas em tempo de execução e o programa deverá informar os valores gerados.
    Solução: vetor.c

  3. Escreva um programa que leia uma frase de até 80 caracteres do teclado e imprima a frequência com que aparece cada uma das letras do alfabeto na frase.
    Solução: c8contac.c

  4. Escreva um programa que leia uma frase de até 80 caracteres e a imprima em ordem reversa convertendo todos os caracteres minúsculos para maiúsculos.
    Solução: reverso.c

  5. Escreva um programa que leia uma matriz e a imprima. O programa deve ler o numero de colunas e linhas do teclado. O programa deve ainda trocar duas linhas da matriz de posição. Os números das linhas a serem trocadas devem ser lidos do teclado.
    Solução: c8trolin.c

  6. Escreva um programa que simule uma pilha usando vetores. O programa deve implementar as seguintes operações na pilha:
    1. Inserir.
    2. Remover
    3. Listar
    Solução: c8pilha.c

  7. Escreva uma função que receba um ponteiro para uma string e troque todo o caracter após um branco pelo seu equivalente maiúsculo.
    Solução: c8maiu.c

  8. Escreva um programa que leia seu nome completo e pergunte quantas letras tem o seu primeiro nome. Assuma que a letra 'a' tem índice 0, a letra 'b' índice 1 e assim por diante. O programa deve imprimir quantas letras iguais a letra cujo índice é o número de letras do seu primeiro nome existem no seu nome completo.
    Solução: diga.c

  9. Faça uma função que verifique se a expressão apontada por substr está presente na cadeia apontada por str. A função possui o protótipo abaixo:
    int posicao(char *substr, char *str);
    e retorna a posição em que a sub-cadeia aparece em cadeia.
    Solução: procura.c

  10. Escreva um programa que procure em uma matriz elementos que sejam ao mesmo tempo o maior da linha e o menor coluna. As dimensões da matriz devem ser pedidas ao usuário.
    Solução: sela.c

  11. Escreva um programa que leia duas cadeias de caracteres e concatene a segunda cadeia ao final da primeira.
    Solução: concatena.c

------------------------------------------------------------------------

Índice