Lab 5: Herança
Você pode colaborar com um ou dois colegas de classe neste laboratório, embora seja esperado que todos os alunos em qualquer grupo contribuam igualmente para o trabalho.
Simule a herança de tipos sanguíneos para cada membro de uma família.
$ ./inheritance
Child (Generation 0): blood type OO
Parent (Generation 1): blood type AO
Grandparent (Generation 2): blood type OA
Grandparent (Generation 2): blood type BO
Parent (Generation 1): blood type OB
Grandparent (Generation 2): blood type AO
Grandparent (Generation 2): blood type BO
Contexto
O tipo sanguíneo de uma pessoa é determinado por dois alelos (ou seja, formas diferentes de um gene). Os três alelos possíveis são A, B e O, dos quais cada pessoa possui dois (possivelmente os mesmos, possivelmente diferentes). Cada um dos pais de uma criança passa aleatoriamente um de seus dois alelos do tipo sanguíneo para a criança. As possíveis combinações de tipos sanguíneos são: OO, OA, OB, AO, AA, AB, BO, BA e BB.
Por exemplo, se um dos pais tem tipo sanguíneo AO e o outro tem tipo sanguíneo BB, então os possíveis tipos sanguíneos da criança seriam AB e OB, dependendo de qual alelo é recebido de cada pai. Da mesma forma, se um dos pais tem tipo sanguíneo AO e o outro OB, então os possíveis tipos sanguíneos da criança são AO, OB, AB e OO.
Começando
Abra o VS Code.
Comece clicando dentro da janela do terminal e, em seguida, execute cd
por si só. Você deve encontrar que seu "prompt" se
assemelha ao abaixo.
$
Clique dentro dessa janela de terminal e execute
wget https://cdn.cs50.net/2022/fall/labs/5/inheritance.zip
digite Enter para baixar um arquivo ZIP chamado inheritance.zip
em seu espaço de códigos. Tenha cuidado para
não ignorar o espaço entre wget
e a URL seguinte, ou
qualquer outro caractere!
Agora execute
unzip inheritance.zip
para criar uma pasta chamada inheritance
. Você não precisa
mais do arquivo ZIP, então pode executar
rm inheritance.zip
e responda com "y" seguido de Enter no prompt para remover o arquivo ZIP que você baixou.
Agora digite
cd inheritance
seguido de Enter para entrar (ou seja, abrir) nesse diretório. Seu prompt agora deve se parecer com o abaixo.
inheritance/ $
Se tudo foi bem sucedido, você deve executar
ls
e você deve ver o arquivo inheritance.c
.
Se você encontrar algum problema, siga os mesmos passos novamente e veja se consegue determinar onde errou!
Entendendo
Dê uma olhada no código de distribuição em inheritance.c
.
Observe a definição de um tipo chamado person
. Cada pessoa possui um array de dois parents
, cada um dos quais é um ponteiro para outra struct person
. Cada pessoa também possui um array de dois alleles
, cada um dos quais é um char
(ou seja, 'A'
, 'B'
ou 'O'
).
Agora, dê uma olhada na função main
. A função começa por "seeding" (ou seja, fornecendo algumas entradas iniciais para) um gerador de números aleatórios, que usaremos posteriormente para gerar alelos aleatórios. A função main
então chama a função create_family
para simular a criação de structs person
para uma família de 3 gerações (ou seja, uma pessoa, seus pais e seus avós). Então chamamos print_family
para imprimir cada um desses membros da família e seus tipos sanguíneos. Finalmente, a função chama free_family
para liberar
qualquer memória que foi previamente alocada com malloc
.
As funções create_family
e free_family
são deixadas para você escrever!
Detalhes de Implementação
Complete a implementação de inheritance.c
, de modo a criar uma família de tamanho de geração especificado e atribuir alelos de tipo sanguíneo a cada membro da família. A geração mais antiga terá alelos atribuídos aleatoriamente a eles.
- A função
create_family
recebe um inteiro (generations
) como entrada e deve alocar (como viamalloc
) uma estruturaperson
para cada membro da família com o número de gerações especificado, retornando um ponteiro para operson
na geração mais nova.- Por exemplo,
create_family(3)
deve retornar um ponteiro para uma pessoa com dois pais, onde cada pai também tem dois pais. - Cada
person
deve ter seusalelos
atribuídos a eles. A geração mais antiga deve ter alelos escolhidos aleatoriamente (como chamando a funçãorandom_allele
), e as gerações mais jovens devem herdar um alelo (escolhido aleatoriamente) de cada pai. - Cada
person
deve ter seusparents
atribuídos a eles. A geração mais antiga deve ter ambos osparents
definidos comoNULL
, e as gerações mais jovens devem terparents
sendo um array de dois ponteiros, cada um apontando para um pai diferente.
- Por exemplo,
Nós dividimos a função create_family
em algumas tarefas TODO
para você completar.
- Primeiramente, você deve alocar memória para uma nova pessoa. Lembre-se de que você pode usar
malloc
para alocar memória esizeof(person)
para obter o número de bytes a serem alocados. - Em seguida, incluímos uma condição para verificar se
generations > 1
.- Se
generations > 1
, então há mais gerações que ainda precisam ser alocadas. Já criamos dois novosparents
,parent0
eparent1
, chamando recursivamentecreate_family
. Sua funçãocreate_family
deve, então, definir os ponteiros dos pais para a nova pessoa que você criou. Finalmente, atribua ambos osalleles
para a nova pessoa escolhendo aleatoriamente umallele
de cada pai. - Caso contrário (se
generations == 1
), não haverá dados de pais para essa pessoa. Ambos osparents
da nova pessoa devem ser definidos comoNULL
e cadaallele
deve ser gerado aleatoriamente.
- Se
- Por fim, sua função deve retornar um ponteiro para a
person
que foi alocada.
A função free_family
deve receber como entrada um ponteiro para uma pessoa
, liberar a memória para essa pessoa e, em seguida, recursivamente liberar a memória para todos os seus ancestrais.
- Como essa é uma função recursiva, você deve primeiro lidar com o caso base. Se a entrada da função for
NULL
, não há nada para liberar, então a função pode retornar imediatamente. - Caso contrário, você deve recursivamente
liberar
ambos os pais da pessoa antes deliberar
a criança.
Dicas
- Você pode achar a função
rand()
útil para atribuir aleatoriamente alelos. Esta função retorna um número inteiro entre0
eRAND_MAX
, ou2147483647
.- Em particular, para gerar um número pseudorandom que é
0
ou1
, você pode usar a expressãorand() % 2
.
- Em particular, para gerar um número pseudorandom que é
- Lembre-se de que, para alocar memória para uma pessoa específica, podemos usar o
malloc(n)
, que recebe um tamanho como argumento e alocarán
bytes de memória. - Lembre-se de que, para acessar uma variável por meio de um ponteiro, podemos usar a notação de seta.
- Por exemplo, se
p
é um ponteiro para uma pessoa, então um ponteiro para o primeiro pai desta pessoa pode ser acessado porp->parents[0]
.
- Por exemplo, se
Como Testar Seu Código
Ao executar ./inheritance
, o seu programa deve aderir às regras descritas no contexto. A criança deve ter dois alelos, um de cada pai. Os pais devem ter cada um dois alelos, um de cada um dos seus pais.
Por exemplo, no exemplo abaixo, a criança na Geração 0 recebeu um alelo O de ambos os pais da Geração 1. O primeiro pai recebeu um alelo A do primeiro avô e um alelo O do segundo avô. Da mesma forma, o segundo pai recebeu um alelo O e um alelo B de seus avós.
$ ./inheritance
Child (Generation 0): blood type OO
Parent (Generation 1): blood type AO
Grandparent (Generation 2): blood type OA
Grandparent (Generation 2): blood type BO
Parent (Generation 1): blood type OB
Grandparent (Generation 2): blood type AO
Grandparent (Generation 2): blood type BO
Execute o comando abaixo para avaliar a correção do seu código usando o check50
. Mas certifique-se de compilar e testar o código você mesmo também!
check50 cs50/labs/2023/x/inheritance
Execute o código abaixo para avaliar o estilo do seu código usando style50
.
style50 inheritance.c
Como enviar
No seu terminal, execute o seguinte para enviar seu trabalho.
submit50 cs50/labs/2023/x/inheritance