4

So I am trying to create the complement of the sequence TGAGACTTCAGGCTCCTGGGCAACGTGCTGGTCTGTGTGC however my output didn't work as expected. The complements for each letter in the sequence are
A -> T
G -> C
C -> G
T -> A

I've been programming in Java for over a year now so I've gotten really rusty with pointers in C++, I'm guessing the problem lies in the reverse methods and the way to pointers are shifted around through each pass of the function call

#include<stdio.h>
#include<iostream>
using namespace std;

void reverse(char s[]);

int main() {
    char s[40] = {'T','G','A','G','A','C','T','T','C','A','G','G','C','T','C','C','T','G','G','G','C','A','A','C','G','T','G','C','T','G','G','T','C','T','G','T','G','T','G'};

    cout << "DNA sequence: "<< endl << s << endl;

    reverse(s);

    cout << "Reverse Compliment: "<< endl << s << endl;



    system("pause");
}

void reverse(char s[])
{
    char c;
    char *p, *q;

    p = s;

    if (!p)
        return;

    q = p + 1;
    if (*q == '\0')
        return;

    c = *p;
    reverse(q);

    switch(c) {
        case 'A':
            *p = 'T';
            break;
        case 'G':
            *p = 'C';
            break;
        case 'C':
            *p = 'G';
            break;
        case 'T':
            *p = 'A';
            break;  
    }
    while (*q != '\0') {
        *p = *q;
        p++;
        q++;
    }

    *p = c;

    return;
}
Ryan Fung
  • 2,069
  • 9
  • 38
  • 60
Juan Battini
  • 115
  • 3
  • 14
  • Did you check the maping logic? Is it correct? *hins* – Ryan Fung Oct 12 '15 at 06:34
  • 1
    Why making your life harder by using raw `char` arrays instead of `std::string`? – πάντα ῥεῖ Oct 12 '15 at 06:35
  • Hint: The output is exactly the reversed string. Could it be that you're somehow overwriting the "complemented" value? – molbdnilo Oct 12 '15 at 06:56
  • You call `reverse` inside `reverse` method. Do you really want your algorithm to be recursive or a `for` loop would be OK too? – Lukáš Bednařík Oct 12 '15 at 07:21
  • 2
    Rusty with pointers? That's actually a good thing, You should almost never use pointers in a C++ program. Certainly not in this one. – n. m. could be an AI Oct 12 '15 at 07:26
  • I should have mentioned this is a homework problem ... and it calls specifically for char arrays and use of pointers to traverse the array – Juan Battini Oct 12 '15 at 20:57
  • Is this a C++ course or general programming/algorithms course? – n. m. could be an AI Mar 02 '17 at 07:44
  • @n.m. this was a intro to programming class that my wife was taking, and she had asked me to give her a hand since she's not much of a programmer herself lol – Juan Battini Mar 31 '17 at 23:32
  • Beware! For anyone looking to _reverse-complement_ a DNA sequence, some answers below only output the _complement_. Order of conversion can be: seq->comp->rev (TTGC->AACG->GCAA) or seq->rev->comp (TTGC->CGTT->GCAA). [http://reverse-complement.com/](http://reverse-complement.com/) – flyingfinger Oct 28 '20 at 23:12

3 Answers3

6

Standard modern C++ makes this low-level, pointer-oriented programming, unnecessary (in fact, you're effectively writing C).

Once you have a function, say complement, which transforms a nucleotide to its complement, you just need to apply some standard library function like transform.

Here is a rewrite of your program in C++11:

#include <string>
#include <iostream>                                                                                                                                                                                          
#include <algorithm>
#include <cassert>


using namespace std;


char complement(char n)
{   
    switch(n)
    {   
    case 'A':
        return 'T';
    case 'T':
        return 'A';
    case 'G':
        return 'C';
    case 'C':
        return 'G';
    }   
    assert(false);
    return ' ';
}   


int main() 
{   
    string nucs = "ACAATTGGA";
    transform(
        begin(nucs),
        end(nucs),
        begin(nucs),
        complement);
    cout << nucs << endl;
}   
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
2

std::string style, looks easy and clean: I presume it may be useful to OP or others.

creating complement of DNA sequence and reversing it C++

In other words, it is reverse complement of a DNA sequence, which can be easily achieved by reversing the DNA sequence and then getting its complement. Or getting the complement and then reversing. An example is shown below.

#include <iostream>
#include <string>
#include <algorithm>

int main()
{
    std::string DNAseq = "TGAGACTTCAGGCTCCTGGGCAACGTGCTGGTCTGTGTGC";
    reverse(DNAseq.begin(), DNAseq.end());
    for (std::size_t i = 0; i < DNAseq.length(); ++i){
        switch (DNAseq[i]){
        case 'A':
            DNAseq[i] = 'T';
            break;    
        case 'C':
            DNAseq[i] = 'G';
            break;
        case 'G':
            DNAseq[i] = 'C';
            break;
        case 'T':
            DNAseq[i] = 'A';
            break;
        }
    }
    std::cout << "reverse complement : " << DNAseq << std::endl;
    return 0;
}
Community
  • 1
  • 1
Agaz Wani
  • 5,514
  • 8
  • 42
  • 62
1

Change the reverse method like this

void reverse(char s[])
{
    while (*s) {
        switch(*s) {
        case 'A':
            *s = 'T';
            break;
        case 'G':
            *s = 'C';
            break;
        case 'C':
            *s = 'G';
            break;
        case 'T':
            *s = 'A';
            break;  
        }
        ++s;
    }
    return;
}

...and you will get correct result.

If you don't like pointers, please, don't use them! In modern C++ pointers aren't often necessary. The following code is C++11 (do you have C++11 compiler?) written as I would do it.

#include <string>
#include <iostream>
#include <algorithm>

std::string reverse(std::string seq)
{
    auto lambda = [](const char c) {
        switch (c) {
        case 'A':
            return 'T';
        case 'G':
            return 'C';
        case 'C':
            return 'G';
        case 'T':
            return 'A';
        default:
            throw std::domain_error("Invalid nucleotide.");
        }
    };

    std::transform(seq.cbegin(), seq.cend(), seq.begin(), lambda);
    return seq;
}


int main()
{
    std::string seq("TGAGACTTCAGGCTCCTGGGCAACGTGCTGGTCTGTGTG");
    std::cout << "DNA sequence: " << std::endl << seq << std::endl;
    seq = reverse(seq);
    std::cout << "Reverse Compliment: " << std::endl << seq << std::endl;
    system("pause");
    return EXIT_SUCCESS;
}

Some notes:

  1. Use default in switch statement.
  2. In C++ it's better to return a value from a function than to manipulate a variable via pointer.
  3. Prefer std::string to plain char.
Lukáš Bednařík
  • 2,578
  • 2
  • 15
  • 30