我有一个包含字符串列表的文件。我尝试生成这些的所有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
我注意到除了最后一行之外,你文件中的每一行都以'\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导致for
循环仅循环4次而不是5次导致第5 k- mer没有被生成。
您需要做的是以下之一:
A)在文件末尾添加一个空行,以便当前最后一行也以'\n'
结尾。
或:B)更改for
循环:
while ( (read = getline(&line, &len, stdin)) != -1 ) {
for ( i = 0; line[i+k-1] != '\n' && line[i+k-1] != '\0'; i++ )
或者:C)当'\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()
时都会为line
分配空间,但你永远不会释放它,导致内存泄漏(严格来说你也应该释放qazxswpoi)。