簡體   English   中英

在 C 中反轉 DNA 字符串時意外的 output 字符 p

[英]unintended output character p when reversing a DNA string in C

預期的 output 是首先反轉整個 DNA 字符串,然后轉換 A <-> T,C <-> G。但是,在實際的 output 中,第一個出現的字符是“但是 output 字符串的 rest 很好。 這是代碼:

int main() {
    
    const char dna[] = "GATCACAGGTCTATCACCCTATTAACCACTCACGGGAGCTCTCCATGCAT"
                       "TTGGTATTTTCGTCTGGGGGGTGTGCACGCGATAGCATTGCGAGACGCTG"
                       "GAGCCGGAGCACCCTATGTCGCAGTATCTGTCTTTGATTCCTGCCTCATT"
                       "CTATTATTTATCGCACCTACGTTCAATATTACAGGCGAACATACCTACTA"
                       "AAGTGTGTTAATTAATTAATGCTTGTAGGACATAATAATAACAATTGAAT";

    int dna_len = strlen(dna);

    char rev_comp[dna_len+1];   
    char temp = '\0'; 
    char temp_dna[dna_len+1]; 

    for (int i = 0; i < dna_len + 1; i++) {
        temp_dna[i] = dna[dna_len - i];
        if (temp_dna[i] == 'A') {
            temp = 'T';
            rev_comp[i] = temp;
        }
        else if (temp_dna[i] == 'T') {
            temp = 'A';
            rev_comp[i] = temp;
        }
        else if (temp_dna[i] == 'C') {
            temp = 'G';
            rev_comp[i] = temp;
        }
        else if (temp_dna[i] == 'G') {
            temp = 'C';
            rev_comp[i] = temp;
        }
    }

    rev_comp[dna_len+1] = '\0'; 

    printf("original: %s\n", dna);
    printf("rev_comp: %s\n", rev_comp);

    return 0;
}

您的循環錯誤並循環到dna_len ( null 終止符所在的位置)。 它應該是:

for (int i = 0; i < dna_len; i++) {     // corrected loop
    temp_dna[i] = dna[dna_len - i - 1]; // corrected calculation

此外,rev_comp 中的最終 null 終止rev_comp應分配在索引dna_len ,而不是dna_len + 1 - 這超出了范圍,因此您的程序具有未定義的行為 打印p未定義行為的一種可能結果。

rev_comp[dna_len] = '\0';

演示

您創建了一個小助手 function 來在開始交換字符串中的字符之前進行反轉。

void rev(const char *in, size_t len, char *out) {
    for(size_t i = 0; i < len; ++i) {
        out[len - i - 1] = in[i];
    }
    out[len] = '\0';
}

並調用它

rev(dna, dna_len, rev_comp);

在交換字母之前:

for (int i = 0; i < dna_len; i++) {
    char *ch = &rev_comp[dna_len - i - 1];
    switch(*ch) {
        case 'A': *ch = 'T'; break;
        case 'T': *ch = 'A'; break;
        case 'G': *ch = 'C'; break;
        case 'C': *ch = 'G'; break;
    }
}

演示

@TedLyngmo 已經指出了您原始代碼中的索引錯誤,但您可能要考慮的另一個考慮因素是考慮能夠重用您稍后在其他程序中編寫的一些代碼。 與其為您編寫的每個單獨程序一遍又一遍地編寫專門的代碼,不如識別您可能希望在另一個程序中再次使用的代碼的公共部分,並為該部分代碼創建一個簡短的 function 使這成為可能。

您可能需要在此程序中多次反轉字符串,因此編寫一個可重用的 function 來反轉您可以在任何需要的地方使用的字符串是有意義的。 根據您的職業道路,您可能還需要轉換A <-> TC <-> G ,而不是在這個程序中,因此簡短的 function 也可能有意義。

警告:如果需要最高效率(處理數十億個字符串),那么結合這些操作並利用對 DNA 序列字符串的單次迭代是有意義的。 通過從字符串的每一端向中間工作,您可以在每次迭代中處理兩個字符,從而將所需的迭代次數減少一半。

要為每個字符串的反轉和轉換制作可重用的 function,您可以編寫如下函數。 字符串反轉 function 顯示了如何從每一端向中間工作,因為字符串有字符,所以只需要一半的迭代次數:

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

/* reverse src in dest copying 2-characters per-iteration. */
void strrev (char *dest, const char *src)
{
  size_t begin = 0, end = strlen(src);  /* begin and 1-past-end indexes */
  
  dest[end--] = 0;                      /* nul-terminate dest */
  
  if (end < 1)                          /* if less than 2 chars, return */
    return;
  
  do {
    dest[begin] = src[end];             /* end to begin */
    dest[end] = src[begin];             /* begin to end */
  } while (--end > ++begin);            /* increment & test */
}

/* transform A <-> T, C <-> G */
void xformATCG (char *s)
{
  do {
    if (*s == 'A')
      *s = 'T';
    else if (*s == 'T')
      *s = 'A';
    else if (*s == 'C')
      *s = 'G';
    else if (*s == 'G')
      *s = 'C';
  } while (*++s);
}

如果您願意,您可以編寫一個簡單的打印 function ,它將以特定數量的字符打破 output 的長行,類似於您在初始化dna[]時顯示的方式。 對於它的價值,您可以添加:

/* simple print with break at brk chars function */
void prnwbrk (const char *s, size_t brk)
{
  size_t n = 0;                       /* counter */
  
  while (s[n]) {                      /* loop until end-of-string */
    if (n && n % brk == 0)            /* if brk chars, output \n */
      putchar ('\n');
    putchar (s[n++]);                 /* output char */
  }
  
  putchar ('\n');                     /* final \n */
}

現在反轉和轉換字符串只需在main()中調用strrev()xformATCG() ) 即可。 您可以在每個操作之間檢查每個步驟(這使得調試更容易)。 一個簡短的main()可能是:

int main (void) {
    
  const char dna[] =  "GATCACAGGTCTATCACCCTATTAACCACTCACGGGAGCTCTCCATGCAT"
                      "TTGGTATTTTCGTCTGGGGGGTGTGCACGCGATAGCATTGCGAGACGCTG"
                      "GAGCCGGAGCACCCTATGTCGCAGTATCTGTCTTTGATTCCTGCCTCATT"
                      "CTATTATTTATCGCACCTACGTTCAATATTACAGGCGAACATACCTACTA"
                      "AAGTGTGTTAATTAATTAATGCTTGTAGGACATAATAATAACAATTGAAT";
  char rev_comp[sizeof dna];
  
  prnwbrk (dna, 50);            /* print original dna */
  putchar ('\n');
  
  strrev (rev_comp, dna);       /* reverse and print */
  prnwbrk (rev_comp, 50);
  putchar ('\n');
  
  xformATCG (rev_comp);         /* transform chars and print */
  prnwbrk (rev_comp, 50);
}

示例使用/輸出

如果我正確理解了您的問題和操作,則反轉和轉換后的字符串將如下所示:

$ ./bin/revdna
GATCACAGGTCTATCACCCTATTAACCACTCACGGGAGCTCTCCATGCAT
TTGGTATTTTCGTCTGGGGGGTGTGCACGCGATAGCATTGCGAGACGCTG
GAGCCGGAGCACCCTATGTCGCAGTATCTGTCTTTGATTCCTGCCTCATT
CTATTATTTATCGCACCTACGTTCAATATTACAGGCGAACATACCTACTA
AAGTGTGTTAATTAATTAATGCTTGTAGGACATAATAATAACAATTGAAT

TAAGTTAACAATAATAATACAGGATGTTCGTAATTAATTAATTGTGTGAA
ATCATCCATACAAGCGGACATTATAACTTGCATCCACGCTATTTATTATC
TTACTCCGTCCTTAGTTTCTGTCTATGACGCTGTATCCCACGAGGCCGAG
GTCGCAGAGCGTTACGATAGCGCACGTGTGGGGGGTCTGCTTTTATGGTT
TACGTACCTCTCGAGGGCACTCACCAATTATCCCACTATCTGGACACTAG

ATTCAATTGTTATTATTATGTCCTACAAGCATTAATTAATTAACACACTT
TAGTAGGTATGTTCGCCTGTAATATTGAACGTAGGTGCGATAAATAATAG
AATGAGGCAGGAATCAAAGACAGATACTGCGACATAGGGTGCTCCGGCTC
CAGCGTCTCGCAATGCTATCGCGTGCACACCCCCCAGACGAAAATACCAA
ATGCATGGAGAGCTCCCGTGAGTGGTTAATAGGGTGATAGACCTGTGATC

main()中做這一切並沒有錯,但提前思考可以避免每次你需要在另一個程序中做同樣的事情時重新發明輪子。 (此外,編寫和調試一次 function 可防止以后重新發明 function 時出現新錯誤)

如果您還有其他問題,請仔細查看並告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM