Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas


Computação - Linguagem C, Notas de estudo de Engenharia Elétrica

Apostila de computação com os seguintes conteúdos: 1 - Funções em C ; 2 - Ponteiros ; 3 - Estruturas ; 4 - Arquivos

Tipologia: Notas de estudo

2013

Compartilhado em 19/06/2013

gabriel-silva-21
gabriel-silva-21 🇧🇷

2 documentos

1 / 29

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
COMPUTAÇÃO II
COMPUTAÇÃO II COMPUTAÇÃO II
COMPUTAÇÃO II
(PARTE
(PARTE (PARTE
(PARTE 1
11
1)
))
)
Prof..
Prof.. Prof..
Prof.. Dr
DrDr
Dr. Ionildo José Sanches
. Ionildo José Sanches. Ionildo José Sanches
. Ionildo José Sanches
CURITIBA
2011
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d

Pré-visualização parcial do texto

Baixe Computação - Linguagem C e outras Notas de estudo em PDF para Engenharia Elétrica, somente na Docsity!

COMPUTAÇÃO IICOMPUTAÇÃO IICOMPUTAÇÃO IICOMPUTAÇÃO II

(PARTE(PARTE(PARTE(PARTE 1111 ))))

Prof..Prof.. Dr Prof..Prof..DrDrDr. Ionildo José Sanches. Ionildo José Sanches. Ionildo José Sanches. Ionildo José Sanches

CURITIBA

ii

    1. FUNÇÕES EM C SUMÁRIO
    • 1.1 SUBPROGRAMAS
    • 1.2 FUNÇÕES EM C.................................................................................................................................................................
      • 1.2.1 Escopo de Variáveis...............................................................................................................................................
      • 1.2.2 Passagem de Parâmetros.......................................................................................................................................
    • 1.3 ESPECIFICAÇÃO DE CLASSES DE ARMAZENAMENTO
    1. PONTEIROS
    • 2.1 OPERAÇÕES COM PONTEIROS
    • 2.2 PASSANDO ENDEREÇOS PARA FUNÇÕES.........................................................................................................................
    • 2.3 INICIALIZAÇÃO DE PONTEIROS
    • 2.4 ALOCAÇÃO DINÂMICA DE MEMÓRIA
    • 2.5 ARGUMENTOS DA LINHA DE COMANDO
    1. ESTRUTURAS..................................................................................................................................................................
    • 3.1 EXEMPLO DE UMA ESTRUTURA
    1. ARQUIVOS
    • 4.1 DECLARAÇÃO DE ARQUIVOS EM C/C++
    • 4.2 COMANDOS DE ARQUIVOS EM C/C++
      • 4.2.1 Função fopen ()....................................................................................................................................................
      • 4.2.2 Função fclose()
      • 4.2.3 Função ferror()
      • 4.2.4 Função fputc()......................................................................................................................................................
      • 4.2.5 Função fgetc()......................................................................................................................................................
      • 4.2.6 Função fputs()......................................................................................................................................................
      • 4.2.7 Função fgets()
      • 4.2.8 Função fwrite()
      • 4.2.9 Função fread()
      • 4.2.10 Função fseek()......................................................................................................................................................
      • 4.2.11 Função feof()........................................................................................................................................................
      • 4.2.12 Função rewind()
      • 4.2.13 Função remove()..................................................................................................................................................
      • 4.2.14 Função fflush().....................................................................................................................................................
      • 4.2.15 Função ftell()
      • 4.2.16 Função fprintf()....................................................................................................................................................
      • 4.2.17 Função fscanf()
  • BIBLIOGRAFIA
  • APÊNDICE A -

if (a > b) { Aux = a; a = b; b = Aux; } printf(“%d %d”, a, b); }

Aux = a; a = b; b = Aux; } } int main() { scanf(“%d %d”, &a, &b); Ordena(); printf(“%d %d\n”, a, b); }

Quando o programa “Ordena2” é executado, e encontra o identificador “Ordena” (chamada de
função), ocorre um desvio para a função que é executada. Ao término da função, o controle é devolvido
ao comando seguinte ao da sua ativação (comando printf).
A chamada de uma função funciona como um Comando Simples, bastando o nome da função
seguida pelos parênteses para ativá-la. Perceba que a função main de “Ordena2” executa exatamente o
que o problema define: ler, ordenar e escrever.
Exemplo: Programa para calcular o fatorial de um número:

#include <stdio.h> #include <conio.h>

long fat(int N) { int i; long Fat; Fat = 1; for (i=2; i<=N; i++) Fat = Fat * i; return Fat; }

int main() /* programa principal */ { int N; char ch; do { printf("\n\nEntre com um numero: "); scanf("%d", &N); if (N > 0) printf("Fatorial de %d = %ld\n", N, fat(N)); else printf("Numero Invalido!\n"); printf("\nDeseja Continuar ou ? "); ch=getch(); } while (ch=='s' || ch=='S'); return 0; }

1.2.1 Escopo de Variáveis
A linguagem C permite definir o escopo das variáveis de um programa, isto é, em que pontos do
programa estas variáveis são visíveis (podem ser referenciadas).
Esta visibilidade é definida pelo local onde a variável está declarada no programa, ou seja, a qual
Bloco de Declarações pertence. Isto porque um programa pode ser formado por um conjunto de funções,
onde cada uma possui seu próprio Bloco de declarações.
No programa “Ordena2”, visto anteriormente, a variável Aux está declarada no início do programa
(fora das funções) e só é utilizada pelo procedimento “Ordena”. Neste caso, tanto a função Ordena como
a função main podem usar esta variável. Dizemos que Aux é uma variável global ao programa.

/* Programa Ordena3 */ #include <stdio.h> int a, b; / variáveis globais /

void Ordena(void) { int Aux; / variável local / if (a > b) { Aux = a; a = b; b = Aux; } }

int main() { scanf(“%d %d”, &a, &b); Ordena(); printf(“%d %d\n”, a, b); return 0; }

Agora Aux é uma variável local a “Ordena()”, pois está declarada no seu bloco de declarações,
impedindo o seu acesso pela função main. Na verdade, a variável Aux só é criada quando a função é
ativada e ao seu término a variável Aux é liberada, tornando-se inacessível e seu conteúdo é perdido.
As variáveis a e b, como estão declaradas fora das funções, podem ser acessadas tanto pelo
programa principal quanto pela função “Ordena()”. São variáveis globais à função.
Na realidade, todas as variáveis declaradas fora das funções são visíveis (globais) a todos os seus
subprogramas, com exceção do caso a seguir:

/* Programa Escopo */ #include <stdio.h> int x; / x global /

void Troca(void) { int x; / x local / x = 1; }

int main() { x = 0; printf(“x antes = %d\n”, x); Troca(); printf(“x depois = %d\n”, x); return 0; }

Saída: x antes = 0
x depois = 0
O programa “Escopo” possui declaradas duas variáveis x. Uma global (definida no inicio do
programa) e outra local (definida na função “Troca()”). Quando duas variáveis são declaradas com um
mesmo nome, o mecanismo de visibilidade deve definir qual das variáveis está sendo realmente acessada.
Ponteiros são passados para as funções como qualquer outra variável. Obviamente, é necessário
declarar os parâmetros como do tipo ponteiro. Por exemplo, a função Ordena(), que troca os valores dos
seus dois argumentos inteiros.

/* Programa Ordena3 */ #include <stdio.h>

**void Ordena(int *a, int b) { int Aux; if (a > *b) { Aux = *a; *a = b; b = Aux; } }

int main() { int a, b; scanf(“%d %d”, &a, &b); Ordena(&a, &b); printf(“%d %d\n”, a, b); return 0; }

#include <stdio.h>

void Troca(int *y) { *y = 1; }

int main() { int x = 0; printf(“x antes = %d\n”, x); Troca(&x); printf(“x depois = %d\n”, x); return 0; }

Saída: x antes = 0

x depois = 1

Exemplo: Calcular o produto de dois números:

#include <stdio.h>

void Mult (float x, float y) { printf(“%f\n”, x * y); }

int main() { Mult(2, 3); Return 0; }

O programa anterior consiste de uma função que imprime o valor do produto de dois números
recebidos pela passagem de parâmetros e função main que manda executar a função Mult() enviando os
valores numéricos 2 e 3 como argumentos.
Observe que:
  • Não utilizou nenhuma variável global.
  • As variáveis x e y do procedimento não precisam ser declaradas, pois são variáveis de
passagem e foram declaradas no início da função.
  • A função main não utiliza nenhuma variável.
  • Os parâmetros recebem os valores na mesma ordem em que são declarados como
parâmetros. Isto quer dizer que para efeito de cálculo dentro da função Mult(), o x assume
valor 2 e y o 3.
Exemplo: Calcular x dx^2

a

b

∫ usando Soma do Retângulos.

/* Programa Integral */ #include <stdio.h>

float f(float x) { float fx; fx = x * x; /* funcao utilizada */ return fx; }

int main() { float a, b, h, Soma; int i, n; printf(“Entre com um numero inteiro de divisoes: “); scanf(“%d”, &n); printf(“Entre com o intervalo inicial: “); scanf(“%f”, &a); printf(“Entre com o intervalo final: “); scanf(“%f”, &b); h = (b - a) / n; Soma = 0; for(i=0; i<n; i++) Soma = Soma + f(a + i * h); Soma = Soma * h; printf(“O Valor Aprox. da Integral = %.10f\n”, Soma); return 0; }

Em C é permitido que funções ativem a elas mesmas. Esta forma de ativação é conhecida como
Recursividade.

1.3 Especificação de Classes de Armazenamento

Declarações fora de uma função implicam armazenamento default static. Uma variável static tem
alocação de memória permanente inalterado, exceto se modificado por uma função: seu escopo é dito ser
o programa.
A palavra chave auto é redundante, uma vez que não se pode declarar uma variável como auto
fora de uma função, e declarações dentro do corpo de uma função são assumidas como auto. A memória
é alocada (na pilha) até que a função retorne; o escopo de uma variável auto é dito ser a função.
A palavra chave register também cria objetos auto, mas orienta o compilador a armazenar o
objeto em um registrador rápido; sugere ao compilador que uma variável é usada fortemente. Não é
permitido ter acesso ao endereço de uma variável register.

2. Ponteiros

Um ponteiro proporciona um modo de acesso a variáveis sem referenciá-las diretamente.
Basicamente, um ponteiro é uma representação simbólica de um endereço.
Ponteiros são usados em situações em que a passagem de valores é difícil ou indesejável. Algumas
razões para o uso de ponteiros são (MIZRAHI, 1990):
1. Fornecem maneiras com as quais as funções podem realmente modificar os argumentos que
recebem;
2. Para passar vetores e strings mais convenientemente de uma função para outra, isto é, usá-los
ao invés de vetores;
3. Para manipular vetores mais facilmente através de movimentação de ponteiros para elas (ou
parte delas), em vez de o próprio vetor.
4. Para criar estruturas de dados complexas, como listas encadeadas e árvores binárias, onde uma
estrutura de dados deve conter referências sobre outra;
5. Para comunicar informações sobre memória, como na função malloc() que retorna a
localização de memória livre através do uso de ponteiro;
6. Uma outra razão importante para o uso de ponteiros é que notações e ponteiros compilam mais
rapidamente tornando o código mais eficiente.
Um ponteiro é uma variável que contém um endereço de memória. Esse endereço é normalmente
a posição de uma outra variável na memória. Se uma variável contém o endereço de uma outra, então a
primeira variável é dita para apontar para a segunda.
A figura abaixo ilustra esta situação, onde uma variável aponta para outra.

Endereço na Memória

Variável na Memória

Se uma variável irá conter um ponteiro, ela deve ser declarada como tal. Uma declaração de
ponteiro consiste do tipo de base, um "*" (asterisco) e o nome da variável. A forma geral para se declarar
uma variável ponteiro é:

*

onde é qualquer tipo válido em C e é o nome da variável ponteiro.
O tipo base do ponteiro define que tipo de variáveis o ponteiro pode apontar. Tecnicamente,
qualquer tipo de ponteiro pode apontar para qualquer lugar na memória. No entanto, toda a aritmética de
ponteiros é feita por meio do tipo base, assim, é importante declarar o ponteiro corretamente. Por
exemplo,

char *ptr;

Existem dois operadores especiais para ponteiros: * e &. O operador de endereço (&) é um
operador unário que devolve o endereço na memória do seu operando. Um operador unário requer apenas
um operando. Por exemplo,

ptr = &soma;

coloca em ptr o endereço da memória que contém a variável soma. Esse endereço é a posição interna ao
da variável no computador. O endereço não tem relação alguma com o valor de soma. O operador & pode
ser imaginado como retornando "o endereço de". Assim, o comando de atribuição anterior significa "ptr
recebe o endereço de soma".
Para entender melhor a atribuição anterior, assuma que a variável soma usa a posição de memória
1005 para armazenar seu valor. Assuma também que soma tem o valor 10. Então, após a atribuição
anterior, ptr terá o valor 1005.
O segundo operador de ponteiro é o operador indireto (*) que é o complemento de (&). É um
operador unário que devolve o valor da variável localizada no endereço (ponteiro) operando, isto é,
devolve o conteúdo da variável apontada pelo operando. Por exemplo, se ptr contém o endereço da
variável soma,

aux = *ptr;

coloca o valor de soma em aux. Portanto, aux terá o valor 10 porque 10 estava armazenado na posição
1005, que é o endereço que estava armazenado em ptr. O operador * pode ser imaginado como "no
endereço". Nesse caso, o comando anterior significa "aux recebe o valor que está no endereço ptr".

#include <stdio.h> int main() { int y, x=1; int p; p=&x; / faz com que p aponte para o endereço de x / y=p; /* atribui o valor de x para y */ printf("Endereco de p = %u\n", &p); printf("Endereco de x = %u\n", &x); printf("Endereco de y = %u\n", &y); printf("Valor de p = %u\n", p); printf("Valor de *p = %d\n", *p); printf("Valor de x = %d\n", x); printf("Valor de y = %d\n", y); return 0; }

2.1 Operações com Ponteiros

Em geral, expressões envolvendo ponteiros concordam com as mesmas regras de qualquer outra
expressão em C.
Como é o caso com qualquer variável, um ponteiro pode ser usado no lado direito de um comando
de atribuição para passar seu valor para um outro ponteiro. Por exemplo,

#include <stdio.h> int main() { int x=100; int *p1, p2; p1=&x; p2=p1; printf("%p\n", p2); / imprime o endereço de x, não seu valor */

}

int main() { int x=1, y=2; soma(&x, &y); printf("X = %d e Y = %d\n", x, y); return 0; }

A saída do programa será:

X = 11 e Y = 4

O símbolo *px indica o conteúdo do endereço px. Em outras palavras, pode usar *px onde usaria
x. A primeira instrução toma o conteúdo do endereço px (isto é, 1) e soma 10 a ele, armazenando o total
no endereço px. O mesmo vale para a segunda instrução.
O programa abaixo mostra o uso de ponteiros dentro do próprio programa.

#include <stdio.h> int main() { int x=1, y=2; *int px, py; printf("X = %d e Y = %d\n", x, y); px = &x; / inicializa ponteiro atribuindo endereços */ **py = &y; *px = *px + 10; py = py * 2; printf("X = %d e Y = %d\n", x, y); return 0; }

A instrução:

int *px, *py;

declara px e py do tipo "ponteiros para inteiros". Ponteiros são sempre inicializados com o valor 0 ou
NULL (nulo) e C garante que NULL não é um endereço válido, então antes de usá-los devemos atribuir
algum endereço válido a eles, o que é feito pelas instruções:

px = &x; py = &y;

As instruções

*px = *px + 10; *py = *py * 2;

são equivalentes a:

x = x + 10; y = y * 2;

É possível comparar dois ponteiros em uma expressão relacional. Por exemplo, dados dois
ponteiros p e q, o fragmento de código seguinte é perfeitamente válido.

if (p < q) printf("p aponta para um endereco anterior a q");

2.2 Passando Endereços para Funções

Funções podem alterar argumentos que recebem da função que a chamou. A forma de passar
vários valores para uma função e retornar um único já foi vista. Mas, como fazer para que uma função
altere mais de um valor para a função chamadora? Visto que não há mecanismos próprios de funções para
isto, nós devemos contar com o uso de ponteiros.
Vamos analisar a seguinte situação: como uma função pode alterar duas variáveis da função
chamadora. Dois procedimentos são necessários:
1. O programa chamador, em vez de passar valores para a função, passa seus endereços. estes
endereços são onde o programa chamador quer que a função coloque os dados gerados; em
outras palavras, são endereços de variáveis do programa chamador onde nós queremos
armazenar os novos valores.
2. A função chamada deve declarar os endereços recebidos como ponteiros.
Exemplo: Programa que passa o endereço de duas variáveis como argumentos para uma função onde os
seus valores são alterados.

#include <stdio.h> void altera1(int px, int py) { px=1; py=2; }

**void altera2(int px, int py) { **px=1; py=2; }

int main() { int x=0, y=0; altera1(x, y); printf("X = %d e Y = %d\n", x, y); altera2(&x, &y); printf("X = %d e Y = %d\n", x, y); return 0; }

Ao executar este programa, a saída será:

X = 0 e Y = 0 X = 1 e Y = 2

A função main() indica para a função altera2() onde colocar os valores através da passagem de
seus endereços usando o operador de endereços (&). A expressão

altera2(&x, &y);

causa a passagem dos endereços de x e y para a função, que os armazena em localizações privadas de
memória somente conhecidas por ela.
Alocação dinâmica: alocação de memória para o componente quando ele começa a existir
durante a execução do programa.
Exemplo de alocação dinâmica de memória para uma variável do tipo int.

#include <stdio.h> #include <stdlib.h> int main(){ int *iptr; iptr = malloc(sizeof(int)); *iptr = 10; printf(“O Valor é %d”, *iptr); free(iptr); return 0; }

2.5 Argumentos da Linha de Comando

Você já deve ter usado algum programa em que, quando você o chama pelo sistema operacional,
você pode não só digitar o seu nome, como também vários outros itens, como o nome do arquivo a ser
utilizado. Um exemplo típico é:

$ gcc -o programa programa.c

Aqui o argumento "-o" indica que o próximo argumento será o nome do arquivo executável, neste
caso, será programa (se for omitido o arquivo de saída se chamará "a.out") e o último argumento indica
o nome do arquivo fonte.
O C, automaticamente, fornece a capacidade de ler este tipo de argumentos a todos os programas
C.
O programa seguinte mostra isso:

#include <stdio.h>

int main(int argc, char *argv[])

{

int i; printf("Numero de argumentos: %d\n", argc); for (i=0; i<argc; i++) printf("Argumento[%d]: %s\n", i, *(argv+i)); return 0;

}

Os dois argumentos nos parênteses de main() são argc e argv. A variável argc corresponde ao
número de argumentos da linha de comando, incluindo o nome do programa. A variável *argv[]
representa uma matriz de ponteiros para string, onde cada string representa um argumento da linha de
comandos. As strings podem ser acessadas através de *(argv + i) ou argv[i], para i variando de 0 até
argc – 1.
A primeira string, *(argv + 0), representa o nome do programa e o caminho de localização dele
no disco.
Os nomes argc ( ARGument Count ) e argv ( ARGument Values ) são tradicionalmente usados para
este fim, mas qualquer outro pode ser usado.

3. Estruturas

No caso de vetores, foi visto que todos os componentes pertenciam a um mesmo grupo (tipo-
base). O problema de agrupar dados desiguais em C é resolvido pelo uso de Estruturas. Estruturas
permitem agrupar um conjunto de tipos de dados não similares sob um único nome.
Uma estrutura é uma coleção de uma ou mais variáveis, possivelmente de tipos diferentes,
colocadas juntas sob um único nome. Estruturas são chamadas de “registros” em algumas linguagens. Um
Registro é uma estrutura que envolve elementos de natureza distinta. No registro cada elemento pode ser
de um tipo diferente.
Cada Estrutura tem um certo número de componentes denominados campos ( fields) e definidos
através de identificadores.

struct {

; ;

M ;

};

Variáveis do Tipo Estrutura são utilizadas quando uma coleção de dados tem alguma afinidade
entre si.

3.1 Exemplo de uma Estrutura

O programa a seguir usa uma estrutura simples contendo dois itens de dados: uma variável inteira
(código) e uma variável float (salário).

#include <stdio.h>

int main()

{

struct exemplo { /* define o tipo de dado / int codigo; / atributo inteiro / float salario; / atributo float */ }; struct exemplo x; x.codigo=2410; x.salario=545.00; printf(“Código = %d\nSalario=%f\n”, x.codigo, x.salario); return 0;

}

O exemplo tradicional de uma estrutura é o cadastro de funcionários de uma empresa que agrega
as características deste funcionário: um funcionário é descrito por um conjunto de atributos como nome
(uma strting), cargo (string), salário (float), data de admissão (inteiros). Provavelmente, haverá outros
funcionários, então deverá ser definido um vetor de estruturas.
Primeiramente, deve ser definido o tipo da estrutura que deseja criar.

#include <stdio.h>

#include <conio.h>

#define NumFunc 10

typedef struct {

int Dia, Mes, Ano;

} TpData;

typedef struct {

char Nome[30]; char Cargo[20]; float Salario; TpData DataAdm;

} TpRegFunc;

TpRegFunc CadFunc[NumFunc];

float Media;

void LeFuncionarios()

{

int i; for (i=0; i<NumFunc; i++) { printf("Entre com o Nome : "); scanf("%[^\n]", CadFunc[i].Nome); fflush(stdin); printf("Entre com o Cargo : "); scanf("%[^\n]", CadFunc[i].Cargo); fflush(stdin); printf("Entre com o Salario : "); scanf("%f", &CadFunc[i].Salario); fflush(stdin); printf("Entre com a Data de Admissao : "); scanf("%d/%d/%d",&CadFunc[i].DataAdm.Dia,&CadFunc[i].DataAdm.Mes,&CadFunc[i].DataAdm.Ano); fflush(stdin); printf("\n"); }

}

void CalcMedia()

{

int i; Media = 0; for (i=0; i<NumFunc; i++) Media = Media + CadFunc[i].Salario; Media = Media / NumFunc;

}

void ExibeSalarios()

{

int i; for (i=0; i<NumFunc; i++) { if (CadFunc[i].Salario > Media) { printf("%s\n", CadFunc[i].Nome); printf("%s\n", CadFunc[i].Cargo); printf("%.2f\n", CadFunc[i].Salario); printf("%02d/%02d/%02d\n\n", CadFunc[i].DataAdm.Dia, CadFunc[i].DataAdm.Mes, CadFunc[i].DataAdm.Ano);

} }

}

int main()

{

LeFuncionarios(); CalcMedia(); ExibeSalarios(); getch(); return 0;

}