Tarefa 4 - Falando como o Cebolinha

Falando como o Cebolinha

O Cebolinha é um menino muito esperto, mas tem dificuldades de dicção. O seu problema é que toda vez que uma palavra tem um erre (R), ou dois erres (RR), ele o troca por um ele.

Queremos escrever um programa para saber como o Cebolinha falaria uma palavra.

Entrada

A entrada é uma única palavra que pode ou não conter erres e está escrita em caixa alta.

CHURRASQUEIRO

Saída

A palavra como Cebolinha falaria.

CHULASQUEILO

Implementando

Strings em C

O tratamento de strings em C é muito diferente do tratamento de strings em Python. O motivo disso é que C é uma linguagem de nível mais baixo do que Python e não tem um tipo primitivo de string. Em Python, existe um tipo str e todas as dificuldades de lidar com strings são escondidas pelo interpretador. Antes de começarmos nossa tarefa, vamos fazer um exercício diferente: verificar se uma palavra é igual ao seu inverso, isso é, se uma palavra é um palíndromo. Em Python alguém poderia escrever

palavra = input()
inverso = palavra[::-1]
if palavra == inverso:
    print("É palíndromo")
else:
    print("Não é palíndromo")

A expressão palavra[::-1] parece meio mágica, mas é apenas uma conveniência de Python: ela diz para copiar toda a string, mas andando -1 caractere por vez, isso é, copie o último, depois o penúltimo, depois o antepenúltimo etc. Poderíamos escrever nossa própria função que faz isso:

def copiar_inverso(palavra):
    inverso = ""
    i = len(palavra) - 1 # índice da última letra
    while i >= 0:
        inverso = inverso + palavra[i] # concatena a i-ésima letra de palavra
        i = i - 1
    return inverso

palavra = input()
inverso = copiar_inverso(palavra)
if palavra == inverso:
    print("É palíndromo")
else:
    print("Não é palíndromo")

Se em C não há um tipo para strings, então como representá-las? A resposta é usarmos um vetor de caracteres, isso é, um vetor de char. Aqui descobrimos a primeira diferença fundamental: como é o caso de todo vetor estático, em C uma string deve ter um tamanho máximo permitido. Vamos começar lendo uma string e escrevendo-a de volta.

#include <stdio.h>

#define MAX_PALAVRA 10

int main() {
    char palavra[MAX_PALAVRA];
    char inverso[MAX_PALAVRA];

    scanf("%s", palavra);
    printf("Você escreveu %s\n", palavra);
}

Para ler uma palavra do teclado, usamos scanf("%s", palavra); o trecho %s indica para a função scanf que ela deve ler uma palavra do teclado que não contém espaços e guardá-la no vetor palavra. Repare que nesse caso não usamos o símbolo &.

Descobrindo o tamanho da string

Se você se lembra da tarefa de vetores, deve recordar que guardávamos o número n de posições utilizadas juntamente com cada vetor. Esse não é o caso do código acima, então como sabemos quantas letras realmente foram lidas e guardadas no vetor palavra por scanf? Como saber qual é a última posição utilizada do vetor palavra?

A resposta é que scanf copia um caractere especial '\0' depois do último caractere lido. Assim, se a palavra lida é CASA, então o vetor terá a seguinte forma

 índice:   [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
          +---+---+---+---+---+---+---+---+---+---+
palavra:  | C | A | S | A |\0 | ? | ? | ? | ? | ? |
          +---+---+---+---+---+---+---+---+---+---+

As posições marcadas com ? não estão inicializadas, então elas podem conter qualquer valor. Repare que, como gastamos uma posição com o '\0', a maior palavra que cabe nesse vetor tem tamanho 9 caracteres.

Para descobrir o tamanho de uma string, podemos usar a função strlen da biblioteca padrão de funções em C. Para usar essa função precisamos incluir o arquivo string.h no topo do arquivo. Mas tudo o que essa função faz é contar quantos caracteres há antes do '\0'. Assim, se quisermos, podemos construir nossa própria função que calcula o comprimento de uma string.

int comprimento_str(char string[]) {
    int comprimento = 0;
    while (string[comprimento] != '\0') {
        comprimento += 1;
    }
    return comprimento;
}

Obtendo o inverso

Uma consequência de usar o caractere '\0' para finalizar toda string é que, se quisermos escrever funções que devolvem uma string, então nós também devemos adicionar um '\0' no final da string criada. Lembre-se de que como uma string é um vetor, se quisermos criar ou alterar uma string por uma função, então devemos passá-la por parâmetro. Na implmentação em C de nossa função copiar_inverso, iremos fazer as duas coisas.

void copiar_inverso(char palavra[], char inverso[]) {
    int i, j;
    i = comprimento_str(palavra) - 1;  /* índice da última letra de palavra */
    j = 0;                             /* índice da primeira posição de inverso */
    while (i >= 0) {
        /* copia a i-ésima letra de palavra para a j-ésima posição de inverso */
        inverso[j] = palavra[i];
        i = i - 1;
        j = j + 1;
    }
    /* adicionamos o '\0' para indicar que a string inverso terminou */
    inverso[j] = '\0';
}

Comparando duas strings

Agora que já sabemos ler uma palavra e construir o inverso, basta comparar essas duas strings para saber se palavra é um palíndromo. Embora seja tentador escrever palavra == inverso, como faríamos em Python, esse trecho não vai funcionar em C! A razão é que uma string em C é um vetor e, portanto, está restrita a todas as limitações de um vetor: não podemos comparar dois vetores diretamente.

De novo, podemos escrever uma nova função que recebe duas strings, verifica se elas têm o mesmo tamanho e, se tiver, compara cada uma das suas posições. Ao invés de fazermos tudo isso, dessa vez vamos usar a função strcmp da biblioteca string.h. Para usarmos essa função, fazemos uma chamada strcmp(palavra1, palavra2) que irá devolver um número inteiro

Juntando tudo, podemos escrever um programa.

#include <stdio.h>
#include <string.h>

#define MAX_PALAVRA 20

/* funções comprimento_str e copiar_inverso */

int main() {
    char palavra[MAX_PALAVRA];
    char inverso[MAX_PALAVRA];

    scanf("%s", palavra);
    copiar_inverso(palavra, inverso);
    if (strcmp(palavra, inverso) == 0) /* se as strings são iguais */
        printf("É palíndromo\n");
    else
        printf("Não é palíndromo\n");
}

Resolvendo o exercício

Finalmente podemos voltar ao nosso problema inicial: trocar os erres por eles. Devemos prestar atenção em uma sutileza: se uma palavra tiver dois erres (RR) colados, então queremos substituí-los por um único ele (L).

Em Python, poderíamos escrever:

def copiar_cebolinha(palavra):
    i = 0 # índice da letra em palavra
    ultima_eh_erre = False # indica se a última letra copiada foi R
    palavra_modificada = "" # string a ser devolvida

    for i in range(len(palavra)):
        letra = palavra[i]
        if letra == 'R':
            if not ultima_eh_erre:
                palavra_modificada += 'L'
            ultima_eh_erre = True
        else:
            palavra_modificada += letra
            ultima_eh_erre = False

    return palavra_modificada

palavra = input()
palavra_modificada = copiar_cebolinha(palavra)
print(palavra_modificada)

Observe que a variável ultima_eh_erre é do tipo bool. Em C, não há um tipo booleano. Para saber como representar um valor booleano em C, veja o exemplo abaixo. Resolva agora a tarefa em C. Você pode começar modificando o código do palíndromo disponível em Falando como o Cebolinha.

Exemplos relacionados

Na linguagem C, ao invés de usarmos um tipo dedicado a valores booleanos, utilizamos um inteiro como se fosse um valor booleano e adotamos a seguinte convenção: uma variável declarada como int valor_booleano; é interpretada como:

O código a seguir verifica se um número é primo (muito lentamente).

#include <stdio.h>

int eh_primo(int n) {
    int i;

    for (i = 2; i < n; i++) {
        if (n % i == 0)
            return 0; /* devolve falso */
    }

    return 1; /* devolve verdadeiro */
}

int main() {
    int n;

    scanf("%d", &n);
    if (eh_primo(n)) {
        printf("%d é primo\n", n);
    } else {
        printf("%d NÃO é primo\n", n);
    }
}