This question is part of a series solving the Rosalind challenges. For the previous question in this series, see Calculating protein mass ruby. The repository with all my up-to-date solutions so far can be found here.
I started the Rosalind challenges roughly a year ago in Ruby. Now I got curious whether I could do the same challenges in C.
Problem: DNA
A string is simply an ordered collection of symbols selected from some alphabet and formed into a word; the length of a string is the number of symbols that it contains. An example of a length 21 DNA string (whose alphabet contains the symbols 'A', 'C', 'G', and 'T') is "ATGCTTCAGAAAGGTCTTACG."
Given:
A DNA string
s
of length at most 1000 nt.Return:
Four integers (separated by spaces) counting the respective number of times that the symbols 'A', 'C', 'G', and 'T' occur in
s
.Sample Dataset:
AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC
Sample Output:
20 12 17 21
Actual Dataset:
CTCCTCAGATCTCAAACGGCTCTATATTACTAGATAGGAGACACGCCCATACCAGCGACGCGGGGTCACTCATTTTCCCAAGAATCCATGAGTGCGAAGCGCACGTCCATGTGACACAAAATTACTAGAGAGTTTTCAAGTCTGATTACCCGTAGTAAACGACCTTGTGCCGGGTCACTAGTGCAATGAAGAATATGTCAACTATTACTCCCGTGGGATCTATAAAACCAGAAGATCCATTGCACTTGTAGTCGCTGTATAGTCTCTCGTCGTCACCTAGCCGATATGACCGTGCGCGAGTTATCCGGAACCTATAAGTGTTTGCTCTCAACAGTGTCTCAACACATGGAGTCGGTAACCTACTACGAAGCCTGCACCAAGATCGATCAGGGAGAATACCCCCTGACGGTCAACGCCGAAGATCAAAGAGAATGATTCGGCCTAGGGCGATTGGCTATTATCCCGGTCTAACCGCCAGGATACTTCAGTAGATCCCGCTCGACATCTGCCCCCCACAAAGTTATTCAGTTTCGGTGATAATTTCGCTTGAACTCCTATCTATTTAAAAGTTTTCCTATACGATGACTAGTCCCTTGCGAACGATCTTTGCCAGGATGCACGACGGCGAGACAATATTACAATACCGAGTGGAGTGATTGGTATCTACACATACGAAATCTCAATGAGAATGGAAGGTCACACTCGTAACAAACTCCTAAGCGGCGGAGAGCGGAAAGGTATAGTCGAGTCGAAGCCTTTATATCGTGTGGCCAGCAGCTAACACAGAGAAATATGGCGGGAATCATC
Actual output:
231 201 181 194
DNA.c:
#include "DNA.h"
int main()
{
size_t MAX_LENGTH = 1000;
char *user_input;
user_input = (char *) malloc (MAX_LENGTH + 1);
getline (&user_input, &MAX_LENGTH, stdin);
output(countACGT(user_input));
}
DNA.h:
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
uint8_t A;
uint8_t C;
uint8_t G;
uint8_t T;
} uint8_t_container;
uint8_t_container countACGT(char *nucleotide)
{
uint16_t len = strlen(nucleotide);
char nucleobase;
uint8_t_container *count = calloc(4, sizeof(uint8_t_container));
for(uint16_t i = 0; i < len; i++)
{
nucleobase = nucleotide[i];
if isalnum(nucleobase)
{
if (nucleobase == 'A')
{
count->A += 1;
}
else if (nucleobase == 'C')
{
count->C += 1;
}
else if (nucleobase == 'G')
{
count->G += 1;
}
else if (nucleobase == 'T')
{
count->T += 1;
}
}
}
return *count;
}
void output(uint8_t_container result)
{
printf("%i %i %i %i\n", result.A, result.C, result.G, result.T);
}
Explanation:
I prepare the user_input
which will contain the nucleotide
. The nucleotide
(basically an array of nucleobase
s) will be iterated over. If the input is alphanumeric it will get checked for it's value and the appropriate member value of count
(a container of uint8_t
) will be increased by one. While the challenge only provides sanitized input data, this should further decrease the likelihood of useless data wreaking havoc. At the end, the container will be retrieved and read. The \n
in the printf
statement is not required but keeps my terminal sane.
My typing and naming can probably be improved and I'm sure I missed some obvious optimizations. An earlier version used an array inside uint8_t_container
, but I decided this probably looked better. Feel free to prove me wrong.
The last time I've written a decent amount of C is a while ago, so I'm especially looking for things that may bite me in the behind when done in production. Alternative solutions are only useful as part of a review or won't be of use. I'm perfectly aware this isn't the most straightforward method of solving the challenge, but I was going for modularity.
Compiled using:
gcc -Wall -Wextra -pedantic DNA.c -o DNA.out
As far as I know that should give me pretty much all warnings available.