LINGUAGEM C

1. Estrutura Básica de um Programa.

	Um programa em C consiste numa colecção de funções e variáveis.

	Programa = {Declarações} FunçãoMain.

	Declarações = {Bibliotecas} |
					{Constantes} |
					{Tipos} |
					{Variáveis} |
					{Funções} .

	Bibliotecas = (#INCLUDE biblio)*.

	biblio = <nome_biblioteca> | "nome_biblioteca".

	Constantes = (#DEFINE nome valor)*.

	Tipos = (TYPEDEF tipo nome ";")*.

	Variáveis = (tipo lista_de_identificadores";")*.

	Funções = (tipo nome (declaração_parâmetros)
				(declaração_tipo)*";"
				(declaração_variáveis)*";"
				comandos)*.

1. 1. Bibliotecas.

	A linguagem C suporta programação modular, permitindo a divisão de um programa em vários ficheiros.

	Os ficheiros com código C podem ter duas extensões:
	- nome.h: tratam-se de ficheiros header, que contém definições de tipos de dados e cabeçalhos de funções;
	- nome.c: tratam-se de ficheiros code, que contém o código das funções.

	As funções existentes nas bibliotecas não pertencem à linguagem C "base". Logo para usar essas funções é necessário importar as respectivas bibliotecas.

	Bibliotecas de sistema: stdio.h, stdlib.h, math.h.

1.2. Constantes.

	#DEFINE mil 1000

	#DEFINE false 0

	#DEFINE vtab '\xb'

1.3. Tipos de Dados.

	1.3.1. Tipos Básicos

	INTEIROS			int

	REAIS					float ou double

	CARACTERES		char
	
							'x'	'A'
	
							'\t'	'\n'
	
							"cadeias de caracteres"

	ENUMERADOS		enum nome {t1, ..., tn}

	O 1ª valor da lista tem índice 0, o segundo 1, etc.

		Exemplos:

	enum dias_semana {seg,ter,qua,qui,sex,sab,dom}

		enum boolean {no,yes}

	NOTA: não existe explicitamente o tipo booleano 	nem a possibilidade de definir tipos intervalares

	BOOLEANOS		{	0, 	int \ {0} }
								≠		≠
							   false		true

	1.3.2. Operadores Aritméticos

		+		Adição

		-		Subtracção

		*		Multiplicação

		/		Divisão

		%		Módulo (Resto da divisão inteira)

	1.3.3. Operadores Relacionais	

		Dão como resultado 1 ou 0

		>	>=		<	<=		

		== 	(igual)

		!=	(diferente)

	1.3.4. Operadores Lógicos

		Entre expressões inteiras, tendo como resultado 1 ou 0

		&&		(AND)

		||			(OR)

		!			(NOT)

	1.3.5. Operadores Bit a Bit

		Entre expressões inteiras

		&			(AND)

		|			(OR inclusivo)

		^			(OR exclusivo)

		<<			(Left shift)

		>>			(Right shift)

		~			(Complemento)

	1.3.6. Tipos Estruturados

Estruturas

	struct	nome	{
				tipo	campo_1;
				tipo	campo_2;
				.
				.
				tipo	campo_n;
	}

Exemplo

	struct	aluno	{
				int		n_mec;
				float	nota;
	}

corresponde a

	aluno = record
			 n_mec: integer;
			 nota : real
				end;

Arrays (vectores)

Declaração:	tipo	ident '[' int ']' 

Exemplo:	int		v [ 10 ];

Declaração de um vector com 10 componentes:

			v[0], v[1], ... v[9]

corresponde a

			array [0..9] of integer;

OBS:	o índice do vector pode ser uma qualquer expressão inteira

Exemplo:		int	i;

				v[i+5]

1.4. Declarações de Tipos.

TYPEDEF tipo nome;

Exemplo:

typedef	enum naipe_en 
	{ouros, copas, espadas, paus} naipe;

typedef enum valor_en {dois,três,quatro,cinco,seis,sete,oito,nove,dez,dama,valete,rei,ás}
valor;

typedef	struct carta_str {
				valor	número;
				naipe	tipo;
			} carta;

typedef	carta jogador[13];

1.5. Declarações de Variáveis.

	Obs: os identificadores são separados por virgulas 

	Exemplos:			int	a;
						int	b;

						ou	int	a, b;	

 						float	x;
						double	y;

						char	c, string[100];

						struct	aluno_str	a1, a2;
						aluno	a1, a2;

	Pode-se inicializar uma variável na sua 	declaração.

	Exemplo			int		i = 0;
		
						float	x = 1.0e-5;

						aluno	a1 = {38235, 14.0};

						char	palavra[10] =  "word";

						int		v[5] = {1, 2, 3, 4, 5}

	OBS: as declarações não têm que ser agrupadas 	como em pascal, podendo-se intercalar declarações 	de 	constantes, variáveis, tipos, funções, etc.

1.6. Comandos

	1.6.1. Atribuição

	variável = expressão

	exp ::= constante | variável | exp_aritmética | 
			exp_lógica | selecção | atribuição | 
			exp_condicional.

	Exemplo	int	a, b, c; double x; aluno p;

				b = 5;	
				a = c = 3;
				x = cos(a) * (b + c) + 2;
				b = p.n_mec;
				a == b ? x *= 2 : x *= 3;

	1.6.2. Atribuições Especiais

C														Pascal

x += exp;										x := x + exp;

x -= exp;										   x := x - exp;

x *= exp;										x := x * exp;

x /= exp;										   x := x / exp;

x++; ou ++x;								x := x+1;	

x--; ou --x;										x := x-1;	

*	ATENÇÃO

	++ e -- podem ser usadas como expressões aritméticas

	neste caso:
		
	-	o incremento (ou decremento) de uma unidade à variável é feita antes da avaliação da expressão, se ++ (ou --) se encontrar antes da variável

	-	o incremento (ou decremento) de uma unidade à variável é feita depois da avaliação da expressão, se ++ (ou --) se encontrar depois da variável

Exemplo

C														Pascal

x = f(y++);										x := f(y);
														y := y+1;

x = f(++y);										y := y+1;
														x := f(y);										

	1.6.3. Composição Alternativa Simples

	if	(expressão)	
		bloco_1
	else				
		bloco_2

	Exemplo:	

	C									PASCAL

	if (x>0) y += x;					if x>0 then 									y:=y+x:

	if (x>0) y += x;					if x>0 then 
	else y = 0;								y:=y+x
												else y := 0;

	if (x>0) {									if x>0 then begin
		y /= x;										y := y / x;
		x --;										x := x-1
	}									  	end	
	else {										else begin
		y = 0;										y := 0;
		x++;										x := x+1
	}											end;

	ELSE-IF							não existe pascal

	if	(expressão_1)
		bloco_1
	else if (expressão_2)
		bloco_2
	.
	.
	else
		bloco_n

Exemplo		if (x>0) printf("Positivo\n");
				else if (x == 0) printf("Nulo\n");
				else printf("Negativo\n");

				if	(x>0) {
					x = x-1;
					printf("Positivo\n");
				}
				else if (x == 0) {
					x = x+1;
					printf("Nulo\n");
				}
				else {
					x = x+2;
					printf("Negativo\n");
				}

	1.6.4. Composição Alternativa Generalizada 

	switch	(expressão)	{
		case cte_1 :	bloco_1
		case cte_2 :	bloco_2
		.
		.
		.
		case cte_n:		bloco_n
		default:		break;
	}

	Exemplos:
	
	switch (xpto[k].tipo)	{	
		case paus : 	npaus ++; break;
		case ouros :	nouros ++; break;
		case copas: 	ncopas ++; break;
		case espadas:	nesp ++; break;
		default : printf("Erro\n"); break;
	}

	Em Pascal

	case (xpto[k].tipo)	of
			paus : 		npaus := npaus + 1;
			ouros :	nouros := nouros + 1;
			copas: 	ncopas := ncopas + 1;
			espadas:	nesp := nesp +1
	end

	switch (c) {
		case '0': case '1':
			printf("O digito é zero ou um.\n");
			break;
	}

	1.6.5. Composição Iterativa

*	WHILE

	expr1;								
	while (expr2) {
		comando;
		expr3;
	}

	adição:		k = 1;										k := 1;
							s = 0;										s := 0;
							while (k < 100)					while k < 100 do
							{													begin
								s += k;										s := s+k;
								k++;											k := k+1
							}													end

*	FOR

	for (expr1; expr2; expr3) bloco

	onde, normalmente,	
			
				expr1 e expr3 são atribuições 
				expr2 é uma expressão booleana

	for	(s = k = 0; k < 100; s += k++);

	Questão: o que faz o comando for(;;); ?

1.7. Funções

	Programa em C:	colecção de pequenas funções 	(equivalem às funções e 	procedimentos em PASCAL);

									*	função especial que inicia qualquer programa em C:	main().

	Não há tipos ou funções locais a outra função: são sempre GLOBAIS.

		Não existem parâmetros de passagem por variável;  os 	parâmetros são todos de passagem por valor.

		É possível declarar funções que se comportam como 	
         procedimentos; o tipo que devolvem é o tipo especial 	
         VOID.

		Exemplo:

		void opcoes()
		{
			printf("1-Ver ficheiro\n");
			printf("2-Alterar ficheiro\n");
			printf("3-Sair\n");
		}

2. Exemplos

2.1. 

#	include <stdio.h>

main()
{
	printf("Hello, World\n");
}

Nota: para compilar (gnu C) faça gcc hello.c, que gera um executável a.out, ou gcc hello.c -o hello, que gera um executável hello.

2.2.	Programa que soma os 100 primeiros naturais

#	include <stdio.h>

int	soma (int n);

main()
{
	int	n, s;

	printf("Introduza um valor inteiro\n");
	scanf("%d", &n);
	s = soma(n);
	printf("%s %d", "A soma dos", n);
	printf("%s %d","primeiros naturais é", s);
}
										
int	soma	(int	n)
{
	int	k, s;

	k = 1;
	s = 0;
	while (k < n) {
		s = s + k;
		k = k + 1
	}
	return s;
}

TPC: Faça uma versão com o For.

2.3.		Factorial recursivo e iterativo

#	include <stdio.h>

int fact (int n);

main()
{
	int val=0;

	while (val != -1) {
	     printf("Valor: ");
	     scanf("%d",&val); 
            printf("O factorial de %d e' %d\n",val,fact(val));
	}
}

int fact (int n)
{
	int s=n;

	if (n <= 1)
	   return 1;
	else
           return(n*fact(n-1));
 }

ou uma versão iterativa:

int fact (int n)
{
	int i=n,s=1;

	if (i<=1)
 	  return s;
	else
	   while (i != 0) {
		 s*=i;
	        i--;
	   }
	return s;
}

3. Tipos estruturados: ponteiros.

3.1.Declaração

	tipo	*ident;

	constante	NULL		/* NIL do Pascal */

	Operadores

		*	aplica-se a uma variável do tipo ponteiro e  devolve o conteúdo da variável apontada;

		& aplica-se a uma qualquer variável e devolve o endereço de memória dessa variável (usa-se também para fazer passagens por referência).

	Exemplos:

		int *ip;		/* ip é um ponteiro para inteiros /*

		int x = 1, y = 2, z[10];

		ip = &x;
		y = *ip;
		*ip = 0;
		ip = &z[0];

		aluno *p;

		(*p).n_mec 	acede ao conteúdo do campo n_mec da variável apontada por p.

		Equivalente a p -> n_mec

3.2.Relacionamento entre vectores e ponteiros.

			Os vectores são representados internamente em C como ponteiros, mas a alocação de memória é estática e a sua localização não pode ser modificada.

		Qualquer operação sobre os índices dos vectores pode ser feita com a aritmética dos ponteiros.

	Exemplos:

		int	a[10], *pa;

		pa = &a[0];    */ pa aponta a 1ª componente de a */

		a[i] é o mesmo que *(a+i) e &a[i] é a+i

		pa + 1 aponta a[1] e *(pa + 1) refere a[1]

		pa = &a[5];

		pa + 3 aponta a[8] e pa -3 aponta a[2]

		pa = a é equivalente a pa = &a[0];

	Nota: um ponteiro é uma variável, mas o nome de um
			vector não.

			a = pa ou a += i são atribuições inválidas.

3.3.Alocação dinâmica de memória

			(tipo *) malloc (sizeof(tipo))		/* new */
			free (pointer)									/* dispose */

	Funções da biblioteca stdlib.h

	Exemplos:

			char	*p;

			p = (char *) malloc (sizeof(char));
			*p = 'a';
			p = (char *) malloc (20*sizeof(char));
			*p = "palavra";

			aluno *p;

			p = (aluno *) malloc (sizeof(aluno));

			free (p)

			int *a;
			a = (int *) malloc (100*sizeof(int));

	/* alocação dinâmica de memória para um vector */

3.4.Exemplos

			int xpto ()
			{
					char a[] = "abcd";
					int i = 0;
					while (a[i] != '\0') i++;
					return i
			}

			int xpto ()
			{
					char *a = "abcd";
					int i = 0;
					while (a[i] != '\0') i++;
					return i
			}

			int xpto ()
			{
					char *a = "abcd";
					int i = 0;
					while (*a != '\0') {
						i++;
						a++;
					}
					return i
			}

			int xpto ()
			{
					char *a0, *a = "abcd";
					a0 = a;
					while (*a != '\0') a++;
					return a - a0;
			}

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

	typedef struct no_str *lista ;

	typedef struct no_str {
        	 	float nota ;
          		int peso ;
          		lista seg ;
        } no ;

	float media (np)
	lista np ;
	{
        	int pesos ;
        	float soma ;

        	for (pesos=soma=0 ;
             		np!=NULL ;
             		pesos+=np->peso, soma+=(np->peso)*(np->nota), 			np=np->seg) ;
        	return soma/pesos ;
	}

	main()
	{
        	lista nota_peso, aux ;
        	int passo ;
        	char c ;

        	for (passo=1, c='n', nota_peso=NULL ; c!='s' ; passo++)
        	{
                		aux=(no *)malloc(sizeof(no)) ;
                		aux->seg=nota_peso ;
                		nota_peso=aux ;
                		printf("A nota numero %d e: ",passo) ;
                		scanf("%f",&(nota_peso->nota)) ; 						printf("%f",nota_peso->nota);
                		printf("o seu peso e: ") ;
                		scanf("%d",&(nota_peso->peso)) ;
                		printf("Quer continuar?") ;
                		scanf("%c\n",&c) ; printf("sim\n");
                		free(aux) ;
        	}
        	printf("A media e: %f\n",media(nota_peso)) ;
		}