Introdução a
LINGUAGEM DE
PROGRAMAÇÃO C
HISTÓRICO 5
CARACTERÍSTICAS 6
CRÍTICAS 7
PROGRAMA EM C 8
TIPOS DE ARQUIVOS FONTES EM C 8
BIBLIOTECAS EM C 8
PALAVRAS CHAVES 9
VARIÁVEIS E CONSTANTES - TIPOS E DECLARAÇÕES 9
TIPOS DE DADOS 11
A NORMA ANSI C 11
IDENTIFICADORES 12
VARIÁVEIS 13
Onde declarar variáveis 13
PARÂMETROS FORMAIS 14
VARIÁVEIS GLOBAIS 15
ESPECIFICADORES DE TIPOS DE ARMAZENAMENTO DEVARIÁVEIS 16
COMANDO DE ITERAÇÃO 29 COMANDO DE DESVIO 30 ARRANJOS 34 ESTRUTURAS 40 UNIÕES 41 EXEMPLOS: 41 F U N Ç Õ E S 46 USO DE FUNÇÕES 47 FUNÇÕES EM C 47
PASSAGEM DE ESTRUTURAS PARA FUNÇÕES 47
EXEMPLOS DO USO DE FUNÇÕES 49 UTILIZAÇÃO DE PARÂMETROS 50 FUNÇÕES DE ENTRADA E SAÍDA 51 A P O N T A D O R E S ( P O I N T E R S ) 56
APONTADORES 57
APONTADORES E ARGUMENTOS DE FUNÇÕES 58
APONTADORES E ARRANJOS 59 ARITMÉTICA COM ENDEREÇOS 59
APONTADORES PARA FUNÇÕES 61 APONTADORES PARA ESTRUTURAS 62 FUNÇÃO PARA ABRIR E FECHAR ARQUIVOS 63
LEITURA E GRAVAÇÃO EM ARQUIVOS 63
EXEMPLOS 64
Histórico
• BCPL → B → C
• Projetada por Dennis Ritchie para ser implementada no sistema operacional
Unix
• Evolução: O Unix e os programas de aplicação implementados em C • Linguagem de Implementação de vários sistemas operacionais,
Características
• Linguagem de programação de finalidade geral
• É uma linguagem que combina o “alto nível” com o “baixo nível”
permite a manipulação direta de bits, bytes, palavras e apontadores
• Possui modernos fluxos de controle e estruturas de dados e, ainda, um rico
conjunto de operadores
• Possui apenas 28 palavras-chaves (reservadas)
• Permite economia de expressão e gera códigos reduzidos
• Permite estruturar o software em módulos, arquivos fontes, bibliotecas • É facilmente transportável (ANSI C)
• Alocação dinâmica de memória • C permite recursividade
• O uso da recursividade torna-se inviável quando o tempo ou o espaço da
Críticas
• Dá-se muita liberdade ao programador
Programas ininteligíveis, acesso direto a memória
• Não permite o aninhamento de funções
• Não há verificação de tipos e nem de limites de arranjos
Simplifica o “design” do compilador C
• O uso de apontadores pode se tornar muito confuso
• Mensagens de erro muito vagas ( limitação do compilador )
• Alguns comandos não podem ser definidos semanticamente
Programa em C
• Consiste de uma (main) ou mais funções
• Um programa começa a ser executado no início da função main ( ), que
invocará as demais funções
• A comunicação entre as funções é feita através da passagem de argumentos
e/ou variáveis globais
Tipos de Arquivos Fontes em C
• Arquivos fonte *.c
• Arquivos fonte *.h (stdio.h, math.h)
Bibliotecas em C
• São utilizadas para facilitar o desenvolvimento de software
• Por exemplo, “stdlib.a” é sempre incluída em todos os programas C por
Palavras Chaves
• São sempre escritas com letras minúsculas
auto break case char continue default do double else entry extern float for goto if int long register return short szeof satic struct switch typedef union unsigned while
Variáveis e Constantes - Tipos e Declarações
• Declaração deve vir antes do uso
• Os nomes das variáveis são constituídos de letras e dígitos, onde o primeiro
caractere é uma letra
• Há diferença entre letras maiúsculas e minúsculas
L I N G U A G E M C
T I P OS D E D A D O S
Tipos de Dados
→ char - tipo caractere (normalmente um byte)
→ int - tipo inteiro (tamanho natural de inteiro na máquina “2 bytes”) → float - tipo ponto flutuante de precisão simples (1e-37 até 1e+37) → double - tipo ponto flutuante de precisão dupla
→ void - tipo explicíto para funções ou ponteiros (será visto a posterior)
• Qualificadores para o tipo inteiro → short
→ long → unsigned A Norma ANSI C
• Diferentes compiladores C para diferentes arquitetura de hardware
define tamanhos diferentes para o armazenamento dos tipos de dados da Linguagem C
Tipo Tamanho em Bits Intervalo char 8 -127 à 127 unsigned char 8 0 à 255 signed char 8 -127 à 127 int 16 -32.767 à 32.767 unsigned int 16 0 à 65.535
signed int 16 Igual a int
short int 16 Igual a int
unsigned short int 8 0 à 65.535
signed short int 8 Igual a short int
long int 32 -2.147.483.647 à 2.147.483.647
unsigned long int 32 0 à 4.294.967.295
signed long int 32 Igual a long int
float 32 Seis dígitos de precisão
double 64 Dez dígitos de precisão
long double 128 Dez dígitos de precisão
Todos os tipos de dados defenidos pelo padrão ANSI
Identificadores
• Usados para definir nomes de variáveis, funções, rótulos (labels), etc.
• Consiste de um ou mais caracteres, o primeiro caracter deve ser letra ou “_”,
os demais devem ser letras, ou números ou “_”
• Pode ter qualquer tamanho , os 6 primeiros caracteres devem ser significativos
para serem usados como nomes externos, e os 31 primeiros caracteres para nomes internos
Correto Incorreto
contador 1contador
Variáveis
• É uma posição da memória, identificada por um nome (identificador), usada
para guardar um valor que poderá ser usado, modificado pelo programa
• Todas as variáveis em C devem ser declaradas
• Uma declaração consiste de um tipo (adcionado de algum qualificador) e de
uma lista de variáveis (separadas por vírgula) que sejam deste tipo Ex: int soma, total;
double fact; char carac, ch;
unsigned int idade; short int valor;
• C não inicializa as variáveis
• Variáveis podem ser inicializadas quando declaradas
Ex: int eh_zero = 0, num_max = 5000;
float pi = 2.1416, eps = 1.0e-5;
Onde declarar variáveis
• dentro de funções → variáveis locais
• definição dos parâmetros das funções → parâmetros formais • fora das funções → variáveis globais
• Variáveis Locais
• Só pode ser referenciada dentro do bloco na qual foi definida, são criadas após
a sua definição e são destruídas após a saída do bloco
• Um bloco é identificado por um par de chaves “{“ no ínicio e “}” no fim, no
máximo um bloco representa uma função
• Variáveis podem ser definidas em qualquer parte do bloco, normalmente as
variáveis são definidas logo no início de uma função ( a variável local só pode ser referenciada depois de ter sido definida)
Parâmetros Formais
• São usados para definir os argumentos de uma função • Comportamento igual ao de uma variável local
• Lista de identificadores, separados por vírgula, após o nome da função entre
parenteses
• Deve-se definir os parâmetros e o tipo deles deve ser o mesmo definido para os
Variáveis Globais
• Diferem das variáveis locais por poderem ser usadas em qualquer parte do
código
• Existem durante todo o ciclo de vida do programa (ocupa memória)
• Normalmente são declaradas no ínicio do programa e/ou em arquivos do tipo
header (*.h)
• Se uma variável local tem o mesmo nome de uma variável global, dentro do
bloco no qual foi definido a variável local ela terá prioridade sobre a global
• Deve-se evitar o uso abusivo de variáveis globais para evitar problemas de
limitação de memória e de tempo de execução
• As variáveis globais só podem ser declaradas uma só vez • O Tipo const
• Variáveis do tipo const não podem ser modificadas pelo programa, entretanto
elas “podem” ser inicializadas quando forem definidas
Especificadores de Tipos de Armazenamento deVariáveis • extern • static • register • auto • extern
• Permite que dois ou mais arquivos compartilhem as mesmas variáveis globais • As variáveis globais só podem ser declaradas uma só vez
• É um mecanismo para importar variáveis globais definidas em outros arquivos • O escopo de uma variável extern vai do ponto em que ela é declarada no
arquivo fonte até o fim do mesmo
• Para variáveis automáticas (locais) e argumentos, o escopo é a função em que o
nome é definido
• Declaração extern é obrigatória em dois casos • Declaração é diferente de definição
Ex:
Arquivo 1: Arquivo 2: int ap = 0; /* apontador */ extern int ap;
double val [MAXVAL]: extern double val[ ];
double empil (f) { ... } double desempil ( ) { ... }
• static
• Quando usado em uma variável local: instrui o compilador a manter a
variável local existente durante o tempo de vida do programa (ela só existe no bloco em que foi definida)
• Quando usado em uma variável global: instrui o compilador a limitar o
uso desta variável ao arquivo onde ela foi definida
Ex: int contador ( x) char x; {
static int meucontador = 0;
meucontador = meucontador + 1; ...
} • register
• usado em variáveis locais do tipo caractere ou inteiro, provê um acesso
mais rápido a mesma (pode também ser usado nos parâmetros formais). Em algums implementações utiliza registradores ao invés de memória
Ex: register int aux;
for (aux = 0; aux < 100; aux++) {
... }
• auto
• usado para declarar variáveis locais. É opcional e pouco usado porque é
Constantes
• São valores constantes fixos dentro do programa que não podem ser alterados
Tipo de Dado Exemplos
int 1 123 21000 -234
long int 35000L -34L
short int 10 -12 90
unsigned int 10000U 987U 40000
float 123.23F 4.34e -3F
double 123.23 12312333 -0.9876324
long double 1001.2L
hexadecimal int hex = 0x80 (128)
octal int oct = 012 (10)
character ‘a’
string “este e um teste”
Código Significado \b Espaço \f Alimenta formulário \n Pula linha \r “Carriage return” \t Tabulação horizontal \” Aspa dupla \’ Aspa simples \0 NULL \\ \ \v Tabulação vertical \a Alerta \N Constante octal \xN Constante hexadecimal
• O uso de constantes simbólicas torna o programa mais legível. Geralmente são
escritas com letras maiúsculas. O comando define neste exemplo será processado pelo pré-processador do C (cpp)
Ex: #define INICIO 0 /* limite inferior da tabela */ → int
#define GOS 0.1 /* grau de servico eh 10% */ → double #define FIM 123L /* limite inferior */ → long
• Operadores
• atribuição • aritméticos • relacionais • lógicos
• manipulação de bits (bitwise) • especiais
• Atribuição
• O operador de atribuição pode ser usado em qualquer expressão válida em C Forma geral:
nome-da variavel = expressao ;
• O nome-da-variavel deve ser uma variável ou um pointer (para um endereço
válido na memória)
• Múltiplas atribuições • Ex: x = y = z = 0;
• Quando tipos diferentes de variáveis são usados ocorre uma conversão de tipos
nas seguintes situações (este resultado depende da arquitetura do hardware)
Tipo da Variável Tipo da Expressão Possíveis Perdas
signed char char Se valor > 127, valor final é negativo
char short int 8 bits de mais alta ordem
char int 8 bits de mais alta ordem
char long int 24 bits de mais alta ordem
int long int 16 bits de mais alta ordem
int float parte fracionária e talvez mais info
float double Precisão, resultado arredondado
double long double Precisão, resultado arredondado
• Operadores Aritméticos
Operador Prioridade Ação
- 3 (1) subtração ( unário )
+ 3 adição
* 2 multiplicação
/ 2 divisão
% 2 resto da divisão (só para int)
-- 1 decrementa ++ 1 incrementa Ex: x = x + 1; → ++x; x = x -1; → x--; x = 10; y = ++x; → y = 11 x = 10; y = x++; → y = 10 • Operadores Relacionais
Operador Prioridade Ação
> 4 maior que
> = 4 maior ou igual que
< 4 menor que
< = 4 menor ou igual que
= = 5 igual
• Operadores Lógicos
Operador Prioridade Ação
&& 6 e
|| 7 ou
! 1 não
• Operadores para Manipulação de Bits (só para int e char)
Operador Ação & e | ou ^ ou exclusivo ~ complemento de 1 >> deslocamento à esquerda << deslocamento à direita
Ex: ch & 127 1 1 0 0 0 0 0 1 com paridade 0 1 1 1 1 1 1 1 & 0 1 0 0 0 0 0 1 sem paridade 128 | 3 1 0 0 0 0 0 0 0 127 ^ 120 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 0
| (ou) ^ (ou exclusivo) 1 0 0 0 0 0 1 1 0 0 0 0 0 1 1 1
char x x depois de cada comando valor de x x = 7; 0 0 0 0 0 1 1 1 7 x << 1; 0 0 0 0 1 1 1 0 14 x << 3; 0 1 1 1 0 0 0 0 112 x << 2; 1 1 0 0 0 0 0 0 192 x >> 1; 0 1 1 0 0 0 0 0 96 x >> 2; 0 0 0 1 1 0 0 0 24
Multiplicação e Divisão através do operador de deslocamento
Ex: complemento de 1
~ 0 0 1 0 1 1 0 0 → 1 1 0 1 0 0 1 1 • Operadores Especiais
• O operador ?
Forma geral: Exp1 ? Exp2 : Exp3 Ex: x = 10;
y = x > 9 ? 100 : 200; • Os operadores & e * para pointers (ponteiros)
- Um ponteiro é o endereço de uma variável na memória
- Uma variável do tipo ponteiro (pointer) pode ser declarada para um
tipo específico de dado
- Ponteiros podem ser usados para: acesso rápido a elementos de
arranjos; modificar os parâmetros de chamad de uma função; e acesso a estruturas dinâmicas
Ex: m = &contador; → m recebe o endereço de contador q = *m; → q recebe o valor que está armazenado no endereço m
• O operador , (vírgula)
-Usado para juntar várias expressões Ex: x = ( y = 3, y + 1);
• Precedência e Ordem de Avaliação
• A tabela abaixo apresenta um resumo das regras de precedência e
de`associatividade de todos os operadores vistos
Operador Associatividade
( ) [ ] -> . esquerda para direita ! ~ ++ - - - (tipo) * & sizeof direita para esquerda
* / % esquerda para direita
+ - esquerda para direita
<< >> esquerda para direita
> = > < < = esquerda para direita
= = ! = esquerda para direita
& esquerda para direita
^ esquerda para direita
| esquerda para direita
&& esquerda para direita
|| esquerda para direita
?: direita para esquerda
++ = -= etc. direita para esquerda
L I N G U A G E M C
Comandos de Controle
• O ponto-e-virgula (;) é usado como terminador de comandos • seleção • iteração • desvio • rótulo (label) • expressão • bloco • Comando de Seleção • if
Forma Geral: if (expressão) comando; else comando;
• switch
Forma Geral: switch (expressão) {
case constante1: comando(s) break; case constante2: comando(s) break; . . . default: comando(s) }
Comando de Iteração
• for
for (expressao_1; expressao_2; expressao_3) inicialização condição de parada incremento comando;
Loop infinito: for (; ;) comando;
for sem corpo: for ( t=0; t < VALOR; t++);
• while
Forma Geral: while (condição) comando;
• do-while
Forma Geral: do {
comando(s) ;
Comando de Desvio
• return
Forma Geral: return expressão; → (opcional)
• goto
Forma Geral: goto label; . . . label: comando; • break
Forma Geral: break;
• exit
Forma Geral: void exit (int codigo-de-retorno);
• continue
• Expressões
• Qualquer expressão válida em C seguida de um “;” Ex: func ( ); /* chamada de funcao */ a = b + c; /* comando de atribuicao */ ; /* comando nulo */
• Bloco de Comandos
• Comandos agrupados que são tratados como uma unidade. Devem estar entre
• Exemplos • main () { printf(“programa em C\n”); }
• main ( ) /* copia entrada na saída */ main( ) { {
int c; int c;
c = getchar( ) ; while ((c = getchar( )) != EOF) while (c != EOF) putchar(c);
{ } putchar (c); c = getchar( ); }
}
• main() /* teste da funcao de potencia */ {
int j;
for ( j = 0; j < 10; j++) printf ( “%d %d %d\n”, j , pot(2,j), pot(-3,j));
} pot (x, n) int x, n; { int j, p; p = 1; for (j = 1; j <= n; ++j) p = p * x;
L I G U A G E M C
Arranjos
• Coleção de variáveis do mesmo tipo referenciadas por um só nome. Um
elemento específico num arranjo é localizado por um índice ou mais
• Os arranjos em C podem ter de 1 a N dimensões
• Pode-se declarar arranjos em quaisquer dos tipos de dados descritos
anteriormente
• Os índices de arranjos começam sempre de 0 • C não faz testes para os limites de um arranjo • Arranjo Bi-dimensional
• Arranjos com várias dimensões são declarados colocando-se a dimensão
adicional dentro de outro par de colchetes
• Strings
• O uso mais comum para os arranjos uni-dimensionais é na declaração de
strings (cadeia de caracteres)
• Em C um string é definido como uma cadeia de caracteres que termina por um
caractere null (‘\0’). Portanto quando declarar o arranjo adicione 1 ao tamanho máximo
Ex: char s [11]; → s pode armazenar 10 caracteres → s [10] deve ser o caracter null (‘\0’)
• Em C não existe o tipo de dados string, porém existe a constante do tipo string Ex: char mensagem = “ola a todos”;
• Funções para Manipulação de Strings
Nome Função strcpy (s1, s2) copia s2 em s1
strcat (s1, s2) concatena s2 no fim de s1 strlen (s1) retorna o tamanho de s1
strcmp (s1, s2) retorna 0 se s1 e s2 forem do mesmo tamanho retorna < 0 se s1 < s2 retorna > 0 se s1 > s2
strchr (s1, ch) retorna um ponteiro para o primeiro caracter de ch em s1
strstr (s1, s2) retorna um ponteiro para a primeira ocorrência de s2 em s1
• Arranjos de strings
• É só utilizar o bi-dimensional arranjo de caracteres Ex: char str-array [30] [80];
• Inicialização de Arranjos
Ex: int j[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; char str [14] = “Eu gosto de C”;
char str [14] = {‘E’, ‘u’, ‘ ‘, ‘g’, ‘o’, ‘s’, ‘t’, ‘o’, ‘ ‘, ‘d’, ‘e’, ‘ ‘, ‘C’, ‘\0’};
Ex:
main ( ) int nbranco = 0; { int noutro = 0;
int c, j, nbranco, noutro; int ndigito[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} int ndigito[10]; main ( ) nbranco = noutro = 0; { for (j = 0; j < 10; j ++) int c, j; ndigito[j] = 0; . . . . . . } }
Exemplos
• main () /* conta carac. na entrada */ main () { {
long int nc; double int nc; nc = 0; for (nc = 0; getchar() != EOF; ++nc) while (getchar () != EOF) ;
++nc; printf (“%.0f\n”, nc); printf (“%ld\n”, nc); } } • main () /* conta digitos, espaco em branco, outros caracteres */ { int c, j, nbranco, noutro; int ndigito [10]; nbranco = noutro = 0; for (j = 0; j < 10; ++j) ndigito [j] = 0; while ((c = getchar()) != EOF) if (c >= ‘0’ && c <= ‘9’) ++ndigito [c - ‘0’]; else if (c == ‘ ‘ || c== ‘\n’ || c == ‘\t’) ++nbranco; else ++noutro; printf (“digitos =“); for (j = 0; j < 10; j++) printf (“%d”, ndigito [j]); printf(“\nespacos em branco = %d, outros = %d\n”, nbranco, noutro);
Exemplos (continuação)
• /* exemplo do uso do continue */ for (j = 0; j < N; j++)
{
if (a[j] < 0) /* elementos negativos saltados */ continue;
. . . /* elementos positivos processados */ }
• /* exemplo do uso do goto */ for (j = 0; j < N; j++) for (k = 0; k < M; k++) if (v[j][k] < 0) goto achei; /* nao achei */ . . . achei: /* achei na posicao j, k */
L I N G U A G E M C
E S T R U T U R A S E U N I Õ E S
Estruturas
• Pode-se criar combinações de tipos de dados básicos, utilizando struct e union • Uma estrutura é uma coleção de uma ou mais variáveis que podem ser de
tipos diferentes e que passam a ser referenciadas por um único nome Forma Geral: struct tag {
tipo nome-da variavel; tipo nome-da variavel; tipo nome-da variavel;
. . .
} variaveis-estruturas; Ex: struct func struct func { {
int matr; int matr; char nome [40]; char nome [40]; int setor; int setor;
float salario; float salario; } serv1, serv2; };
struct func serv1, serv2; • O operador ponto (.) é usado quando se quer referenciar um elemento
individual de uma estrutura Ex: serv1.setor = 2112;
serv1.salario = 2190000.21 • Estruturas admitem aninhamento
Uniões
• Uma union é definida quando duas ou mais variáveis compartilham a
mesma área de memória Ex: union qualq
{ char ch; int x; } aux1; x byte 1 byte 2 ch Exemplos:
struct data static int tab_dia[2][13] = {
{ {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} int dia; {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} int mes; }; int ano; int dia_ano; char nome_mes[4]; };
dia_do_ano(ad) /* acha o dia do ano a partir do dia do mes */ struct data *ad;
{
int j, dia, bissexto; dia = ad -> dia;
bissexto = ad -> ano % 4 = = 0 && ad -> ano % 100 ! = 0 || ad -> ano % 400 = = 0;
• Exemplos (continuação) • #define SIM 1 #define NAO 0
main( ) /* conta linhas, palavras, caracteres na entrada */ {
int c, nl, np, nc, empalavra; empalavra = NAO;
nl = np = nc = 0;
while ((c = getchar( ) ) != EOF) { nc++; if (c = = ‘\n’) nl++; if (c = = ‘ ‘ || c = = ‘\n’ || c = = ‘\t’) empalavra = NAO;
else if (empalavra = = NAO) { empalavra = SIM; np++; } } }
• atoi (s) /* funcao que converte um string de números s em um inteiro */ { int j, n = 0; for ( j = 0; s[j] >= ‘0’ && s[j] <= ‘9’; ++j) n = 10 * n + s[j] - ‘0’; return (n); }
• Exemplos (continuação)
• comprime (s, c) /* remove todos os c de s */ char s[ ]; int c; { int j, k; for (j = k = 0; s[j] != ‘\0’; j++) if (s[j] != c) s[k++] = s[j]; s[k] = ‘\0’; }
• contabits (n) /* conta os bits ligados em n */ unsigned n; { int b; for (b = 0; n != 0; n >>= 1) if (n & 01) b++; return (b); }
• Exemplos (continuação)
• pesq-binaria(x, v, n) /* acha x em v[0] ... v[n-1] */
int x, v[ ], n; {
int inicio, fim, meio; inicio = 0;
fim = n -1;
while (inicio <= fim) {
meio = (inicio + fim) / 2; if (x < v[meio]) fim = meio - 1; else if (x > v[meio]) inicio = meio + 1; else /* achou */ return(meio); } return (-1); }
• Exemplos (continuação)
/* imprimir a tabela de conversão Fahrenheit-Celsius para f = 0, 20, ..., 300 */ • main( )
{
int inicio = 0, /* limite inferior da tabela */ fim = 300, /* limite superior */
incr = 20; /* incremento */ float fahr, celsius;
fahr = inicio; while (fahr <= fim) {
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf(“%4.0f %6.1f\n”, fahr, celsius); fahr = fahr + incr;
} }
• /* imprimir a tabela de conversão Fahrenheit-Celsius para f = 0, 20, ..., 300 */
#define INICIO 0 /* limite inferior da tabela */ #define FIM 300 /* limite superior */
#define INCR 20 /* incremento */ main( )
{
int fahr;
for (fahr = INICIO; fahr <= FIM; fahr += INCR)
printf(“%4.0f %6.1f\n”, fahr, (5.0 / 9.0) * (fahr - 32)); }
L I N G U A G E M C
Uso de Funções
• Funções dividem grandes tarefas de computação em partes menores e simples • Um programa é estruturado em C como um conjunto de definições individuais
de funções
• O programa fonte pode ser dividido em arquivos múltiplos
Funções em C
• Comunicação feita por argumentos e valores retornados
• O return define um mecanismo para retornar um valor de uma função
chamada para a sua chamadora
• As funções podem ocorrer em qualquer ordem no arquivo fonte • C permite que declaremos o tipo que uma função irá retornar
• A rotina chamadora deve estabelecer que a função chamada retorna um valor
não inteiro
• Por “default”, o tipo de uma função é int Passagem de Estruturas para Funções
• Pode se pssar um elemento de uma estrutura por valor Ex: struct exemplo {
char x; int y;
} ex;
• Passagem do endereço de um componente Ex: func2 (&ex.x);
• Passagem de uma Estrutura por referência func3 (&ex);
Exemplos do uso de Funções
• double fatorial (num) int num;
/* Retorna o fatorial de um numero. Se um erro ocorre, ela retorna o valor -1 e emite uma mensagem */
{
double aux, fact; if (num < 0)
{
printf (“\n Erro: fatorial de um numero negativo!”); fact = -1.0;
} else {
fact = 1.0;
for (aux = num; aux > 0: aux --) fact *= aux;
}
return (fact); }
• atoi (s) /* converte um string num inteiro */ char s[ ];
{
int j, n, sinal;
for (j = 0; s[j] == ‘ ‘ || s[j] == ‘\n’ || s[j] == ‘\t’; j++) ; /* pula espacos em branco */
sinal = 1;
if (s[j] == ‘+’ || s[j] == ‘-’) /* sinal */ sinal = (s[j++] == ‘+’) ?1:-1;
Utilização de Parâmetros
• A passagem de argumentos pode ser feita por: • valor
• referência (endereço), por exemplo, o endereço de um arranjo • As funções em C aceitam um número variável de argumentos (não
transportável)
• As variáveis externas (globais) são definidas fora de qualquer função e ficam
disponíveis para qualquer função
• As funções são sempre externas (não há aninhamento)
• Deve-se usar variáveis externas quando há um grnde número de funções que
fazem uso das mesmas
• O escopo de um nome é a parte do programa para o qual o nome é definido • Para variáveis automáticas (locais) e argumentos, o escopo é a função em que o
nome é definido
• Num programa C deve ter pelo menos a função main ( ) onde começa a
execução
• A função main ( ) tem dois argumentos: • argc
Funções de Entrada e Saída
As funções de entrada e saída estão definidas no arquivo header “stdio.h” • A Função Printf
Permite a impressão de quantidades numéricas, strings, caracteres, etc. Forma Geral:
printf (controle, arg1, arg2, ... )
caracteres ordinários e especificações de conversão ( % )
• Entre o % e o caractere de conversão pode haver:
⇒ sinal de menos
⇒ cadeia de dígitos (tamanho mínimo) ⇒ um ponto ⇒ cadeia de dígitos ⇒ modificador de tamanho (l) • Caracteres de conversão: d, o, x, u, c, s, e, f e g Ex:
printf(“fatorial de %d = %g\n”, num, fatorial(num));
• Por “default” todos os tipos são ajustados à direita, para ajustar à esquerda
Formato Significado
%c caracter
%d inteiro decimal com sinal
%i inteiro decimal com sinal
%e notação científica com e
%E notação científica com E
%f ponto flutuante decimal
%g escolhe %e ou %f ,o menor dos dois formatos
%G escolhe %E ou %f ,o menor dos dois formatos
%o octal
%p imprime o endereço de um ponteiro
%s cadeia de caracteres
%u inteiro decimal sem sinal
%x hexadecimal sem sinal (letras minúsculas)
%X hexadecimal sem sinal (letras maiúsculas)
%% imprime o caracter ‘%’
• Exemplo main ( ) { int num; double fatorial;
printf (“\n Entre com um numero:”); scanf (“%d”, &num);
printf (“\n Fatorial de %d %f\n”, num, fatorial(num)); }
double fatorial (x)
int x;
/* Calcula o fatorial de um numero recursivamente. Retorna um valor negativo se recebe como parametro um numero negativo */ {
if (x < 0) {
printf (“\n Erro: fatorial de um numero negativo!!!); return (-1); } else if (x == 0) return (1); else return (x * fatorial (x - 1)); }
• A função Scanf
Usada para a entrada (leitura) de dados, para string ler até o primeiro espaço
em branco, ou o return, ou o tab.
Forma Geral:
scanf ( controle, arg1, arg2, . . .)
Devem ser apontadores
Análogo ao printf
A cadeia de controle pode conter
⇒ Espaços em branco ⇒ Caracteres ordinários
⇒ Especificações de conversão
⇒ Um número (opcional) especificando o tamanho do campo ⇒ Caracteres de conversão
• Caracteres de conversão aceitos: d, o, x, h, c, s e f
Ex: Note que a função scanf está usando passagem de parâmetros por referência
#include <stdio.h>
main ( ) /* calculadora elementar */ {
double soma, v;
soma = 0;
while (scanf (“%lf”, &v) != EOF)
printf (“\t%.2f\n”, soma += v); }
• Os caracacteres d, o, x e f podem ser precedidos por l
Formato Significado
%c lê um caracter
%d lê um inteiro decimal com sinal
%i lê um inteiro decimal com sinal
%e lê um número ponto flutuante
%f lê um número ponto flutuante
%g lê um número ponto flutuante
%o lê um octal
%p lê o endereço de um ponteiro
%s lê uma cadeia de caracteres
%u lê um inteiro sem sinal
%x lê um hexadecimal sem sinal
L I N G U A G E M C
A P O N T A D O R E S ( P O I N T E R S )
Apontadores
• Um apontador é uma variável que contém o endereço de outra variável
• Levam a um código mais compacto e eficiente (disciplina)
• É aplicado apenas a variáveis, elementos de arranjos e elementos de estruturas
• O operador unário & fornece o endereço de um objeto
Ex: px = &x;
• O operador unário * trata seu operando como endereço
Ex: y = *px;
• É necessário haver declaração de tais variáveis Ex: int x, y;
int *px;
• Podem ocorrer em expressões (os operadores * e & têm precedência sobre
os demais operadores)
Ex: y = *px + 1; ≠ * ( px + 1 )
*px = 0; (*px) ++;
Apontadores e Argumentos de Funções
• Apontadores são utilizados quando se quer passar valores por referência
• O programa chamador passa apontadores para as variáveis que se quer
atualizar
Ex: troca (ax, ay) /* permuta *ax e *ay */
int *ax, *ay; { int temp; temp = *ax; *ax = *ay; *ay = temp; }
• Uso comum quando uma função deve retornar mais de um valor
Ex: leint (an) /* le proximo caracter da entrada */
int *an; {
int c, sinal;
while (( c = getch( )) = = ‘ ‘ || c = = ‘\n’ || c = = ‘\t’) ; /* pula espaco em branco */
sinal = 1; if (( c = = ‘+’ || c = = ‘-’) /* guarda o sinal */ { sinal = (c = = ‘+’) ? 1 : -1; c = getch ( ); }
for (*an = 0; c >= ‘0’ && c <=‘9’; c = getch ( )) *an = 10 ** an + c - ‘0’;
*an *= sinal; if (c != EOF) ungetch ( c);
Apontadores e Arranjos
• Existe um relacionamento muito estreito entre arranjos e apontadores Ex: int a[10];
int *pa;
pa = &a[0]; /* pa = a */
x = *(pa + 1) /* refere-se ao conteudo de a[1] */
• Obs: a[j] é idêntico a *( a + j )
• Qualquer arranjo e expressão indexada podem ser escritos como um
apontador e deslocamento ( vice-versa )
• É possível passar parte de um arranjo para uma função
Aritmética com Endereços
• Se p é um apontador, então p++ faz p apontar para o próximo elemento,
independente do tipo para o qual p aponta
Ex: strlen (s) /* retorna o tamanho da cadeia s */ char *s; { char *ap = s; while (*ap != ‘\0’) ap++; return (ap - s);
• Operações permitidas com apontadores: adição/subtração com inteiro;
adição/subtração/comparação de dois apontadores NULL e p < q
Apontadores de Caractere e Funções
• Quando uma cadeia de caracteres aparece num programa, o acesso a mesma é
feito através de um apontador de caractere
Ex: char *mensagem;
mensagem = “sou uma cadeia”;
strcpy (s, t) /* copia t em s */ strcpy (s, t) /* copia t em s*/ char s[ ], t[ ]; char *s, *t; { { int j; while ((*s++ = *t++) != ‘\0’) ; j = 0; } while ((s[j] = t[j] != ‘\0’) j++; } Note que: *++p ≠ *p++
• É possível criar apontadores para apontadores Ex: int *tab_dia[13];
• Arranjos de apontadores podem ser incializados
Ex: char *nome_mes (n) /* retorna o nome do n-esimo mes */
int n; {
static char *nome[ ] = { “mes ilegal”, “janeiro”, “fevereiro”, . . . “dezembro” };
return ((n < 1 || n > 12) ? nome[0] : nome[n]); }
Apontadores para Funções
• É possível definir um apontador para uma função
• Tal apontador pode ser manipulado, passado como argumento, colocado em
arranjos, etc.
Apontadores para Estruturas
Ex: struct addr *addr-pointer;
• A referência para um elemento de uma estrutura através de um apontador
para esta estrutura é feita usando o operador “->“
Ex: struct exemplo { float numero; char nome [80]; } pessoa; struct exemplo *ptr; ptr = &pessoa; ptr -> nome = “Luis”; • Argumentos da Linha de Comando
• Os únicos argumentos permitidos para a função main
são argc e argv
apontador para os argumentos passados número de argumentos da linha de comando Ex: main (argc, argv)
int argc; char *argv[ ];
{
if (argc < 2)
printf (“Entre com seu nome na linha de comando\n”); else
• argv[0] é o nome do programa e argv[1] é o primeiro argumento
Função para abrir e fechar arquivos
• Existência de um apontador de arquivo
Ex: FILE *fp, *fopen ( );
fp = fopen (nome, modo);
• Os modos de abertura podem ser os seguintes:
“r” - leitura “w” - gravação “a” - adição
• O apontador nulo, NULL, é retornado se há um erro
• fclose ( ) para fechar arquivos
Leitura e Gravação em Arquivos
• Para ler ou gravar num arquivo, pode-se usar: getc ( ), putc ( ), fscanf ( ), fprintf ( )
Ex: c = getc (fp);
Exemplos
#include <stdio.h>
main (argc, argv) /* cat: concatena arquivos */ int argc;
char *argv[ ]; {
FILE *fp, *fopen ( );
if (argc = = 1) /* nao tem argumentos; copia entrada padrao */ copia_arq (stdin);
else
while (--argc > 0)
if ((fp = fopen (*++argv, “r”)) = = NULL) {
fprintf (stderr, “Erro: cat nao pode abrir %s\n”, *argv); exit (1); } else { copia_arq (fp); fclose (fp); } exit (0); }
copia_arq (fp) /* copia arquivo fp na saida padrao */ FILE *fp;
{
int c;
while ((c = getc (fp) != EOF) putc (c, stdout);
O Preprocessador C
• Uma linha do tipo
#include “nome_arquivo”
é substituída pelo conteúdo de nome_arquivo
• Substituição de macros: #define TRUE 1
• Exemplo: