Aula Prática #05 - Mooshak, Strings e Apontadores

English Version


Mooshak: Exercícios para Submissão

Para efeitos de nota atribuída à resolução de exercícios ao longo do semestre, os exercícios que pode submeter desta aula são os seguintes exercícios, que fazem parte do conjunto de exercícios das últimas duas aulas práticas:

Prazo de submissão: DD de Abril (submeter no Mooshak de Programação Imperativa)

É encorajado que falem com os docentes e outros colegas se tiverem dificuldades. No entanto, qualquer ajuda mais direta que tenham recebido de outros colegas deve ser reconhecida nos comentários do programa que submetem.
Depois do prazo os problemas continuarão disponíveis no Mooshak, mas as submissões não contarão para a sua nota.
Cada aula vale 10% da nota desta componente.
Para um problema contar tem de acertar todos os testes (ou seja, ter accepted). Mesmo que resolva todos os problemas, o máximo numa aula é de 100%.
Para ter 100% bastará sempre resolver os exercícios principais.


Exercício 1) Entendendo Apontadores

  1. Sejam i uma variável inteira e p e q apontadores para inteiros. Indique quais das seguintes atribuições são corretas.
    1. p = i;
    2. *p = i;
    3. p = &q;
    4. p = &i;
    5. &i = p;
    6. p = q;
    7. p = *q;
    8. *p = q;
    9. *p = *q;

  2. Sejam i uma variável int e p um apontador para i. Indique quais das seguintes instruções de leitura e escrita são corretas.
    1. printf("%d",i);
    2. scanf("%d",i);
    3. scanf("%d",&i);
    4. printf("%d",p);
    5. printf("%d",*p);
    6. scanf("%d",p);
    7. printf("%p",p);
    8. printf("%p",i);
    9. printf("%p",*p);

  3. Suponha que as seguintes declarações estão em execução:
    int a[] = {5, 15, 34, 54, 14, 2, 52, 72}; 
    int *p = &a[1], *q = &a [5] ;
    1. Qual é o valor de *(p+3)?
    2. Qual é o valor de *(q-3)
    3. Qual é o valor de q - p
    4. A condição p < q é verdadeira ou falsa?
    5. A condição *p < *q é verdadeira ou falsa?

  4. Suponha que high, low e middle são todas variáveis apontadores do mesmo tipo, e que low e high apontam para elementos de um array. Corrija a declaração seguinte que, tal como está, não está correta.
    middle = (low + high) / 2;

  5. Reescreva a função seguinte para usar a aritmética de apontadores em vez de indices de arrays. Por outras palavras, elimine a variável i e todos os usos do operador []. Faça o mínimo de alterações possível.
    void storezeros(int a[], int n){
      int i ;
    
      for (i = 0; i < n; i++)
        a[i] = 0 ;
    }
    

  6. Na aula prática anterior foi-lhe pedido que escrevesse um programa para escrever uma Matriz Identidade Invertida, tendo para isso usado 2 ciclos encadeados para percorrer os elementos da matriz. Reescreva esse código de modo a escrever como output a Matriz Identidade (em vez da invertida) fazendo uso de apenas um apontador para percorrer os elementos da matriz.

    Sugestão: Como não vamos usar variáveis indexadas (indíces de linha e de coluna), não será fácil dizer onde colocar 1. Em vez disso, podemos utilizar o facto de que o primeiro elemento da matriz deve ser 1; os N elementos seguintes devem ser 0; o elemento seguinte deve ser 1; e assim por diante. Utilize uma variável para saber quantos 0's consecutivos foram armazenados: quando a contagem atingir N, é altura de colocar 1.

  7. Reescreva a função seguinte para utilizar aritmética de apontadores em vez de indices para a matriz. Use um único ciclo em vez de ciclos encadeados.
    int sumTwoDimensionalArray(const int a[][LEN], int n) {
      int i, j, sum = 0;
    
      for (i = 0 ; i < n; i++) 
        for (j = 0; j < LEN; j++) 
          sum += a[i][j];
    
      return sum;
    }
    

  8. Implemente uma função com a seguinte declaração:
    void decompose(int totalSegs, int *horas, int *mins, int *segs);
    Dado um valor totalSegs com o total de segundos, a função decompõe este avor em horas, minutos (0-59) e segundos (0-59); os resultados devem ser atribuídos ao conteúdo dos apontadores horas, mins e segs. Pode assumir que o total de segundos é maior que zero.

  9. Implemente uma função com a seguinte declaração:
    void twoLargest(int vec[], int size, int *pmax1, int *pmax2);
    Dado uma sequência de valores inteiros representada pelo array vec[] com tamanho size, a função deve determinar os dois maiores valores da sequência; os resultados devem ser atribuídos às posições apontadas por pmax1 e pmax2. Pode assumir que size é sempre maior que um.

  10. Considere a função apresentada na aula teórica para inverter a ordem de caracteres de uma cadeia. Pretende-se que escreva uma versão alternativa desta função usando apontadores em vez de índices. A função dever ter a declaração seguinte:
    void reverse(char *str);

  11. Escreva uma função para procurar um caracter numa string, usando apontadores. A função dever ter a declaração seguinte:
    char *occursAt(char *str, char ch);
    O resultado deve ser um apontador para a primeira ocorrência do caracter ch (se este ocorrer) ou NULL caso contrário.


Exercício 2) Mais Problemas com Apontadores e Strings

  1. Implemente a função pré-definida na biblioteca strings.h do C:
    char *strcat(char s1[], char s2[]);
    que concatena a string s2 a s1 e retorna o endereço da primeira string.

  2. Implemente a função pré-definida na biblioteca strings.h do C:
    char *strcpy (char *dest, char source[]);
    que copia a string source para a string dest e retorna o valor desta última.

  3. Implemente a função pré-definidana biblioteca strings.h do C:
    int strcmp(char s1[], char s2[]);
    que compara (lexicograficamente) duas strings. O resultado da função deverá ser o seguinte:
    • 0 se as strings forem iguais (s1 = s2);
    • um valor menor que 0 se s1 < s2;
    • um valor maior que 0 se s1 > s2.

  4. Implemente a função pré-definida na biblioteca strings.h do C:
    char *strstr(char s1[], char s2[]);
    que determina a posição onde a string s2 ocorre na string s1. A função deverá retornar NULL caso s2 não ocorra em s1.

  5. Implemente uma função
    void truncW(char text[], int n);
    em que a string text é composta por múltiplas palavras (as palavras estão separadas por um ou mais espaços) e um inteiro n, a função trunca todas as palavras de forma a terem no máximo n caracteres.

    Exemplo:
    char text[] = "universidade, faculdade e fraternidade";
    truncW(text, 4);  // text deverá ser "univ facu e frat"
    
    Nota: a palavra "e" tem apenas 1 caracter (1 < 4) e por isso permanece igual (isto é, não é truncada).

  6. Implemente uma função com a seguinte declaração:
    int remConsecutives(char s[]);
    em que dada uma string s, a função remove todos os carateres repetidos, produzind uma substring da string original em que os caracteres são todos diferentes.

    Exemplo:
    int result = remConsecutives("aabcccaac"); // result deverá ser 3, correspondente à substring "abc"
    

  7. Implemente uma função com a seguinte declaração:
    int triSup(int N, float m[N][N]);
    que verifique se uma dada matriz quadrada é triangular superior, i.e., se todos os elementos abaixo da diagonal são zeros.

  8. Uma forma de representar conjuntos de índices consiste em usar um array de inteiros contendo 1 ou 0 consoante esse índice pertença ou não ao conjunto. Assim o conjunto {1, 4, 7} seria representado por um array em que as primeiras 8 posições conteriam a seguinte sequência de 1's e 0's: {0,1,0,0,1,0,0,1}.

    1. Implemente uma função int unionSet(int N, int v1[N], int v2[N], int res[N]) que coloca no array res o resultado da união dos conjuntos v1 e v2.

    2. Implemente uma função int intersectSet(int N, int v1[N], int v2[N], int res[N]) que coloca no array res o resultado da intersecção dos conjuntos v1 e v2.