我是python的新手。我正在尝试编写两个c脚本,一个读取FASTA格式的纯文本文件(用于DNA / RNA /蛋白质序列)。他们看起来像这样......
>sequence1
ATCTATGTCGCTCGCTCGAGAGCTA
>sequence2
CGTCGCTGGGATCGATTTCGATAGCT
>sequence3
AAATATAACTCGCTAGCTCGATCGATC
>sequence4
CTCTCTCCTCTCTCTATATAGGGG
...个别序列由“>”分隔字符。在每个序列中,实际序列及其标签由换行符分隔。 (即“>标签\ n序列”)。用于读取纯文本然后将其写入二进制文件的脚本似乎可行。但是,当我尝试读取二进制文件并打印其内容时,我收到了分段错误(Core dump)。
我试图在这里发布一个简化的示例,但是这个例子似乎没有错误。所以,我觉得我不得不在这里附上我的整个代码片段。我一定错过了什么。
这是第一个读取纯文本fasta文件的脚本,首先将其拆分为“>”字符,然后由换行符,为上述FASTA文件中的每个序列创建“序列”结构。然后将这些结构写入“your_sequences.bin”。
#include <stdio.h>
#include <string.h>
#define BUZZ_SIZE 1024
struct sequence {
char *sequence;
char *label;
};
int main(int argc, char *argv[]) {
FILE *fptr;
char buffer[BUZZ_SIZE];
char fasta[BUZZ_SIZE];
char *token;
char *seqs[3];
int idx = 0;
const char fasta_delim[2] = ">";
const char newline[3] = "\n";
/* Read-in plain-text */
fptr = fopen(argv[1],"r");
while (fgets(buffer, BUZZ_SIZE, fptr) != NULL) {
strcat(fasta, buffer);
}
fclose(fptr);
/* Process text, first by splitting by > and then by \n for each sequence, and then write to binary */
FILE *out;
out = fopen("your_sequences.bin","wb");
struct sequence final_entry;
token = strtok(fasta,fasta_delim);
while (token != NULL) {
seqs[idx++] = token;
token = strtok(NULL,fasta_delim);
}
for (idx=0; idx<4; idx++) {
token = strtok(seqs[idx],newline);
char *this_seq[1];
int p = 0;
while (token != NULL) {
this_seq[p] = token;
token = strtok(NULL,newline);
p++;
}
final_entry.label = this_seq[0];
final_entry.sequence = this_seq[1];
printf("%s\n%s\n\n", final_entry.label, final_entry.sequence);
fwrite(&final_entry, sizeof(struct sequence), 1, out);
}
fclose(out);
return(0);
}
这正如预期的fprint()声明一样输出到底部:
sequence1
ATCTATGTCGCTCGCTCGAGAGCTA
sequence2
CGTCGCTGGGATCGATTTCGATAGCT
sequence3
AAATATAACTCGCTAGCTCGATCGATC
sequence4
CTCTCTCCTCTCTCTATATAGGGG
我认为错误必须在上面的脚本中(即我的二进制文件搞砸了),因为分段错误是由下面脚本中的fread()语句引起的。我不认为我在调用fread()时犯了错误,但也许我错了。
#include <stdio.h>
#define BUZZ_SIZE 1024
struct sequence {
char *sequence;
char *label; };
int main(int argc, char *argv[]) {
struct sequence this_seq;
int n;
FILE *fasta_bin;
fasta_bin = fopen(argv[1],"rb");
for (n=0;n<4;n++) {
fread(&this_seq, sizeof(struct sequence), 1, fasta_bin);
printf (">%s\n%s\n", this_seq.label, this_seq.sequence);
}
fclose(fasta_bin);
return(0);
}
这会输出分段错误
[1] 8801 segmentation fault (core dumped)
在过去的几个小时里,我已经修好并且花了很多钱。我希望我没有犯下一些愚蠢的错误,浪费你的时间!
感谢您的帮助。
答案 0 :(得分:2)
我认为错误必须在上面的脚本中(即我的 二进制文件搞砸了),
排序。
因为分段错误是由 下面脚本中的fread()语句。
我非常确信错误不会发生在fread()
中,而是发生在以下printf()
中。
我认为我没有做过 调用fread()时出错,但也许我错了。
您的fread()
对应fwrite()
。我们完全有理由期待您准确地回读所写的内容。这里的主要问题是C新手的一个常见问题:你误解了C字符串的性质(char
的空终止数组),并且没有意识到关键,但是数组和指针之间的细微区别。
为了扩展这一点,C没有第一类字符串数据类型。相反,标准库提供“字符串”函数,这些函数对类型为char
的对象序列进行操作,其中序列的末尾由终止符char
标记,值为0.此类序列通常包含在char
数组中,始终可以像对待它们一样对待。因为这是标准库支持的,所以该约定也普遍用于程序和第三方库中。
C没有将数组传递给函数或将它们作为返回值接收的机制。赋值运算符或大多数其他运算符也不适用于数组 - 甚至不是索引运算符[]
。相反,在大多数情况下,数组类型的值会自动转换为指向第一个数组元素的指针,并且这些值可以传递给各种运算符并用作操作数。看到(部分)这个,缺乏经验的C程序员经常错误地用这样的指针识别字符串而不是指向数据。
当然,指针值只是一个地址。您可以复制它并将其存储在程序中的任意位置,但这对指向的数据没有任何作用。现在我终于明白了:你也可以写出一个指针值并将其读回来,就像程序那样,但这样做很少有用,因为指向的是当你这样做时,数据不会出现。除非您将指针读回到写入它的同一进程中,否则回读指针值不太可能有效,并且它与编写它的程序中的确无法达到相同的意义。
您必须改为编写指向数据,但必须选择一种格式。特别是,标题和序列通常具有不同的长度,您需要决定的关键事项之一是,如果有的话,您的二进制格式应该如何反映这一点。但是,如果我可能会如此大胆,我建议您使用一种定义明确的格式:Fasta格式!严重。
没有太多的数据压缩能够更加紧凑地表达fasta格式的数据,因为这种格式只需要表达它传达的变长数据所需的数据。那么,您需要回答的问题是,您正在尝试通过重新格式化来实现什么 - 根本就是重新格式化的原因,以及基于此目标格式实际上是什么。
答案 1 :(得分:1)
您正在获得分段错误,因为在您的程序中,您正在使用指针而不为它们分配内存:
printf (">%s\n%s\n", this_seq.label, this_seq.sequence);
首先需要为this_seq.label
和this_seq.sequence
指针分配内存,如下所示:
this_seq.sequence = malloc(size_of_sequence);
if (this_seq.sequence == NULL)
exit(EXIT_FAILURE);
this_seq.label = malloc(size_of_label);
if (this_seq.label == NULL)
exit(EXIT_FAILURE);
然后将数据读入它们,如下所示:
fread(this_seq.sequence, size_of_sequence, 1, fasta_bin);
fread(this_seq.label, size_of_label, 1, fasta_bin);