2011-10-08 16 views
7

मैं सी के लिए थोड़ा नया हूं और मुझे यह समझने में परेशानी हो रही है कि स्मृति कैसे काम करती है, विशेष रूप से memcpy जैसे अंतर्निर्मित कार्यों में।सी - मॉलोक और मेम्पी (मेमोरी मैनेजमेंट)

यहाँ एक struct मैं

struct data_t { 
    int datasize; 
    void *data; 
}; 

उपयोग कर रहा हूँ है और यहाँ एक सहायक समारोह है कि मैं इसे उपयोग कर रहा हूँ के साथ है:

struct data_t *data_create(int size) 
{ 
    struct data_t *dt=malloc(sizeof(struct data_t)+size); 
    dt->datasize=size; 
    dt->data="1234567890a"; 
    return dt; 
} 

अब main समारोह में मैं यह कर रहा कोई समस्या नहीं है:

struct data_t *data = data_create(1024); 
data->data="123456a";//just an example 

लेकिन यह एक सेग फाल्ट फेंकता है:

memcpy(data->data,"123456a",strlen("1234567890a")+1); 

मेरा प्रश्न है क्यों? और मैं इससे कैसे बचूं? कृपया ध्यान रखें कि मैं सी के लिए नया हूं, तो सी मेमोरी के साथ कैसे सौदों मेरे लिए थोड़ा नया है

धन्यवाद।

संपादित करें: यह काम करता है! आपका बहुत बहुत धन्यवाद। डेटा पॉइंटर को पूरी तरह याद किया। अब सब कुछ valgrind के अनुसार ठीक काम कर रहा है।

उत्तर

6

memcpy(data->data,"123456a",strlen("1234567890a")+1);

कुछ कचरा/अमान्य पते जो आवंटित नहीं किया गया है क्योंकि data->data एक void * प्रकार अंक विफल रहता है। data में स्ट्रिंग अक्षर का पता है जो में पढ़ने के लिए धारा (जैसे .rodata में निष्पादन योग्य और स्मृति में लोड किया गया है, जो लिखने योग्य नहीं है। इसके अलावा, यदि आपने सूचक को ऐसा स्ट्रिंग पता असाइन नहीं किया है चर, तो यह कुछ अवैध/कचरा पते के मूल्य जो आवंटित या कुछ वैध अनुमति दी स्थान के साथ आरंभ नहीं किया है बफर पकड़ होगा। इसलिए पहले आवंटित।

data->data = malloc (sizeof (char) * size); 

malloc पते के एक ब्लॉक के पहले स्थान पते के वापस आ जाएगी कम से कम size * sizeof (char) बाइट्स। अब आप इस स्मृति स्थान पर द्वारा size बाइट कॉपी कर सकते हैं।

आवंटित मेमोरी ब्लॉक को मुक्त करना याद रखें जब आपने free (addr) कॉल के साथ उस मेमोरी बॉक के साथ काम करना समाप्त कर दिया है।


मैं देख रहा हूँ कि आप एक बहुत ही अजीब तरीके से data बफर आवंटित की कोशिश की है (?):

struct data_t *dt=malloc(sizeof(struct data_t)+size); 

जिसके लिए अतिरिक्त struct data_t के साथ size बाइट्स आवंटित। लेकिन क्या मामला है, data घटक अभी भी कुछ जगहों को इंगित करता है जिसे बदला नहीं जा सकता है। का उपयोग करें:

struct data_t *dt = malloc(sizeof(struct data_t)); 
dt->data = malloc (sizeof (char) * size); 
memcpy (data->data, "whatever", sizeof ("whatever")+1); 
return dt; 

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

free (dt->data); 

तो

free (dt); 
+0

अंतरिक्ष आरंभिक आवंटन में आवंटित किया गया था; पॉइंटर बस आवंटित स्थान को इंगित करने के लिए सेट नहीं किया गया था। –

+0

@ जोनाथन लेफ्लर: हां, शुरुआत में आवंटित होने पर पूछने वाले ने कुछ अतिरिक्त जगह आवंटित की, उसे बिंदु पर प्रारंभ करना चाहिए था। यदि आप सभी को एक साथ आवंटित करने की कोई विशिष्ट आवश्यकता नहीं है, तो भी मैं स्पष्ट कॉल पसंद करूंगा। – phoxis

+0

यह एक त्रुटि देगा: "शून्य * * से 'data_t *' [-fpermissive]" से अमान्य रूपांतरण हल करने के लिए "आपको मॉलोक द्वारा लौटाए गए सूचक को स्पष्ट रूप से डालना होगा"। – VasaraBharat

1

सूचना void *data एक सूचक है, data_create में, आप इसके लिए अंतरिक्ष का आवंटन नहीं किया था, आप बस इसे एक स्ट्रिंग स्थिर "1234567890a" पर इंगित करें जो केवल पढ़ा जाता है।

main में, आप एक और स्ट्रिंग निरंतर "123456a" बनाते हैं, तो आप स्ट्रिंग निरंतर है, जो केवल पढ़ने के लिए है करने के लिए void *data बिंदु बनाने के।

तो जब आप memcpy को मेमोरी एड्रेस लिखने के लिए कहते हैं जो लिखने योग्य नहीं है (या प्रारंभ किए बिना), तो आपको एक त्रुटि मिली है।

0

डेटा-> डेटा सूचक है। और यह सूचक कहीं भी इंगित नहीं करता है। Memcpy करने से पहले आपको अंतरिक्ष आवंटित करना चाहिए और इस स्थान पर इंगित करने के लिए डेटा-> डेटा बनाना चाहिए।

data->data = malloc(strlen("1234567890a")+1); 

और फिर memcpy डेटा- के रूप में रूप में लंबे समय असफल नहीं हो> डेटा! = शून्य

कर

data->data = "123"

, ठीक है क्योंकि "123" संकलन समय पर आवंटित किया जाता है, इसलिए डेटा-> स्ट्रिंग "123" की शुरुआत के लिए डेटा पॉइंट्स, लेकिन memcpy(data->data,"123",4) पर कॉल करना असफल हो जाएगा, क्योंकि डेटा-डेटा के पॉइंटर को अनियंत्रित किया गया है और स्मृति में कुछ यादृच्छिक स्थान को इंगित किया गया है जिसे पढ़ा नहीं जा सकता है।

struct data_t *dt=malloc(sizeof(struct data_t)+size); 

यह आकार struct data_t + आकार की स्मृति का एक हिस्सा बना देगा:

+0

'memcpy' अभी भी अमान्य है अगर स्रोत से स्रोत से अधिक बाइट कॉपी करने का प्रयास करता है, जो यहां है। – Mat

+0

हां उनके कोड में दो त्रुटियां हैं –

3

आपका पहला गलती यह है। मुझे लगता है कि आपने जो अपेक्षा की थी वह था कि data_t के अंदर आपका डेटा फ़ील्ड इस मेमोरी का उपयोग कर सकता है लेकिन ऐसा नहीं हो सकता क्योंकि डेटा इस स्मृति में कोई पता नहीं रखता है।

आपकी दूसरी गलती है कि आप जहां "डाटा" में निम्न स्ट्रिंग के मान को कॉपी ग्रहण करने के लिए किया गया था:

data->data="123456a"; 

क्या वास्तव में यहाँ क्या हुआ स्मृति "123456a" है कि मौजूद है में एक स्ट्रिंग है कि वहाँ है अपने कार्यक्रम के पूरे जीवन के लिए। जब आप डेटा को "123456a" असाइन करते हैं-> डेटा वास्तव में क्या हो रहा है यह है कि आप इस स्ट्रिंग "123456a" का पता ले रहे हैं और इसे डेटा-> डेटा में डाल रहे हैं जो आप मूल्य ("123456a") की प्रतिलिपि नहीं बना रहे हैं लेकिन स्थान या "123456a" का पता (0x23822 ...)।

memcpy(data->data,"123456a",strlen("1234567890a")+1); 

आप स्मृति में मूल्य "123456a" नकल करने की कोशिश की डेटा द्वारा की ओर इशारा किया:

आपकी अंतिम गलती यह थी। डेटा इंगित करने वाला क्या है? यह आपकी पिछली असाइन की गई स्ट्रिंग "123456a" वाली मेमोरी के केवल पढ़ने वाले क्षेत्र को इंगित कर रहा है। दूसरे शब्दों में आपने अपने कार्यक्रम को "123456a" के पते पर लिखने के लिए कहा था।

आप निम्न की अपेक्षा एक कार्यक्रम क्या करेंगे है:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <assert.h> 

typedef struct { 
    size_t datasize; 
    char *data; 
} data_t; 

data_t *data_create(size_t size) 
{ 
    data_t *dt; 

    dt = malloc(sizeof(data_t)); 
    assert(dt != NULL); 
    dt->data = malloc(size); 
    assert(dt->data != NULL); 
    dt->datasize = size; 

    /* need to decide what to do when this happens */ 
    assert((strlen("1234567890a") + 1) < size); 
    strcpy(dt->data, "1234567890a"); 

    return dt; 
} 

void data_destroy(data_t *dt) 
{ 
    free(dt->data); 
    free(dt); 
} 

int main(void) 
{ 
    data_t *data = data_create(1024); 
    /* data->data="123456a"; DONT DO THIS YOU WILL CAUSE A MEMORY LEAK */ 

    assert(data->datasize >= (strlen("123456a")+1)); 
    memcpy(data->data, "123456a", strlen("123456a")+1); 

    printf("%s\n", data->data); 

    data_destroy(data); 

    return EXIT_SUCCESS; 
} 
संबंधित मुद्दे