我有一个包含字符串列表的文件。我尝试生成所有这些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
答案 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()
)。