2010-10-13 11 views
5
struct DVDInfo *ReadStruct(void) { 
    struct DVDInfo *infoPtr; 
    int    num; 
    char   line[ kMaxLineLength ]; 
    char   *result; 

    infoPtr = malloc(sizeof(struct DVDInfo)); 

    if (NULL == infoPtr) { 
     printf("Out of memory!!! Goodbye!\n"); 
     exit(0); 
    } 

    printf("Enter DVD Title: "); 
    result = fgets(line, kMaxLineLength, stdin); 
    line[ strlen(line) - 1 ] = '\0'; 
    infoPtr->title = MallocAndCopy(line); 

    printf("Enter DVD comment: "); 
    result = fgets(line, kMaxLineLength, stdin); 
    line[ strlen(line) - 1 ] = '\0'; 
    infoPtr->comment = MallocAndCopy(line); 

    do { 
     printf("Enter DVD Rating (1-10): "); 
     scanf("%d", &num); 
     Flush(); 
    } 
    while ((num < 1) || (num > 10)); 

    infoPtr->rating = num; 

    printf("\n----------\n"); 

    return(infoPtr); 
} 

मैंने इस कोड के बारे में एक और थ्रेड में स्टैक ओवरफ्लो पर एक अलग प्रश्न पूछा, लेकिन उस पर डबल अप नहीं करना चाहता - इन फ़ाइलों के अंत में शून्य को क्यों समाप्त किया जा रहा है fgets द्वारा पढ़ा जा रहा है? fgets वैसे भी टर्मिंग शून्य जोड़ता है, यह overkill नहीं है?fgets स्वाभाविक रूप से सी में एक समाप्ति शून्य डालता है?

+2

सी पर्याप्त बफर लंघन के अवसर के रूप में यह है। जब कोई स्ट्रिंग सही ढंग से समाप्त हो जाती है, तो यह सुनिश्चित करने के लिए कार्य करने में समय लगेगा। (सी में एक स्ट्रिंग * सी में परिभाषा के अनुसार, एक एनयूएल के साथ एक वैध स्ट्रिंग होने के लिए समाप्त होना चाहिए) –

+2

हां, यह अधिक है। –

उत्तर

2

fgets आपके द्वारा प्रदान किए गए बफर में एक नल टर्मिनेटर लिखते हैं (यदि आप 0 से बड़े के रूप में बफर आकार निर्दिष्ट करते हैं)। अन्यथा आप उस पर strlen() को कॉल नहीं कर सका, strlen() एक स्ट्रिंग की अपेक्षा करता है, और यदि इसे समाप्त नहीं किया जाता है तो यह एक स्ट्रिंग नहीं है।

आप पूछ रहे हैं के बारे में

line[ strlen(line) - 1 ] = '\0'; 

यह बंद स्ट्रिप्स line के अंतिम वर्ण हैं.यदि आप एक लाइन पढ़ा है, यह पिछले चरित्र, शायद एक नुल टर्मिनेटर के साथ एक \ N बदल देता है।

ध्यान दें कि fgets बस एक पंक्ति पढ़ते हैं, उदा। आपके line बफर में अब "हैलो \ n" स्ट्रिंग है (\ n सिर्फ भागने का अनुक्रम है, यह वास्तव में केवल 1 वर्ण है, न कि 2)

स्ट्रलेन ("हैलो \ n") 6 है, और 6- 1 से 5 है, इसलिए 5. सूचकांक द्वारा 0

"Hello\n" 
    ^
     | 
     Add 0 terminator 

परिणाम बदल जाएगी: "हैलो"

बस सावधान रहना:

  • आप लाइन करने के लिए [strlen नहीं करना चाहते (रेखा) - 1] = '\ 0'; एक खाली स्ट्रिंग पर, उस स्थिति में आप लाइन कर रहे हैं [-1]।
  • आपको जांचना चाहिए कि क्या fgets succeds है। अगर आप विफल हो जाते हैं तो आप line में चारों ओर पोक नहीं करना चाहते हैं, और आपके बफर को कुछ भी नहीं लिखा है।
  • आप यह जांचना चाहेंगे कि एक पूरी लाइन वास्तव में पढ़ी गई है या नहीं। यदि आपके द्वारा पढ़ी जाने वाली रेखा kMaxLineLength, या उदा। अगर फ़ाइल में आखिरी "पंक्ति" में पिछली \ n नहीं है, तो स्ट्रेल (लाइन) -1 \ n (newline) नहीं होगी।
+1

आपका अंतिम बुलेट बिंदु किसी पिछली पंक्ति के बिना किसी पिछली पंक्ति के लिए फ़ाइल में होना चाहिए। – jamesdlin

3

आम तौर पर, आप न्यूलाइन चरित्र को प्रतिस्थापित करते हैं जो fgets को एक एनयूएल चरित्र के साथ स्ट्रिंग में जोड़ता है। सभी मामलों में, fgets एनयूएल समाप्त हो जाएगा।

देखें: http://www.opengroup.org/onlinepubs/009695399/functions/fgets.html

+0

fgets हमेशा 0 के साथ समाप्त होता है; –

+2

हमेशा नहीं। यदि आप लंबाई 0 के रूप में पास करते हैं तो यह नहीं होगा। हालांकि पागल कोने का मामला। 'Fgets' के वापसी मूल्य की जांच के लिए – JaredPar

1

आपका

result = fgets(line, kMaxLineLength, stdin); 

ठीक है के बाद से लाइन के आकार kMaxLineLength है।

fgetsstream से सबसे ज्यादा एक size से कम पात्रों पर में पढ़ता है और उन्हें बफर में संग्रहीत करता है ...

1

line[ strlen(line) - 1 ] = '\0'; अनावश्यक (और असुरक्षित — strlen() ठीक से काम करने नहीं जा रहा है कर रहे हैं स्ट्रिंग 'isn टी पहले से ही समाप्त हो गया है)। fgets() बफर को रद्द कर देगा। साथ ही, आपको line कॉपी करने का प्रयास करने से पहले result != NULL की जांच करनी चाहिए। fgets() फ़ाइल के अंत में NULL देता है या यदि कोई त्रुटि होती है।

+1

+1। – pmg

1

हां, यह अधिक है।

एक सुझाव यह इसे और अधिक कोड सड़ांध के खिलाफ मजबूत बनाने के लिए ... बदल

result = fgets(line, kMaxLineLength, stdin); 

को

result = fgets(line, sizeof(line), stdin); 
संबंधित मुद्दे