gpt4 book ai didi

c - 从文件崩溃读取时使用 realloc 扩展缓冲区

转载 作者:太空狗 更新时间:2023-10-29 14:57:55 24 4
gpt4 key购买 nike

我正在编写一些需要读取 fasta files 的代码,所以我的部分代码(包含在下面)是一个 fasta 解析器。由于单个序列可以跨越 fasta 格式的多行,因此我需要将从文件中读取的多个连续行连接成一个字符串。我这样做,通过在读取每一行后重新分配字符串缓冲区,使其成为序列的当前长度加上读入的行的长度。我做了一些其他的事情,比如剥离空白等。一切顺利第一个序列,但 fasta 文件可以包含多个序列。类似地,我有一个动态结构数组,其中包含两个字符串(标题和实际序列),即“char *”。同样,当我遇到一个新标题(由以“>”开头的行引入)时,我增加序列的数量,并重新分配序列列表缓冲区。 realloc 在为第二个序列分配空间时出现段错误

*** glibc detected *** ./stackoverflow: malloc(): memory corruption: 0x09fd9210 ***
Aborted

对于我的生活,我不明白为什么。我已经通过 gdb 运行它并且一切似乎都在工作(即一切都已初始化,值似乎是正常的)......这是代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <errno.h>

//a struture to keep a record of sequences read in from file, and their titles
typedef struct {
char *title;
char *sequence;
} sequence_rec;

//string convenience functions

//checks whether a string consists entirely of white space
int empty(const char *s) {
int i;
i = 0;
while (s[i] != 0) {
if (!isspace(s[i])) return 0;
i++;
}
return 1;
}

//substr allocates and returns a new string which is a substring of s from i to
//j exclusive, where i < j; If i or j are negative they refer to distance from
//the end of the s
char *substr(const char *s, int i, int j) {
char *ret;
if (i < 0) i = strlen(s)-i;
if (j < 0) j = strlen(s)-j;
ret = malloc(j-i+1);
strncpy(ret,s,j-i);
return ret;
}

//strips white space from either end of the string
void strip(char **s) {
int i, j, len;
char *tmp = *s;
len = strlen(*s);
i = 0;
while ((isspace(*(*s+i)))&&(i < len)) {
i++;
}
j = strlen(*s)-1;
while ((isspace(*(*s+j)))&&(j > 0)) {
j--;
}
*s = strndup(*s+i, j-i);
free(tmp);
}


int main(int argc, char**argv) {
sequence_rec *sequences = NULL;
FILE *f = NULL;
char *line = NULL;
size_t linelen;
int rcount;
int numsequences = 0;

f = fopen(argv[1], "r");
if (f == NULL) {
fprintf(stderr, "Error opening %s: %s\n", argv[1], strerror(errno));
return EXIT_FAILURE;
}
rcount = getline(&line, &linelen, f);
while (rcount != -1) {
while (empty(line)) rcount = getline(&line, &linelen, f);
if (line[0] != '>') {
fprintf(stderr,"Sequence input not in valid fasta format\n");
return EXIT_FAILURE;
}

numsequences++;
sequences = realloc(sequences,sizeof(sequence_rec)*numsequences);
sequences[numsequences-1].title = strdup(line+1); strip(&sequences[numsequences-1].title);
rcount = getline(&line, &linelen, f);
sequences[numsequences-1].sequence = malloc(1); sequences[numsequences-1].sequence[0] = 0;
while ((!empty(line))&&(line[0] != '>')) {
strip(&line);
sequences[numsequences-1].sequence = realloc(sequences[numsequences-1].sequence, strlen(sequences[numsequences-1].sequence)+strlen(line)+1);
strcat(sequences[numsequences-1].sequence,line);
rcount = getline(&line, &linelen, f);
}
}
return EXIT_SUCCESS;
}

最佳答案

你应该使用看起来像这样的字符串:

struct string {
int len;
char *ptr;
};

这可以防止 strncpy 错误,就像您看到的那样,并允许您更快地执行 strcat 和 friend 。

您还应该为每个字符串使用一个双数组。这可以防止过多的分配和 memcpys。像这样:

int sstrcat(struct string *a, struct string *b)
{
int len = a->len + b->len;
int alen = a->len;
if (a->len < len) {
while (a->len < len) {
a->len *= 2;
}
a->ptr = realloc(a->ptr, a->len);
if (a->ptr == NULL) {
return ENOMEM;
}
}
memcpy(&a->ptr[alen], b->ptr, b->len);
return 0;
}

我现在看到你在做生物信息学,这意味着你可能需要比我想象的更多的性能。您应该改用这样的字符串:

struct string {
int len;
char ptr[0];
};

这样,当您分配一个字符串对象时,您调用了 malloc(sizeof(struct string) + len) 并避免了对 malloc 的第二次调用。它需要做更多的工作,但它应该在速度和内存碎片方面有可衡量的帮助。

最后,如果这实际上不是错误的来源,那么看起来您有一些损坏。如果 gdb 失败,Valgrind 应该可以帮助您检测到它。

关于c - 从文件崩溃读取时使用 realloc 扩展缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8973129/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com