打印文件中所有字符串的k-mer

时间:2019-05-01 15:46:45

标签: c substring

我有一个包含字符串列表的文件。我尝试生成所有这些k-mer。这是我的代码:

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

char* substr(const char *string, size_t start, size_t end) {

  const char *char_start = &string[start];
  const char *char_end = &string[end];

  char *substring = (char *) calloc(1, char_end - char_start + 1);
  memcpy(substring, char_start, char_end - char_start + 1);

  return substring;
}

int main(void) {
  FILE *file;
  file = fopen("out/clean_read_1.txt", "r");
  if (file == NULL) {
    perror("File not found!\n");
    exit(0);
  } 

  char *line = NULL;
  size_t i, len = 0, k = 5;
  ssize_t read;

  while ( (read = getline(&line, &len, file)) != -1 ) {
    for ( i = 0; i < strlen(line) - k; i++ )
      printf("%s\n", substr(line, i, i + k - 1));
  }

  printf("\n");

  fclose(file);

  return 0;
}

这是文件:

ACCAG
CAGTGAA
TGAACGGTA

我不明白为什么代码不生成最后一个k-mer。

预期正确的输出:

ACCAG
CAGTG
AGTGA
GTGAA
TGAAC
GAACG
AACGG
ACGGT
CGGTA

我的代码输出不正确:

ACCAG
CAGTG
AGTGA
GTGAA
TGAAC
GAACG
AACGG
ACGGT

1 个答案:

答案 0 :(得分:1)

我注意到您文件中除最后一行外的每一行都以'\n'结尾。由于getline()还将\n写入line(在文件中找到时),因此strlen(line)总是比该行中可见字符的数量多一个,因为它不包含'\n',所以在处理最后一行时除外。

例如,使用文件的倒数第二行时,line将包含"CAGTGAA\n\0"。不计算结尾的'\0',它们是7个字母字符+ '\n'字符。总共8个,将返回strlen(line)。因此strlen(line) - k等于3,导致for循环循环3次。

但是在处理文件的最后一行时,line将包含"TGAACGGTA\0"。不计算结尾的'\0',它们是9个字母字符,但没有'\n'个字符,因此strlen(line)仅返回9。因此,strlen(line) - k等于4,导致{ {1}}循环仅循环4次,而不是5次,导致没有生成第5个k-mer。

您需要执行以下操作之一:

A) 在文件末尾添加一个空行,以便当前最后一行也以for结尾。

或: B) 更改'\n'循环:

for

或: C) 当 while ( (read = getline(&line, &len, stdin)) != -1 ) { for ( i = 0; line[i+k-1] != '\n' && line[i+k-1] != '\0'; i++ ) 位于行尾时,以结尾的'\n'覆盖,以使行仅包含您要使用的字母字符。然后更改'\0'循环中的条件,以考虑到现在这些行比以前短了一个字符。 (请注意,由于for返回写入的字符数,不计算getline(),并将其存储在'\0'中,因此无需一次又一次地重新计算字符串的长度):

read

您的代码至少还有另外一个问题。您每次调用 while ( (read = getline(&line, &len, stdin)) != -1 ) { if (line[read - 1] == '\n') line[--read] = '\0'; for ( i = 0; i <= read - k; i++ ) 时都会为substring分配空间,但是您永远不会释放它,从而导致内存泄漏(严格来说,您还应该释放substr())。