2011-02-24 6 views
5

के अंदर एक स्ट्रिंग के लिए स्मृति आवंटित करना मुझे पता है कि यह प्रश्न चारों ओर रहा है, लेकिन मुझे थोड़ा धुंधला, लंबा या/और भ्रमित करने का जवाब मिला; इसलिए मैं पूरी तरह से बिंदु प्राप्त करने के लिए विशेष रूप से अपने कोड का उल्लेख करने जा रहा हूं।संरचना

typedef struct album { 
    unsigned int year; 
    char *artist; 
    char *title; 
    char **songs; 
    int songs_c; 
} album ; 

निम्नलिखित कार्य:

struct album* init_album(char *artist, char *album, unsigned int year){ 
    struct album *a; 
    a= malloc(sizeof(struct album)); 
    a->artist = malloc(strlen(artist) + 1); 
    strncpy(a->artist, artist, strlen(artist)); 
    a->title = malloc(strlen(album) + 1); 
    strncpy(a->title, album, strlen(album)); 
    a->year = year; 
    return a; 
} 

void add_song(struct album *a, char *song){ 
    int index = a->songs_c; 
    if (index == 0){ 
    a->songs = malloc(strlen(song)); 
    } else a->songs[index] = malloc(strlen(song)+1); 

    strncpy(a->songs[index], song, strlen(song)); 
    a->songs_c= a->songs_c+1; 
} 

और एक मुख्य कार्य:

int main(void){ 
    char *name; 
    char artist[20] = "The doors"; 
    char album[20] = "People are strange"; 
    int year = 1979; 

    struct album *a; 
    struct album **albums; 

    albums = malloc(sizeof(struct album)); 

    albums[0] = init_album((char *)"hihi", (char *)"hoho", 1988); 

    albums[1] = init_album((char *)"hihi1", (char *)"hoho1", 1911); 

    printf("%s, %s, %d\n", albums[0]->artist, albums[0]->title, albums[0]->year); 
    printf("%s, %s, %d\n", albums[1]->artist, albums[1]->title, albums[1]->year); 

    char song[] = "song 1\0"; 

    add_song(albums[1], song); 

    free(albums[0]); 
    free(albums[1]); 
} 

विभाजन गलती जब में एक गीत को जोड़ने के लिए strncpy जारी करने

तो मैं इस struct मिला "add_song()"।

मैं गंभीर रूप से गलत क्या कर रहा हूं? जैसा कि कई गुना सुना है, सी में कार्यान्वयन का कोई "सही" तरीका नहीं है, जब तक यह काम करता है और यह छोटी नहीं है, यह ठीक है, लेकिन शुरुआत के रूप में स्मृति आवंटन का उपयोग करने के बारे में कुछ सावधानी प्रतिक्रिया या सलाह प्राप्त करना बहुत अच्छा होगा जटिल डेटा संरचनाओं के साथ।

धन्यवाद एक गुच्छा! /एस

+1

चार गीत [] = "गीत 1 \ 0"; यह दो शून्य समाप्ति अक्षर जोड़ता है। जैसे ही आप "" उपयोग करते हैं, संकलक आपके लिए एक अदृश्य शून्य समाप्ति जोड़ देगा, आपको इसे मैन्युअल रूप से करने की आवश्यकता नहीं है। "एक्स" {'x', '\ 0'} जैसा ही है। – Lundin

+0

@Vlad यह एक कठिन choise है। या तो सी/सी ++ में लिखें और स्मृति प्रबंधन के लिए प्रोग्रामर के समय का 9 0% खर्च करें, या एक और भाषा चुनें और उसी उद्देश्य के लिए प्रोग्राम निष्पादन समय का 9 0% खर्च करें। =) – Lundin

+0

@ लंदन: बिल्कुल सही नहीं है। मैं कहूंगा कि यदि आपको किसी महत्वपूर्ण पथ पर आवंटित/मुक्त स्मृति की आवश्यकता है - यह एक खराब डिज़ाइन है, और कोई समस्या है चाहे आप सी या सी ++ का उपयोग करते हों, अन्यथा सी ++ से 'std :: string' का उपयोग नहीं किया जाएगा अपने प्रदर्शन को नुकसान पहुंचाएं, खासकर यदि आपके पास ऑब्जेक्ट पूल है (या यहां तक ​​कि लॉक-फ्री ऑब्जेक्ट पूल)। –

उत्तर

3
if (index == 0) { 
    a->songs = malloc(strlen(song)); 
} else a->songs[index] = malloc(strlen(song)+1); 

यह एक अच्छा विचार नहीं है। आपको a->songs[x] के माध्यम से गाना चाहिए, इसलिए आपको a->songs को (char**)malloc(sizeof(char*)*numsongs) के रूप में आवंटित करने की आवश्यकता है। जब केवल एक गीत होता है, तो आपको इसे उप-सूचक में रखना चाहिए।

एक कारण यह है कि आप segfaulting रहे हैं जैसे आप अन्य सभी स्थानों है, क्योंकि इसके बाद के संस्करण NUL के लिए एक +1 नहीं है ... एक और है कि आप +1strncpy लंबाई में नहीं जोड़ा था, इसलिए कुछ भी वास्तव में हो जाता है है समाप्त हो गया।

+0

मैं इस फ़ंक्शन का उपयोग गतिशील रूप से गाने जोड़ने के लिए करने जा रहा हूं, क्या यह हर बार जब मैं एक गीत जोड़ता हूं तो यह malloc करने के लिए काम करता है? क्या मेरा पिछला आवंटन/प्रयुक्त स्मृति गुम हो गई है? – Smokie

+0

अभी भी एक सेगमेंटेशन गलती मिली है ... – Smokie

3

समस्या strncpy() नहीं आप के लिए स्ट्रिंग शून्य-समाप्त कर देगा है:

a->artist = malloc(strlen(artist) + 1); 
strncpy(a->artist, artist, strlen(artist)); // null terminator is not placed 

जब से तुम यह बताओ कि बफर केवल स्वयं स्ट्रिंग के लिए स्थान है। यहां समाधान केवल strcpy() का उपयोग करना है - आप यह सुनिश्चित करने के लिए जानते हैं कि बफर काफी बड़ा है।

इसके अलावा इस:

free(albums[0]); 
free(albums[1]); 

केवल संरचनाओं मुक्त होगा, लेकिन नहीं तार उन संरचनाओं से की ओर इशारा किया और आप एक स्मृति रिसाव मिल गया है।

+0

strlen (कलाकार) +1 के साथ strcpy और strncpy क्यों? – Smokie

+0

@ स्मोकी: यह होगा, लेकिन यह कोई समझ नहीं आता है - आपके पास स्ट्रिंग और ओवेरिनियर कोड के साथ एक अतिरिक्त स्कैन होगा। 'strcpy()' आप यहां क्या मतलब है, तो बस इसका इस्तेमाल करें। – sharptooth

1

मेरी राय में, क्या तुम गंभीर रूप से उचित साधनों का उपयोग नहीं कर रहा है :-)

एक समस्या यह गलत करते हैं निम्न पंक्ति है:

a->songs = malloc(strlen(song)); 

आप की लंबाई के बराबर बाइट्स की राशि का आवंटन पहला गीत, लेकिन आप चार पॉइंटर्स की एक सरणी चाहते हैं। यह गूंगा भाग्य द्वारा काम कर सकता है, यह पहला गीत शीर्षक उपयोग किए गए चार पॉइंटर्स की संख्या के लिए आवश्यक बाइट्स की संख्या से अधिक वर्ण है।

लेकिन यह बेहतर हो

a->songs = calloc(max_number_of_songs, sizeof(char*)); 

करना या यहां तक ​​कि गतिशील और realloc जब जरूरत 'गीत' सरणी का विस्तार होगा।

वैसे, आप किसी भी चीज़ पर songs_c को कभी भी इंटिलाइज़ नहीं करते हैं, जिसका अर्थ है कि आपने songs आवंटित नहीं किया हो सकता है।

इसके अलावा, आप फिर से

albums = malloc(sizeof(struct album)); 

साथ albums आवंटित, इस गूंगा भाग्य से काम कर सकते हैं के बाद से दो संकेत के आकार struct album के आकार की तुलना में कम हो सकता है, लेकिन मुझे लगता है तुम सच में

albums = calloc(2, sizeof(struct album *)); 
मतलब

इन सभी समस्याओं को या तो स्थिर कोड विश्लेषण या रनटाइम विश्लेषण उपकरण द्वारा पकड़ा जाना चाहिए।

0

एल्बम के लिए initalbum function songs_c चर में [1] प्रारंभ नहीं किया गया है। इसमें एक कचरा मूल्य होगा।

फ़ंक्शन में add_song क्योंकि इंडेक्स प्रारंभ नहीं हुआ है, यह एसईजीवी का कारण बन रहा है।

0

गंभीरता से इस जगह पर विचार करें:

a->artist = malloc(strlen(artist) + 1); 
strncpy(a->artist, artist, strlen(artist)); 
इस के साथ

:

a->artist = my_strdup(artist); 

कहाँ:

char * my_strdup(const char *s) 
{ 
    char *out = NULL; 

    if(s != NULL) 
    { 
     const size_t len = strlen(s); 
     if((out = malloc(len + 1)) != NULL) 
     memcpy(out, s, len + 1); 
    } 
    return out; 
} 

मैं इसे स्पष्ट है कि बाद स्पष्ट है लगता है। यह भी बेहतर कार्यक्षमता के अनुसार है, क्योंकि strncpy() में भयानक अर्थशास्त्र है और वास्तव में मेरी राय में से बचा जाना चाहिए। इसके अलावा, मेरा समाधान काफी तेज है। यदि आपके सिस्टम में strdup() है तो आप इसका उपयोग सीधे कर सकते हैं, लेकिन यह 100% पोर्टेबल नहीं है क्योंकि यह अच्छी तरह से मानकीकृत नहीं है। बेशक, आपको उन सभी स्थानों के प्रतिस्थापन करना चाहिए जहां आपको एक स्ट्रिंग को गतिशील रूप से आवंटित स्मृति में कॉपी करने की आवश्यकता है।

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

  • कोई संबंधित समस्या नहीं^_^