ELC1005 - Algoritmos e Programação

Primeiro semestre de 2009

Avaliação

1a. prova: 12/mai
2a. prova: 7/jul
exame: 14/jul

Data de entrega dos ultimos trabalhos: ate domingo, inclusive. Apresentacoes segunda-feira.

Tem duas provas. Tem dois tipos de trabalhos, os normais e os grandes. Tem 2 trabalhos grandes (o sexto e o último). A primeira prova vale 6. A segunda prova vale 10. Cada trabalho normal vale 1. Juntos, os trabalhos grandes valem 8. O peso de cada trabalho grande é escolhido pelo aluno. O peso mínimo de um trabalho grande é 3. Os trabalhos grandes devem ser apresentados.

Médias Finais

	P1	P2	T1	T2	T3	T4	T5	T6	PT6	T7	M	MF	Ex	MF	Sit
ADFN	25	15	90	100	100	100	85	85	4	95	6,45	EX	29	6,8	Apr
BRA	44	36	95	100	100	100	85	85	4	80	8,86	8,86		8,9	Apr
DFR	45	29	100	100	90	100	90				6,02	EX	37	7,6	Apr
ERR	39	28	95	30	85	80					5,03	EX	24	5,5	Apr
FFF	15	27	90	100	100	100	g2				4,29	EX	23	5,0	Apr
FG	43	34	95	95	100	100	g1	85	5		7,52	7,52		7,5	Apr
FWA	17	9	95	100	40	100	90	85	5	80	5,24	EX	21	5,2	Apr
GFMC	29	 -	90	100	100	100	g2				2,54	EX		1,3	RepFr
GWC	39	25	95	95	80	100	100	95	5	95	8,01	8,01		8,0	Apr
HSKP	32	16	50	100	95	100	100	100	5	40	6,38	EX	26	6,4	Apr
JC	40	23	90	95	90	100	g1	85	5		6,4	EX	29	6,8	Apr
JFS	30	22	85	100	90	90	80	85	4	85	7,02	7,02		7,0	Apr
JPCRJ	47	37	85	100	95	100	95				6,77	6,77		6,8	Apr
KC	31	20	90	95	100	100	85	85	3	100	7,23	7,23		7,2	Apr
LHCR	32	17	95	95	50	100	g1	g1	5		3,96	EX	19	4,4	Repr
LHM	15	1	95	75							1,29	EX		0,6	Repr
LMD	32	 -	50	75	40	100					2,24	EX		1,1	RepFr
LQC	46	36	95	95	100	100	95	85	3	85	9,02	9,02		9,0	Apr
LZ	42	30	90					80	5		6,01	EX	28	6,5	Apr
MAOJ	43	19	95	95	50	100	90	g1	5	90	5,83	EX	31	6,8	Apr
MAX	50	40	100	100	100	100	100	100	4	100	10	10	40	10,0	Apr
MDG	42	9	95	100	90	100	80				4,12	EX	32	6,1	Apr
ML	18	12	95	95	100	100					3,12	EX		1,6	Repr
MMCV	38	25	95	95	60	100	85	80	5	80	7,43	7,43		7,4	Apr
PD	45	35	90	80	35	70	85	20	3	95	7,97	7,97		8,0	Apr
RAK	31	1	95	95	30	100	70				2,71	EX	16	3,4	Repr
RC	19	2	100	90							1,61	EX		0,8	Repr
RFG	32	 -	85	100	90	100	85	85	3	95	5,43	EX	32	6,7	Apr
RMR	22	17	100	95	30	100	85	85	5		5,26	EX	28	6,1	Apr
RO	15	 -									0,62	EX		0,3	RepFr
VS	45	34	100	100	100	100	85		3	80	7,84	7,84		7,8	Apr
YKS	49	40	95	100	95	100	g2	100	5	100	9,58	9,58		9,6	Apr

A tabela acima, em pdf.

Notas da 1a prova

MAX sempre acerta tudo.
MAX 50
LZ 42
RO 15
RAK 31
JPCRJ 47
YKS 49
PD 45
FFF 15
GWC 39
DFR 45
LQC 46
VS 45
LMD 32
BRA 44
MMCV 38
FG 43
HSKP 32
FWA 17
RMR 22
RFG 32
ADFN 25
MAOJ 43
GFMC 29
ML 18
LHM 15
ERR 39
KC 31
JFS 30
RC 19
LHCR 32
MDG 42
JC 40

Notas da segunda prova

MAX 40
JFS 22
ERR 28
YKS 40
RMR 17
LHM 1
MAOJ 19
VS 34
JC 23
KV 20
GS 25
MDG 9
RC 2
FG 34
FWA 9
ADFN 15
ML 12
FFF 27
BRA 36
HP 16
LHCR 17
LQC 36
LZ 30
MMCV 25
PD 35
RAK 1
JPCRJ 37

Exercícios

  1. Para cada trecho de código em linguagem C abaixo, diga qual o valor das variáveis (todas inteiras) após a execução do trecho. Para verificar a correção da resposta, codifique um programa contendo o trecho em questão e faça um computador executá-lo.
    1.   a = 5;
        b = 7;
        a = a + b;
        b = a + b;
        c = a + b;
        
    2.   a = 5;
        b = 7;
        n = 0;
        while ((a + b) < 42) {
          a = 2 * b;
          b = 2 * a;
          n = n + 1;
        }
        
    3.   a = 5;
        b = 7;
        n = 0;
        while ((a + b) <= 42) {
          a = 2 * b;
          b = 2 * a;
          n = n + 1;
        }
        
    4.   a = 5;
        b = 7;
        n = 0;
        while ((a + b) > 42) {
          a = 2 * b;
          b = 2 * a;
          n = n + 1;
        }
        
  2. Crie um trecho de código que troque os valores das variáveis 'a' e 'b' (se o trecho começa com a valendo 3 e b valendo 5, deve terminar com a valendo 5 e b com o valor 3).
  3. Crie um trecho de código que coloque em a o maior valor entre os valores de a e b, e em b o menor desses valores.
  4. Crie um trecho de código que ordene os valores de três variáveis.
  5. Faça os exercícios propostos na seção 2.12 e 3.8 do livro (http://www.ic.ufal.br/professor/jaime/livros/C.htm).
  6. Faça uma função que recebe um inteiro e retorna um bool que diz se o inteiro é primo ou não. Faça um programa que usa essa função para imprimir todos os números primos menores que um valor fornecido pelo usuário. Declaração: bool primo(int n)
  7. Faça um programa que imprime o maior primo menor que um número fornecido pelo usuário. Use a função do exercício anterior.
  8. Faça uma função para calcular e retornar o fatorial de um número inteiro recebido como parâmetro. Usando essa função determine qual o maior número que pode ter seu fatorial calculado. Repita para os demais tipos inteiros da linguagem. Repita para os tipos de ponto flutuante. Ex. com o tipo char, o valor de 5! é calculado corretamente, mas o valor de 6! não é.
  9. Faça uma função que recebe dois parâmetros, o primeiro um double e o segundo um inteiro, e retorna um double que corresponde ao primeiro parâmetro elevado na segundo-parâmetro-ésima potência (xn). Não é permitido usar a função do sistema que já faz isso (função pow()). Declaração: double potencia(double x, int n)
  10. Faça uma função que calcula o seno de um ângulo. O seno de x (em radianos) pode ser calculado pela série de Taylor:

    sen(x) = x - x3/3! + x5/5! - x7/7! + ...

    Use as funções dos dois exercícios anteriores. O ângulo e o seno devem ser do tipo double. Calcule usando os primeiros 10 termos (na fórmula acima tem os primeiros 4 termos).

  11. Altere a função que calcula o seno do exercício anterior para que receba um segundo argumento, inteiro, que representa o número de termos que se deseja que sejam usados.
  12. Quais os caracteres impressos pelo programa abaixo?

    #include 
    
    
  13. Faça uma função que recebe três nùmeros e retorna o maior.
  14. Suponha que já existe uma função bool primo(int n) que diz se um nùmero é primo. Faça uma função int maiorprimo(char *nome), que recebe o nome de um arquivo contendo um nùmero por linha e retorna o maior nùmero primo existente nesse arquivo.
  15. Qual será o valor retornado pela função abaixo, se for chamada com o valor 25?

      int fun(int n)
      {
        if (n == 0) return 1;
        if (n == 1) return 2;
        return n + fun(n - 2);
      }
    
  16. Qual será o valor retornado pela função abaixo, se for chamada com o valor 25?

      int fun(int n)
      {
        int a = 1;
        if (n == 25) a = a + 2;
        if (n > 25) a = a + 4;
        else a = a + 8;
        return a;
      }
    
  17. Foi proposta a função abaixo para retornar o maior elemento de um vetor de t elementos, a partir da posição i, ou 0 se não existir maior elemento. Ela está correta?

      int maiorvet(int v[], int i, int t)
      {
        int r = 0;
        int a;
        if (i < t) {
          r = v[i];
          a = maiorvet(v, i+1, t);
          if (a > r) {
            a = r;
          }
        }
        return r;
      }
    
  18. A expressão 1+1/3+(1*2)/(3*5)+(1*2*3)/(3*5*7)+(1*2*3*4)/(3*5*7*9)+... tende para PI/2. Implemente uma função que receba um número N, e retorne o valor da soma dos primeiros N termos desta expressão.
  19. Faça uma função que recebe um nùmero positivo e retorna a soma de seus algarismos. Exemplo, para 341 deve retornar 8 (3+4+1).
  20. Faça uma versão recursiva da função anterior, que, caso a soma dos algarismos contenha mais de um algarismo, retorna a soma desses algarismos.

Trabalhos

Primeiro trabalho

(Exercício 12 do capítulo 4 do livro) Faça um programa que determine o n-ésimo termo da sequência de Fibbonaci, dado o valor de n.
A sequência de Fibbonaci é a sequência (1, 1, 2, 3, 5, 8, 13, ...), definida por an = 1, se n=1 ou n=2; an = an-1 + an-2, se n>2.

A entrega do trabalho deve ser feita até o dia 8 de abril, por e-mail enviado para ap2009a@inf.ufsm.br, com um arquivo anexado contendo o código C do programa, com o nome fulano-t1.c, onde "fulano" é o nome de login do aluno nas máquinas do NCC. A primeira linha do programa deve conter um comentário com o nome do aluno e a identificação do trabalho (t1).

Avaliação

Segundo trabalho

Incluindo-se math.h em um programa C (e compilando-se com -lm), tem-se acesso a diversas funções matemáticas da linguagem, entre elas as funções trigonométricas. A função sin() calcula o seno do valor fornecido, que deve ser um ângulo em radianos, do tipo double. O valor calculado do seno também é do tipo double. Faça um programa que imprime uma tabela com o valor do seno e do coseno de cada ângulo entre 0 e 90 graus, calculado com as funções sin() e cos(). A tabela deve ser formatada em 3 colunas de 30 linhas, como exemplificado abaixo (com as '|', '+', '-', cabeçalho, todos os números com o mesmo tamanho (use exatamente o mesmo espaçamento, o teste de correção da saída do programa será a comparação do resultado com um gabarito, por um programa de comparação). A função sin() deve ser chamada em um só local do programa (cos() também). Os valores de seno e coseno na tabela abaixo não estão corretos.

+-----+--------+--------+-----+--------+--------+-----+--------+--------+
| Ang |    sen |    cos | Ang |    sen |    cos | Ang |    sen |    cos |
+-----+--------+--------+-----+--------+--------+-----+--------+--------+
|   1 | 0.0174 | 0.9998 |  31 | 0.5150 | 0.8667 |  61 | 0.8765 | 0.4900 |
|   2 | 0.3455 | 0.3453 |  32 | 0.4323 | 0.2342 |  62 | 0.3254 | 0.3455 |
...mais varios valores...
|  30 | 0.3455 | 0.3453 |  60 | 0.4323 | 0.2342 |  90 | 0.3254 | 0.3455 |
+-----+--------+--------+-----+--------+--------+-----+--------+--------+

Entrega como o anterior (trocando t1 por t2), até 8 de abril + 7 dias.

Avaliação

Terceiro trabalho

Faça um programa para imprimir uma tabela contendo a diferença percentual entre o seno de um ângulo calculado pela função sin() fornecida pelo sistema e o calculado pela função do exercicio 11. Crie (e use) uma função que recebe dois números e retorna a diferenca percentual entre eles (100*(x2-x1)/x1) (x1 é o valor correto, x2 o valor aproximado; para que o valor não seja muito grande para impressão, caso o valor absoluto da diferença seja superior a 10000, a função deve retornar 9999,99). A tabela deve conter um ângulo por linha, e para cada ângulo a diferença entre o seno do sistema e o da série de Taylor calculado com 1, 3, 5, ..., 19 termos. A diferença deve ser impressa com 2 casas após a vírgula; a tabela deve ser bem formatada; a tabela deve conter os ângulos entre 0 e 360 graus, de dez em dez. Deve ter um comentário antes de cada função, dizendo o que ela faz.

Entrega como os anteriores, (8+14)/4.

Avaliação

Quarto trabalho

O arquivo bola.c contém um exemplo de programa usando curses para controlar a tela e o teclado. Tem instruções de como compilar no interior do arquivo. Para quem estiver usando windows, parece que tem uma biblioteca curses (não testei, não sei se funciona) em http://pdcurses.sourceforge.net/. O programa é um joguinho bem simples, com uma bola que tem que ser acertada pelo usuário. As funções desconhecidas são da bibliotecas curses, e estão explicadas mais ou menos em comentários no código. Mais informação sobre as funções do curses pode ser obtida no manual do curses (comando "man ncurses" ou na internet (exemplo, tem um tutorial aqui: http://tldp.org/HOWTO/NCURSES-Programming-HOWTO)), ou por mail. Após entender o programa, o trabalho é alterá-lo. Possibilidades:

Entrega: quarta.

Avaliação

Quinto trabalho

Faça um programa que implemente o jogo descrito a seguir, usando a linguagem C e a biblioteca ncurses, e os conceitos do trabalho anterior. Uma bola pingpongueia na tela (em 2D). A bola ricocheteia nos lados e na parte superior do espaço. A bola não ricocheteia na parte inferior. Se a bola cair pela parte inferior, a bola some e o jogador perde uma vida. Na parte inferior, tem uma raquete, que pode se mover horizontalmente. O movimento da raquete é controlado pelo usuário. Se a bola bater na raquete, ela ricocheteia. Dependendo da posição da raquete onde a bola toca, a velocidade horizontal da bola é alterada: se bater bem na ponta esquerda, soma -1 na velocidade horizontal da bola; se bater na ponta direita, soma 1; se bater em um ponto intermediário, soma um valor intermediário; esse valor pode não ser inteiro. Como a velocidade pode não ser inteira, a posição também pode não ser. Usar tipo float para posiçoes e velocidades (deltas) -- converter para int quando for usar na função de posição do cursor. Para controlar a raquete, o usuário tem 3 teclas, uma para diminuir a velocidade, outra para aumentar e outra para zerar a velocidade da raquete. A velocidade pode ter valores entre -1 e 1, e a alteração deve ser de 0,5 a cada teclada nas teclas de mudança de velocidade. Deve-se manter a posição X da raquete em uma variável, e incrementá-la da velocidade a cada iteração. A raquete deve parar se chegar em um dos lados. Cada ricochete na raquete vale um ponto. O programa deve manter em um arquivo o recorde de pontos. A cada final de partida, o arquivo deve ser atualizado, se o recorde for batido.

Sugestão de algoritmo principal:

   enquanto ainda restarem vidas
     processa teclas (pode mudar velocidade da raquete)
     recalcula posicao da bolinha
     recalcula posicao da raquete
     verifica colisao entre bolinha e raquete (pode mudar vel da bolinha e pontos)
     verifica ricochete da bolinha nas paredes (pode mudar vel da bolinha)
     verifica se bolinha caiu (pode reinicializar tudo, alterar n. de vidas)
     desenha tela
     espera
Cada linha acima pode ser implementada como uma função.

Entrega: sexta.

Sexto trabalho

Incremente o programa do trabalho anterior para conter obstáculos ao movimento da bolinha. Quando bate em um desses obstáculos, a bolinha ricocheteia, o obstáculo é destruído e o jogador ganha pontos. Quando acabarem todos os obstáculos, muda a fase do jogo e o jogador ganha pontos. Deve ser mantido em um arquivo as dez maiores pontuações da história, eventualmente atualizado a cada final de partida. No final da partida, deve ser informado ao jogador, caso a pontuação obtida esteja entre as 10 mais (e em que lugar ficou).

O trabalho pode ser feito em grupo, de no máximo dois alunos. Espera-se que todos os componentes do grupo participem na elaboração do trabalho e compreendam seu funcionamento. Parte da avaliação do trabalho será realizada durante a apresentação. A nota é a mesma para todos os membros do grupo.

Primeira parte
Geometria analítica. Implementar tipos de dados e funções auxiliares geométricas; essas funções deverão ser usadas no resto da implementação do programa. Implementar um programa de teste das funções geométricas.
Tipos de dados
// Um ponto, constituído por uma coordenada no eixo x e no eixo y
typedef struct {
    float x;
    float y;
} ponto_t;

// tamanho_t, constituído por altura e largura, do tipo float
// retangulo_t, constituído por um ponto (que contém as coordenadas do canto 
//              inferior esquerdo do retangulo) e um tamanho
// circulo_t, constituido por um ponto (o centro do circulo) e um float (o raio)
Funções
// retorna a distancia entre dois pontos
float distancia(ponto_t p1, ponto_t p2);
// retorna true se o ponto estiver dentro do circulo, false caso contrario
bool ptemcirc(ponto_t p, circulo_t c);
// retorna true se o ponto estiver dentro do retangulo
bool ptemret(ponto_t p, retangulo_t r);
// retorna true se houver uma interseccao entre o circulo e o retangulo
bool intercr(circulo_t c, retangulo_t r);
// retorna true se houver uma interseccao entre os dois retangulos
bool interrr(retangulo_t r1, retangulo_t r2);
// retorna true se houver uma interseccao entre os dois circulos
bool intercc(circulo_t c1, circulo_t c2);

Dica: Como calcular a interseção entre um círculo e um retângulo (com figura!!).

calcule a distância entre o centro do círculo e do retângulo no eixo x, em valor absoluto (dx).
calcule essa distância no eixo y (dy).
// como as distâncias são em valor absoluto, reduz-se o cálculo a um quadrante
(veja figura -- a região verde é o quadrante do retângulo).

se dx for maior que metade da largura mais o raio, não tem interseção
// [o centro do círculo está na região A na figura]
idem dy  [B].

se dx for menor ou igual a metade da largura, tem interseção [C].
idem dy [D].
// nesse caso, o centro do círculo está dentro do retângulo,
// ou acima ou ao lado a uma distância inferior ao raio.

// se passar pelos testes acima, o centro do círculo está fora do retângulo,
// além do canto, dentro de um quadrado de lado igual ao raio (em branco na fig).
// Tem que saber se a distância entre o centro do círculo e o canto
// do retângulo é menor que o raio, para saber se está dentro.
subtrai metade da largura de dx e metade da altura de dy
// com isso, só sobra em dx e dy a distância para fora do retângulo verde.
calcula a distância ao canto (sqrt(dx*dx + dy*dy));
se for maior que o raio, não tem interseção [E].
tem interseção [F].
Segunda Parte
Desenho geométrico. Essa parte é fornecida. Os arquivos tela.h e tela.c contêm a implementação de funções básicas de entrada e saída em uma janela gráfica em ambiente X-Windows (o sistema de janelas mais usado em sistemas Unix). Além disso, é fornecido o programa teste.c, que permite testar as funções geométricas da primeira parte. Esse programa desenha dois círculos e dois retângulos. Eles devem mudar de cor quando o cursor do mouse estiver sobre eles, se a função de deteção de ponto em círculo ou retângulo estiverem corretas. Com o botão do mouse apertado, as figuras mudam de cor caso tenha uma intersecção com outra das figuras. Ainda com o botão apertado, é possível arrastar as figuras na tela. Para que os tipos de dados da primeira parte sejam compatíveis com esses arquivos, são fornecidos também os arquivos para a primeira parte: geom.h e geom.c (que deve ser preenchido com o corpo das funções). Para compilar:
gcc -o teste teste.c geom.c tela.c -lX11
Se em geom.c for usada alguma função de math.h, acrescentar -lm ao comando acima. Quem for mais aventureiro, pode reimplementar geom.c usando curses.
Terceira Parte
Crie um tipo de dados obstaculo_t, para representar um obstáculo do jogo. Esse tipo de dados é uma estrutura composta por um retângulo e um inteiro com o número de vezes que se deve acertar o obstáculo para ele sumir. Faça uma função void desenha_obstaculo(obstaculo_t obs) que recebe um obstáculo como argumento e desenha-o se ele não sumiu (um obstáculo que sumiu tem o inteiro zerado). No centro do obstáculo deve ser escrito o número de vezes que falta acertá-lo.

Faça uma função void desenha_obstaculos(obstaculo_t *obstaculos, int n) que recebe um vetor de obstáculos e um inteiro com o número de obstáculos nesse vetor e desenha todos eles (usando a função anterior).

Crie um tipo de dados bola_t para representar a bola do jogo. É uma estrutura que contém um círculo e um ponto, que representa o vetor velocidade da bola. Faça uma função void move_bola(bola_t *bola), que recebe um ponteiro para o tipo bola_t e altera a posição da bola, de acordo com sua velocidade. Faça uma função void desenha_bola(bola_t bola), que desenha a bola.

Crie um tipo de dados raquete_t, para representar a raquete do jogo. É composto por um retângulo e um float, que contém a velocidade horizontal da raquete. Faça uma função void move_raquete(raquete_t *raq), que recebe um ponteiro para o tipo raquete_t e altera a posição da raquete, de acordo com sua velocidade. Faça uma função void desenha_raquete(raquete_t r), que desenha a raquete. Faça uma função void altera_velocidade_raquete(raquete_t *raq, int tecla), que altera a velocidade da raquete dependendo da tecla que foi pressionada (ou não faz nada, se a tecla não corresponder a uma tecla de mudança da raquete).

Faça uma função bool bateu_obstaculo(obstaculo_t obs, bola_t bola) que recebe um obstaculo_t e uma bola_t como argumento e retorna true se o obstáculo não está sumido e a bola bateu no obstáculo.

Faça uma função bateu_raquete que recebe um raquete_t e uma bola_t como argumento e retorna true se a bola bateu na raquete.

Crie um tipo de dados jogo_t que contém os dados necessários para representar um jogo (um vetor de obstáculos, uma bola, uma raquete, e o que mais julgar necessário (paredes, fase, pontuação, por exemplo)).

Faça as funções bateu_teto, bateu_parede, bateu_chao que recebem um ponteiro para jogo_t e retornam verdadeiro se a bola bateu em alguma borda do espaço de jogo.

Faça a função ricochete_horizontal que recebe um ponteiro para a bola e inverte a velocidade horizontal dela. Faça a função ricochete_vertical, que recebe um ponteiro para a bola e um valor float, e inverte a velocidade vertical da bola, além de alterar a velocidade horizontal, somando-lhe o valor passado.

Faça uma função void verifica_bordas(jogo_t *jogo), que verifica se a bola bateu em alguma borda (superior ou lateral), e ricocheteia a bola corretamente, caso necessário.

Faça uma função void verifica_raquete(jogo_t *jogo), que verifica se a bola bateu na raquete, e ricocheteia se for o caso. O ricochete altera a velocidade horizontal da bola, dependendo da posição da raquete em que a bola bateu, como no trabalho anterior. (o delta da velocidade corresponde à distância do centro da bola ao centro da raquete dividido por metade da largura da raquete).

Faça uma função void verifica_obstaculos(jogo_t *jogo), que verifica se a bola bateu em algum obstáculo, e ricocheteia a bola, altera a pontuação, diminui a vida do obstáculo, caso tenha batido. Por simplicidade, faça sempre ricochete vertical para colisões com obstáculos.

Faça uma função void inicializa_obstaculos(obstaculos_t obstaculos[], int n, int fase), que recebe um vetor de obstaculos, o numero de elementos no vetor e um número que corresponde à fase do jogo. Essa função deve inicializar os obstáculos para que a fase fase do jogo possa começar.

Faça uma função void desenha_jogo(jogo_t *jogo), que recebe um ponteiro para a estrutura que representa o jogo, e limpa a tela e desenha todo o tabuleiro do jogo (usando as funções de desenho anteriores).

Faça uma função void inicializa_jogo(jogo_t *jogo), que inicializa a estrutura de dados correspondente ao jogo.

Faça uma função void termina_jogo(jogo_t *jogo), que termina o jogo após o final das vidas do jogador. Essa função deve atualizar o registro de recordes, se for necessário.

Faça a função principal do jogo, usando as funções acima, e outras funções que julgue necessário para facilitar a implementação.

Sétimo trabalho

Faça um editor de textos, de acordo com a descrição a seguir. O texto é representado em memória por uma estrutura declarada como segue:
typedef struct {
    char *nome;     // nome do arquivo sendo editado
    char **linhas;  // vetor de strings a ser alocado dinamicamente
    int nlin;       // numero de linhas no texto (numero de elementos atualmente em linhas)
    int lincur;     // linha onde esta o cursor (comeca em 0)
    int colcur;     // coluna onde esta o cursoe na linha acima
    int lin1;       // linha do texto mostrada na primeira linha da tela
    int col1;       // coluna do texto mostrada na primeira coluna da tela
} texto_t;
Funções a implementar (no mínimo):
void le_arquivo(texto_t *txt, char *nome);
Inicializa a estrutura apontada por txt com o conteúdo do arquivo chamado nome. Deve ler o arquivo duas vezes: na primeira leitura, só para contar o número de linhas. Então, aloca memória para o vetor de strings linhas, com espaço para esse número de linhas. Depois, deve ler cada linha do arquivo, alocar memória suficiente para essa linha (sem o '\n' final e com um '\0'), copiar o conteúdo da linha para essa memória alocada e inicializar o ponteiro correspondente no vetor linhas para apontar para a memória alocada. A função deve ainda inicializar os demais campos da estrutura apontada por txt.

Sugestão de algoritmo:

1 calcular o tamanho da maior linha
  (de preferencia enquanto le o arquivo para saber quantas linhas tem), 
2 alocar um espaco auxiliar com tamanho suficiente para que a maior linha
  seja lida com fscanf (nao esquecer do \n e do \0),
3 ler uma linha do arquivo nesse espaco auxiliar, 
  (sabendo que ele vai ser suficiente para conter qualquer linha),
4 alocar espaco suficiente para a linha lida,
5 copiar a linha (menos o \n) do espaco auxiliar para esse novo espaco,
6 colocar esse no vetor de linhas.
7 repetir de 3
8 quando terminar a leitura, liberar o espaco auxiliar.
void move_esq(texto_t *txt);
void move_dir(texto_t *txt);
void move_baixo(texto_t *txt);
void move_cima(texto_t *txt);
Move a posição do cursor na direção indicada pelo nome da função. Para a esquerda, para cima e para baixo, não deve sair dos limites do texto. Para a direita, não há limite.

void insere_char(texto_t *txt, char c);
Insere o caractere c na posição do cursor. Deve alocar uma nova região de memória grande o suficiente para conter a linha após a inserção, e copiar o conteúdo da linha antiga, alterada com a inserção do caractere novo. Caso a linha do cursor seja mais curta que a posição do cursor, devem ser inseridos espaços no final da linha, para que o caractere inserido fique na posição correta. A memória ocupada pela linha antiga deve ser liberada e o ponteiro da linha no vetor linhas alterado para apontar para a nova região de memória com a nova versão da linha. Após a inserção, o cursor deve ser movido uma coluna à direita (usar a função acima).

void remove_char(texto_t *txt);
Remove o caractere na posição do cursor no texto apontado por txt. Como na inserção, deve alocar uma nova área de memória para conter a nova versão da linha. Caso o cursor esteja além do final da linha, a função não deve fazer nada. A posição do cursor não deve ser alterada.

void ajeita_tela(texto_t *txt);
Se necessário, deve alterar a primeira coluna e/ou linha do texto mostrado na tela (variáveis lin1 e col1), para garantir que a posição do cursor seja mostrada quando a tela for desenhada (a linha do cursor não pode ser menor que a primeira linha na tela (lin1) nem maior que a última linha na tela (lin1 + altura da tela - 1); idem para coluna).

void desenha_tela(texto_t *txt);
Desenha toda a tela. A primeira linha a ser desenhada é lin1. A primeira coluna a ser desenhada em cada linha é col1.

void gruda_linha(texto_t *txt);
Se o cursor não estiver na última linha do texto, anexa a linha seguinte à do cursor ao final da linha do cursor, e remove a linha abaixo do cursor. Para remover a linha, liberar a memória ocupada pela linha, alocar um novo vetor de linhas com uma posição a menos que o atual, copiar os ponteiros do vetor de linhas atual para o novo (pulando a linha removida), liberar a memória do vetor anterior, colocar o valor do novo vetor no ponteiro linhas.

void quebra_linha(texto_t *txt);
Quebra a linha do cursor na posição do cursor. A linha com o cursor terminará com o caractere logo antes do cursor, e a linha seguinte conterá os caracteres a partir da posição do cursor. Se o cursor estiver além do final da linha, a linha do cursor permanece inalterada e é inserida uma linha vazia após o cursor. Deve ser realocada a memória para a linha do cursor (se ela mudar) e liberada a memória antiga, alocada memória para a nova linha, realocado o vetor de linhas para conter a nova linha.

O programa principal deve ler o arquivo, e ficar em um laço:

    desenha a tela
    lê um caractere
    chama uma das funções de edição, dependendo do caractere
    ajeita a posição do primeiro caractere
Até que seja digitado um caractere para gravar o arquivo, quando o programa grava-o (se o usuário confirmar) e finaliza.

Dúvidas? Mail para ap2009a@inf.ufsm.br ou durante as aulas.

etc

Comandos C vistos em aula até agora

;
comando nulo — não faz nada.
nome = expressão;
comando de atribuição — calcula o valor de expressão e armazena o resultado na variável chamada nome. Caso o tipo do valor calculado seja diferente do tipo da variável, o valor é convertido para esse tipo antes de ser armazenado.
{ comandos }
bloco — define uma sequência de comandos que será executada em ordem; serve para agrupar comandos. Pode ser usado em qualquer lugar onde um comando pode ser usado. Geralmente são usados nos comandos controlados pelos comandos compostos, descritos abaixo. Além de comandos, um bloco pode conter a declaração de novas variáveis, que só existem durante a execução do bloco.
if ( expressão ) comando
execução condicional — calcula o valor de expressão e, caso esse valor seja verdadeiro, executa comando. Se o valor da expressão for falso, o comando não será executado.
if ( expressão ) comando1 else comando2
execução condicional — calcula o valor de expressão e, caso esse valor seja verdadeiro, executa comando1. Se o valor da expressão for falso, será executado comando2.
switch ( expressão ) { case valor1: comandos case valor2: comandos [...] [default: comandos]opcional }
seleção — calcula o valor de expressão. Se esse valor coincidir com algum dos valores marcados por cláusulas case, começa a executar os comandos contidos no switch nesse ponto. Se nenhum desses valores concidir e existir uma cláusula default, começa a executar nesse ponto. Caso contrário, não executa nenhum dos comandos controlados pelo switch. Os comandos após as cláusulas case ou default são opcionais (podem existir duas ou mais cláusulas case sem comandos entre elas; nesse caso, qualquer dos valores associados a essas cláusulas causa o início da execução no mesmo ponto). Caso seja executado o comando break;, o comando switch termina. Geralmente existe um comando break; no final de cada grupo de comandos marcado por uma cláusula case.
while ( expressão ) comando
repetição — calcula o valor de expressão e, caso esse valor seja verdadeiro, executa comando e repete (iniciando pelo re-cálculo da expressão). Se o valor da expressão for falso, o while termina. Se o valor da expressão for falso na primeira vez, o comando não será executado nenhuma vez.
do comando while ( expressão );
repetição — executa comando; calcula o valor de expressão e, caso esse valor seja verdadeiro, repete (iniciando pela re-execução do comando). Se o valor da expressão for falso, o do-while termina. O comando será executado pelo menos uma vez, mesmo se o valor da expressão for falso na primeira vez.
for ( expressão1; expressão2; expressão3 ) comando
repetição — calcula expressão1 (geralmente uma atribuição que inicializa uma variável de controle da repetição). Calcula expressão2 (geralmente um teste para saber se a variável de controle chegou a seu valor final). Se o valor for falso, termina a execução do comando for. Executa comando (geralmente um bloco). Calcula expressão3 (geralmente uma alteração no valor da variável de controle). Repete a partir do cálculo de expressão2. As três expressões são opcionais. O valor da segunda expressão é considerado verdadeiro caso a expressão não exista.

Nos comandos de repetição podem ser usados dois comandos adicionais: break;, que interrompe o comando de repetição quando executado, e continue;, que interrompe a sequência de comandos controlados pelo comando de repetição e continua com as repetições como se o último comando do laço tivesse sido executado.

Tipos de dados C vistos até agora em aula

Tipos Básicos
bool
booleano, pode armazenar um valor lógico. Os únicos valores possíveis para um dado desse tipo são verdadeiro ou falso, representados pelas palavras true e false. Para poder usar esse tipo de dados, deve-se usar #include <stdbool.h>.
char, short int, int, long int, long long int
inteiro, pode armazenar um número inteiro. Existem vários tipos de dados inteiros, para representar diversas precisões (na lista, os tipos estão em ordem não decrescente de tamanho, geralmente ocupando 1, 2, 4 ou 8 bytes). A palavra int é opcional (exceto no tipo composto somente por essa palavra). Esses tipos podem ser precedidos por signed ou unsigned, para se precisar se se quer representar valores com sinal ou sem sinal (números que não são negativos). A gama de valores representáveis por variáveis desse tipo depende do tamanho e do uso de sinal. Com 32 bits, pode representar valores entre -231 e 231-1 (aproximadamente 2 bilhões), quando usado com sinal e entre 0 e 232-1 (aproximadamente 4 bilhões) quando usado sem sinal.
enum
um tipo que enumera todos os valores que uma variável desse tipo pode ter. Cada valor tem um nome, explicitado na declaração.
exemplo:
	enum { seg, ter, qua, qui, sex, sab, dom } dia;
	dia = seg;
	dia ++; /* agora dia vale ter */
	if (dia == qua) sofa();
	
float, double, long double
ponto (ou vírgula) flutuante, pode armazenar um número real aproximado. Em máquinas atuais, floats ocupam 32 bits e doubles ocupam 64 bits. A gama de valores representáveis em 32 bits é de aproximadamente ±10±38, com 7 dígitos decimais de precisão (isso quer dizer que ele não diferencia 90000000 de 89999999 ou 3,1415926 de 3,1415925). Com 64 bits, consegue-se aproximadamente 16 dígitos decimais e expoentes decimais até aproximadamente 308.
Tipos compostos
Vetores
Um vetor agrupa sob uma mesma variável vários valores de um mesmo tipo. O acesso a cada um desse valores dá-se por posição, desde a posição 0, que representa o primeiro elemento do vetor até a posição N-1, para um vetor com N elementos.
Declaração:
	tipo nome[num_elem];
	
tipo é o tipo de cada elemento do vetor, pode ser um tipo qualquer de dado C; nome é o nome da variável; num_elem é o número de elementos que o vetor irá conter (um valor inteiro).
Uso: Um elemento do vetor é acessado com o nome do vetor e, entre colchetes, o índice ou posição do elemento desejado. Exemplo:
	int v[3];  // declara v como um vetor de 3 inteiros
	v[0] = 12; // coloca o valor 12 no primeiro elemento do vetor
	printf("%d", v[2]); // imprime o último elemento do vetor v
	

Um vetor, quando passado como argumento para uma função, é passado por referência, ao contrário de todos os demais tipos da linguagem C, que são passados por valor. Isso quer dizer que, se a função alterar algum dos elementos do vetor recebido, estará alterando o vetor original passado como argumento, e não uma cópia local da função. Na declaração do vetor como argumento da função, pode ser usado uma notação que omite o número de elementod dentro dos colchetes, o que quer dizer que a função não sabe o número de elementos do vetor recebido.
Registros
Um registro agrupa em uma mesma variável vários valores, que podem ser de tipos distintos. Cada valor é chamado de campo do registro, e é referenciado por um nome. Na linguagem C, os registros são também chamados de estruturas.
Declaração:
	struct {
	    tipo1 nomecampo1;
	    tipo2 nomecampo2;
	    ...
	} nome;
        
nome é o nome da variável registro; nomecampoi é o nome de cada campo desse registro; tipoi é o tipo de cada campo do registro.

Para representar o acesso ao campo de nome c do registro contido na variável de nome r, usa-se em C a notação r.c (separa-se o nome da variável do nome do campo por um ponto). Exemplo:

	struct {
	    int matricula;
	    float nota;
	} aluno; // declara a variável aluno, que contém os campos matrivula e nota

	aluno.matricula = 8310845;  // atribui um valor ao campo matricula da variavel aluno
	aluno.nota = 5.3;  // atribui um valor ao campo nota
	printf("a nota é: %f\n", aluno.nota); // imprime o valor de um campo
	
Ponteiros
Uma variável do tipo ponteiro pode conter um valor que representa a posição em que um determinado dado se encontra, na memória do computador. Diz-se que o ponteiro aponta ou referencia esse dado. A posição de memória é também chamada de endereço. O dado para o qual o ponteiro aponta tem um tipo, que é chamado o tipo do ponteiro. Quando se tem um ponteiro para um dado de tipo desconhecido, ou quer-se simplesmente registrar o endereço de memória, em C usa-se ponteiro para o tipo void.

Declaração:

	tipo *nome;
	
Declara nome como sendo uma variável do tipo ponteiro para um dado de tipo tipo. Para acessar o dado apontado pelo ponteiro, usa-se a notação *nome. Essa operação chama-se dereferenciação. Para acessar o próprio ponteiro, usa-se, como em qualquer outro tipo de dado, somente o nome da variável. O valor NULL representa um local da memória normalmente usado quando se quer fazer com que um ponteiro aponte para um local inválido. Nunca se deve dereferenciar um ponteiro não inicializado ou que aponte para NULL ou que aponte para um local não alocado da memória (para uma variável ativa do programa ou para uma área de memória alocada dinamicamente e ainda não liberada).

Exemplo:

	int a;  // declara uma variável inteira chamada a
	int b;  // outra, chamada b
	int *p; // declara um ponteiro para inteiro, chamado p
	int *q;

	p = &a; // faz o ponteiro p receber o valor do endereco de a
	        // (em outras palavras, faz p apontar para a)
	*p = 3; // armazena 3 no valor apontado por p (altera o valor de a)
	a += *p; // soma o valor apontado por p em a
	b = *q; // erro, q nao foi inicializado. Esse erro pode nao ser detectado
	        // pelo compilador, e pode nao ser detectado durante a execucao.
	

Operadores vistos em aula

aritméticos
as 4 operações (+, -, *, /), resto de divisão inteira (%). São operadores binários (um operando de cada lado); operam dados de mesmo tipo e tamanho, produzindo resultado do mesmo tipo dos operandos. Caso os operandos não sejam do mesmo tamanho, converte o "menor" para o "maior" antes de realizar a operação. Os operandos de multiplicação têm precedência sobre os de soma. A precedência pode ser forçada com o uso de parênteses. Tem ainda o operador unário de negação (-), que calcula o valor negativo do operando a sua direita.
de comparação
operadores binários que comparam valores aritméticos de mesmo tipo e produz um valor lógico. Realiza conversões de tipo semelhantes aos operadores aritméticos em caso de comparação de tipos diferentes. São 6 (<, >, >=, <=, ==, !=).
lógicos
operadores binários que operam sobre dois operandos booleanos e produzem um resultado booleano. Operador "e" (&&), cujo resultado é verdadeiro quando os dois operandos são verdadeiros e falso quando algum é falso. Operador "ou" (||), cujo resultado é verdadeiro quando algum operando é verdadeiro e falso quando ambos são falsos. Operador unário de negação (!), que inverte o seu operando.
bit a bit
Operadores com operandos inteiros e resultado inteiro, que realizam uma operação binária sobre cada dois bits na mesma posição em cada operando. Operadores: "e" (&), "ou" (|), "ou exclusivo" (^), operador unário que inverte os bits (~). Operadores de deslocamento: >> e << têm dois argumentos inteiros, e o resultado é o deslocamento do valor esquerdo tantos bits quanto for o valor direito. O deslocamento dos bits pode ser à esquerda ou à direita, dependendo do operador.
operadores de atribuição
operadores que alteram o valor do operando esquerdo, que obrigatoriamente deve ser uma variável. O valor resultante do operador é o valor atribuido. O valor a direita do operador tem seu tipo convertido para o tipo da variável a esquerda antes que o operador atue. Atribuição simples (=); atribuição com operação (+=, -=, *=, /=, |=, <<=, etc.); incremento/decremento (++, --) -- esses operadores são unários e têm o valor da variável antes do incremento (com o operador após a variável) ou depois do incremento (quando o operador estiver antes da variável). Não deve existir mais de uma atribuição a mesma variável no mesmo comando.
Exemplo:
	int a, b;
	a = 5;
	b = a++;  /* a vale 6, b vale 5 */
	a = ++b;  /* b vale 6; a vale 6 */
	a += ++b; /* b vale 7; a vale 13 */
	
operador de dereferência de ponteiros
operador unário *, usado à esquerda de um ponteiro, para acessar o valor apontado pelo ponteiro. Se o ponteiro apontar para um dado do tipo registro, e se quer acessar um dos campos desse registro, existe o operador ->. Não se pode usar o operador de dereferência com ponteiros para void.

Exemplos:

	int a;
	int *p;
	struct { int x, int y; int *z} b, c, *q;
	p = &a;
	q = &b;
	*p = 10;  // atribui 10 a variavel a
	*q = c;   // atribui a estrutura apontada por q o valor da estrutura c
	b.x = a;  // atribui 10 ao campo x de b
	*q.x = a; // erro (. tem precedencia sobre * e q não é uma estrutura nem x um ponteiro)
        (*q).y = a; // atribui ao campo y de b o valor de a
	q->y = a; // notacao alternativa, identico a linha anterior
	b.z = &a; // atribui ao campo z de b o endereco de a
	b.y++;
	*(q->z) = q->y + 5; // que valor é atribuído a que variável?
	
operadores de aritmética de ponteiros
os operadores de soma e subtração (+, -, ++, --, +=, -=) podem ser usados em ponteiros. Um ponteiro pode ser somado com (ou subtraído de) um valor inteiro. O resultado da soma considera que a memória próxima ao endereço do ponteiro é preenchida por dados do mesmo tipo do ponteiro, colocados contiguamente. O resultado da soma corresponde ao deslocamento do ponteiro tantos desses dados quanto for o valor somado ao ponteiro. Por exemplo, se p é um ponteiro para um inteiro, p+1 é um ponteiro para o próximo inteiro colocado logo após o inteiro apontado por p, e p+10 é um ponteiro para o décimo inteiro após. Se um inteiro ocupa 4 bytes de memória, p+1 soma 4 ao valor de p. Dois ponteiros do mesmo tipo podem ser subtraídos, quando estiverem apontando para a mesma região de memória, que contém vários dados do mesmo tipo. Nesse caso, o resultado da subtração é um inteiro, que corresponde ao número de dados (do tipo dos ponteiros) que cabem entre os dois endereços. Ponteiros para void não podem ser usados em operações aritméticas.
outros operadores
O operador condicional ternário ?: tem uma expressão antes da interrogação e uma de cada lado do sinal de dois pontos. A primeira expressão é avaliada. Caso seja considerada verdadeira (diferente de zero), a segunda expressão é avaliada, e é o resultado da operação. Se a primeira expressão for falsa, a terceira expressão é avaliada, e é o resultado. Exemplo:
	c = a>b ? a : b; 
atribui a c o maior valor entre a e b.

O operador vírgula (,) avalia a expressão à esquerda da vírgula, ignora o valor e avalia a expressão à direita da vírgula, que é o valor da operação.

O operador unário sizeof tem um valor que corresponde ao tamanho em bytes do dado ou tipo de dado à sua direita.

Procure por "precedência de operadores C" na internet para encontrar uma tabela com a precedência de todos esses operadores, e sua associatividade. De posse dessa tabela, indentifique o que faz e a ordem em que os operadores serão calculados, na expressão abaixo.
     a*b+*p.x*d
Para que a soma fosse realizada antes das multiplicações, onde deveria ser colocado parênteses?

Alocação dinâmica de memória

Por vezes, um programador não sabe de antemão a quantidade de dados que seu programa deverá manter em memória para processar corretamente. Por exemplo, programas que devem manter em memória para processamento dados contidos em um arquivo, de tamanho desconhecido (um editor de textos, por exemplo). Como declarar variáveis para conter esses dados? Uma forma de solucionar esse problema é declarar variáveis com um determinado tamanho, razoavelmente grande, e, caso esse tamanho mostre-se insuficiente em tempo de execução, informar ao usuário dessa limitação e abortar a execução. Essa solução, apesar de não ser incomum, tem dois fortes inconvenientes: o programa tem um limite artificial ao volume da dados máximo que suporta, e impõe uma carga também artificial, quando está processando um volume de dados bem inferior a esse limite.

Uma outra solução é o programa alocar memória do sistema dinamicamente (durante sua execução), conforme constate a necessidade. Dessa forma, o programa utilizará somente a memória necessária para o processamento que irá realizar, e poderá processar um volume de dados somente limitado pela capacidade de memória do sistema.

A biblioteca padrão da linguagem C contém um conjunto de funções que permitem que um programa realize a alocação e liberação de regiões de memória. As principais funções são malloc() e free().

Exemplo de alocação dinâmica de memória.

Funções

Declaração
tipo nome(lista de parâmetros);

A lista de parâmetros é composta do tipo e nome de cada parâmetro, separados por virgula. Caso a função não seja parametrizada, a lista vazia é indicada por void. Caso a função não tenha valor de retorno, o tipo da função é void.

Definição
A definição de una função é formada por uma declaração sem o ";" seguida por um bloco, que contém o corpo da função (declarações de variáveis locais a função e comandos da mesma).
Chamada
A chamada a uma função é composta pelo nome da função a ser chamada seguido pela lista de argumentos entre parênteses, separados por virgula. Quando executado, o comando de chamada de função cria as variáveis locais da função, atribui os valores dos argumentos da função chamadora aos parâmetros da função chamada e executa os comandos da função. Quando a função chamada terminar sua execução, suas variáveis locais são destruidas e seu valor de retorno substitui o ponto de chamada da função chamadora.

Indentação

Programas de computador são muito mais lidos que escritos. É importante que um programa seja facilmente legível por um humano. A indentação, a inclusão de comentários, a escolha de nomes adequados torna essa tarefa mais fácil. Além disso, a legibilidade é um dos pontos avaliados nos trabalhos da disciplina. É mais fácil entender a segunda versão abaixo do mesmo programa (para o compilador ambas oferecem a mesma dificuldade, e ambos geram o mesmo programa executável).

O segredo da indentação é saber o nível do comando: cada chave ou comando controlador (if, while, for...) faz com que os comandos subordinados estejam em um nível a mais que o comando que os controla. A indentação de um comando corresponde ao seu nível. A quantidade de indentação entre um nível e o seguinte é sempre a mesma, geralmente 2, 4 ou 8 caracteres. Além disso, geralmente se usa espaços para facilitar a leitura. Um espaço antes de "{", um espaço após ",", ";", ":", um espaço antes de operadores unários, um espaço de cada lado de operadores binários.

int main(
){
int a,
b
,c,d;
printf("Entre com dois valores");                   
scanf("%d%d",&a ,&b);
if(a>b){
c=a;
d=c*c;}else
{c=b;d=c*c;}
printf("o maior valor é %d\n",c);
printf("o quadrado é %d\n",d);}
/* Este programa calcula o quadrado
 * do maior valor digitado.
 */
int main()
{
  int a, b;
  int maior, quadrado;
  
  printf("Entre com dois valores");
  scanf("%d%d", &a, &b);

  if ( a > b ) {
    maior = a;
    quadrado = maior * maior;
  } else {
    maior = b;
    quadrado = maior * maior;
  }

  printf("o maior valor é %d\n", c);
  printf("o quadrado é %d\n", d);
}

FAQ

> mas queria se posível uma breve explicação destes warnings que não entendi o
> motivo.
> 1)
> t7.c:52: aviso: implicit declaration of function ?malloc?
> t7.c:52: aviso: incompatible implicit declaration of built-in function
> ?malloc?
declaracao implicita quer dizer que a primeira vez que o compilador viu a funcao
foi em um uso e nao em uma declaracao. Ele entao declara a funcao implicitamente
como recebendo qualquer coisa e retornando inteiro.
a funcao malloc esta declarada no stdlib.h, que deve ser incluido no
teu programa.
o compilador gcc tem a funcao malloc como uma funcao interna (built-in), por
isso o segundo aviso.

> t7.c:52: aviso: assignment from incompatible pointer type
> txt->linhas=(char*)malloc(cont);
> para eu botei o tipo para ser convertido, por que o aviso?
o valor retornado foi convertido para char *, ok. e esse char * esta
sendo atribuido para
a variavel linhas. so que linhas e char **, que e um tipo incompativel
com char *,
por isso o aviso.

>
> 2)
> t7.c:57: aviso: passing argument 3 of ?fgets? from incompatible pointer type
> fgets(linleitura,maiorlin,txt->nome);
> txt->nome não aponta pro FILE*?
como esta declarado o txt->nome? nao e uma string, contendo o nome do arquivo?

>
> 3)
> t7.c:107: aviso: implicit declaration of function ?free?
> free(linhavelha);
> o argumento é um ponteiro para uma string recisa passar com &?
declaracao implicita, ver 1

>
>
> 4)
> t7.c:206: aviso: assignment makes pointer from integer without a cast
>   linha1=vetorlin[txt->lincur]; // Passa linha1 para outra variavel
nao sei o que e o vetorlin, mas o erro fala que estas transformando um
inteiro em um ponteiro na
atribuicao. isso quer dizer que linha1 deve ser um ponteiro, e
vetorlin deve ser um vetor de inteiros.

>
>
> 5)
> t7.c:212: aviso: passing argument 2 of ?strcpy? makes pointer from integer
> without a cast
>   strcpy(lingrud,vetorlin[txt->lincur]); // Copia a primeira linha para a
> nova linha
mesmo problema que 4, vetorlin[] deve ser int, e strcpy quer um char *

>
> t7.c:247: aviso: passing argument 1 of ?memcpy? makes pointer from integer
> without a cast
> t7.c:247: aviso: passing argument 2 of ?memcpy? makes pointer from integer
> without a cast
>     memcpy(novaslinhas[txt->lincur+2],vetorlin[txt->lincur+1],txt->nlin -
> txt->lincur); // Copia linhas nao alteradas para vetor
mesma coisa que antes

>
> nas funções strcpy e memcpy não é possivel passar vetores?
ambas esperam ponteiros. um vetor pode ser tratado como um ponteiro,
mas o elemento de
um vetor pode ser de qquer tipo. cada elemento de um vetor de inteiros
e um inteiro, por exemplo.

>
>
> 6)   FILE* slv;
> t7.c:279: aviso: passing argument 2 of ?rename? from incompatible pointer
> type
>   rename(txt->nome,slv);
rename troca o nome de um arquivo. os argumentos sao o nome antigo e o
novo nome, ambos
string.

>
> t7.c:284: aviso: passing argument 1 of ?remove? from incompatible pointer
> type
>   remove(slv);
remove recebe o nome do arquivo a remover, uma string.

>
>
> 7)
> t7.c:282: aviso: passing argument 2 of ?fputs? from incompatible pointer
> type
>     fputs(txt->linhas[i],txt->nome);

o segundo argumento de fputs e uma referencia a um arquivo aberto
(FILE *), nao o nome do arquivo.

>
> 8)
> t7.c:305: aviso: implicit declaration of function ?exit?
> t7.c:305: aviso: incompatible implicit declaration of built-in function
> ?exit?
>     exit(1);
declaracao implicita. exit() esta declarado no stdlib.h

>
> 9)
> t7.c:341: aviso: comparison is always false due to limited range of data
> type
>     if (tecla==KEY_*)

comparacao e sempre falsa devido a gama limitada de valores do tipo de dados.
e um caso como o de EOF, que tem um valor nao representavel em char.
declara tecla com int.