2012-01-23 20 views
5

मैं कुछ कोड लिख रहा हूं जिन्हें fasta files पढ़ने की आवश्यकता है, इसलिए मेरे कोड का हिस्सा (नीचे शामिल) एक फास्ट पार्सर है। चूंकि एक अनुक्रम फास्ट प्रारूप में कई लाइनों का विस्तार कर सकता है, इसलिए मुझे फ़ाइल से एक ही स्ट्रिंग में पढ़ने वाली कई लगातार पंक्तियों को जोड़ना होगा। मैं यह करता हूं, अनुक्रम की वर्तमान लंबाई और लाइन पढ़ने की लंबाई होने के लिए, प्रत्येक पंक्ति को पढ़ने के बाद स्ट्रिंग बफर को फिर से चलाकर। मैं कुछ अन्य सामान करता हूं, जैसे सफेद स्थान को अलग करना आदि। सभी के लिए अच्छा है पहला अनुक्रम, लेकिन फास्ट फाइलों में एकाधिक अनुक्रम हो सकते हैं। इसी तरह, मेरे पास दो तारों (शीर्षक, और वास्तविक अनुक्रम) के साथ "char *" होने के साथ structs की एक गतिशील सरणी है। दोबारा, जैसा कि मुझे एक नया शीर्षक मिलता है ('>' से शुरू होने वाली रेखा से पेश किया गया है) मैं अनुक्रमों की संख्या में वृद्धि करता हूं, और अनुक्रम सूची बफर को फिर से चलाता हूं। मुझे के जीवन मैं क्यों नहीं देख सकते हैं के लिएफ़ाइल क्रैश से पढ़ने के दौरान बफर का विस्तार करने के लिए रीयलोक का उपयोग करना

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

के साथ दूसरे दृश्य के लिए अंतरिक्ष आवंटन पर realloc segfaults।

#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; 
} 
+0

सबस्ट्रिंग दिनचर्या के बारे में सभी टिप्पणियों के लिए धन्यवाद। मैंने इसे अपने कोड में ठीक कर दिया है। मैंने यह भी ध्यान दिया कि जिस तरह से मैंने नकारात्मक इंडेक्स के साथ निपटाया वह गलत था। मुझे नकारात्मक सूचकांक जोड़ना चाहिए, इसे घटाएं नहीं। ऐसा कहा जा रहा है, मुझे यह भी एहसास हुआ कि मैंने सबस्ट्रेट फ़ंक्शन को गलती से कॉपी किया है, क्योंकि मैं इसे चिपकाए गए कोड के बाकी हिस्सों में नहीं कहता हूं। – sirlark

+0

'स्ट्रिप() 'भी छोटी है। यह शून्य-लंबाई तारों के साथ बुरी चीजें करेगा। ऐसा लगता है कि आप इसे इस तरह के तारों से नहीं बुलाते हैं, लेकिन मुझे लगता है कि इसे कहीं और इस्तेमाल करने के लिए ठीक करना एक अच्छी बात होगी। –

उत्तर

1

मुझे लगता है कि स्मृति भ्रष्टाचार समस्या आपके परिणामस्वरूप हो सकती है कि आप अपने getline() कॉल में उपयोग किए गए डेटा को कैसे प्रबंधित कर रहे हैं। मूल रूप से, line के माध्यम से strip() पर कॉल में पुन: आवंटित किया गया है, इसलिए बफर आकार linelengetline() द्वारा ट्रैक किया जा रहा है अब सटीक नहीं होगा। getline() बफर को ओवरराउन कर सकता है।

while ((!empty(line))&&(line[0] != '>')) { 

    strip(&line); // <-- assigns a `strndup()` allocation to `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); // <-- the buffer `line` points to might be 
              //  smaller than `linelen` bytes 

} 
+0

आप यहां कुछ स्ट्रिंग्स को ट्रिम करने के लिए कुछ अच्छे, सरल, परीक्षण किए गए फ़ंक्शंस प्राप्त कर सकते हैं: http://stackoverflow.com/a/2452438/12711 उस लिंक से 'trim()' का उपयोग करके इस समस्या को हल किया जाएगा (और अन्य अव्यवस्था 'स्ट्रिप() 'फ़ंक्शन में बग)। –

+0

मैंने स्ट्रिप (और सबस्ट्र) के साथ सभी समस्याएं तय कीं और अभी भी समस्या थी। गेटलाइन और लिनेलीन के साथ बातचीत निश्चित रूप से समस्या थी। पूरी सहायताके लिए शुक्रिया – sirlark

3

एक संभावित यहां मुद्दा यह है:

strncpy(ret,s,j-i); 
return ret; 
मैं gdb के माध्यम से इसे चलाने की है और सब कुछ (यानी सब कुछ initialised है, मूल्यों समझदार लगता है) काम कर रहा है ... यहाँ कोड है

ret शायद एक शून्य टर्मिनेटर नहीं मिल सकता है। man strncpy देखें:

 char *strncpy(char *dest, const char *src, size_t n); 

     ... 

     The strncpy() function is similar, except that at most n bytes of src 
     are copied. Warning: If there is no null byte among the first n bytes 
     of src, the string placed in dest will not be null terminated. 

वहाँ भी एक बग यहाँ है:

j = strlen(*s)-1; 
while ((isspace(*(*s+j)))&&(j > 0)) { 

क्या होगा अगर strlen(*s) 0 है? आप (*s)[-1] पढ़ना समाप्त कर देंगे।

आप strip() में भी चेक नहीं करते हैं कि स्ट्रिंग में पूरी तरह से रिक्त स्थान शामिल नहीं हैं। यदि ऐसा होता है, तो आप j < i के साथ समाप्त हो जाएंगे।

संपादित करें: बस ध्यान दिया गया कि आपका substr() फ़ंक्शन वास्तव में नहीं बुलाया जाता है।

4

आप तार कि कुछ इस तरह दिखाई उपयोग करना चाहिए:

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

यह यह क्या लगता है कि आप देखा की तरह strncpy कीड़े से बचाता है, और आप strcat और दोस्तों के लिए तेजी से करने के लिए अनुमति देता है।

आपको प्रत्येक स्ट्रिंग के लिए एक दोगुनी सरणी का भी उपयोग करना चाहिए। यह बहुत से आवंटन और 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 आपको इसका पता लगाने में मदद करनी चाहिए।

+0

@lief: स्मृति की खपत गति से अधिक समस्या है। मैं दोगुनी हिस्सों में आवंटित नहीं करना चाहता हूं और अंतरिक्ष बर्बाद हो गया हूं। माना जाता है कि यह प्रसंस्करण में फास्ट पार्सर में कोई समस्या नहीं है। – sirlark

+0

आंतरिक मॉलोक विखंडन के कारण, यदि आप इसका अनुरोध नहीं करते हैं तो भी आप बहुत अधिक स्मृति का उपयोग कर समाप्त कर सकते हैं। दोगुनी सरणी काफी भरोसेमंद हैं, लेकिन यदि वे बहुत डरावनी हैं, तो कृपया कम से कम अपने विखंडन को मापने के लिए 'malloc_usable_size' जैसे कुछ का उपयोग करें। यदि आप सरणी को दोगुना करना चुनते हैं, और लम्बाई और स्ट्रिंग बफर आवंटित करने का मेरा दूसरा सुझाव, सावधान रहें कि आप आकार गणना में लंबाई शामिल करते हैं, या आप भयानक विखंडन के साथ समाप्त हो सकते हैं (यदि आप 2^n + sizeof int आवंटित करते हैं , उदाहरण के लिए)। – leif

+0

'चार पीआरटी [0];' अमान्य सी है। आपका मतलब है 'char ptr [];', लेकिन यह अब तत्व के लिए एक बुरा नाम है क्योंकि यह एक सरणी है, सूचक नहीं। मैं इसे 'डेटा' या 'सामग्री' या उन पंक्तियों के साथ कुछ कहूंगा। –

संबंधित मुद्दे