2010-05-14 32 views
6

सीखने के बाद कि strncmp दोनों ऐसा नहीं लगता है और strlcpy मेरे ऑपरेटिंग सिस्टम (लिनक्स) पर उपलब्ध नहीं है, मुझे लगा कि मैं इसे स्वयं कोशिश कर सकता हूं और लिख सकता हूं।सी अजीब सरणी व्यवहार

मुझे लिबिक रखरखाव, Ulrich Drepper से उद्धरण मिला, जिसने mempcpy का उपयोग करके strlcpy का विकल्प पोस्ट किया। मेरे पास mempcpy नहीं है, लेकिन इसका व्यवहार दोहराना आसान था। इस, सबसे पहले testcase मैं

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

#define BSIZE 10 

void insp(const char* s, int n) 
{ 
    int i; 

    for (i = 0; i < n; i++) 
     printf("%c ", s[i]); 

    printf("\n"); 

    for (i = 0; i < n; i++) 
     printf("%02X ", s[i]); 

    printf("\n"); 

    return; 
} 

int copy_string(char *dest, const char *src, int n) 
{ 
    int r = strlen(memcpy(dest, src, n-1)); 
    dest[r] = 0; 

    return r; 
} 

int main() 
{ 
    char b[BSIZE]; 
    memset(b, 0, BSIZE); 

    printf("Buffer size is %d", BSIZE); 

    insp(b, BSIZE); 

    printf("\nFirst copy:\n"); 
    copy_string(b, "First", BSIZE); 
    insp(b, BSIZE); 
    printf("b = '%s'\n", b); 

    printf("\nSecond copy:\n"); 
    copy_string(b, "Second", BSIZE); 
    insp(b, BSIZE); 

    printf("b = '%s'\n", b); 

    return 0; 
} 

है और यह अपने परिणाम है:

Buffer size is 10      
00 00 00 00 00 00 00 00 00 00 

First copy: 
F i r s t  b  =  
46 69 72 73 74 00 62 20 3D 00 
b = 'First' 

Second copy: 
S e c o n d   
53 65 63 6F 6E 64 00 00 01 00 
b = 'Second' 

आप आंतरिक प्रतिनिधित्व में देख सकते हैं (लाइनों insp() बनाई गई) वहाँ कुछ शोर में मिलाया, की तरह है कि पहली प्रतिलिपि के बाद निरीक्षण में printf() प्रारूप स्ट्रिंग, और दूसरी प्रति में एक विदेशी 0x01।

तारों को बरकरार रखा गया है और यह सही ढंग से बहुत लंबे स्रोत तारों को संभालता है (चलिए 0 के लिए copy_string की लंबाई 0 के साथ संभावित समस्या को अनदेखा करते हैं, मैं इसे बाद में ठीक कर दूंगा)।

लेकिन मेरे गंतव्य के अंदर विदेशी सरणी सामग्री (प्रारूप स्ट्रिंग से) क्यों हैं? ऐसा लगता है कि गंतव्य वास्तव में नई लंबाई से मेल खाने के लिए संशोधित किया गया था।

+1

एक विदेशी सरणी क्या है? – WhirlWind

+0

इस मामले में मेरा मतलब है printf से स्ट्रिंग अक्षर, अर्थात् "बी = '% s'", जिसे मेरी सरणी "बी" के साथ "इंटरमीक्स" मिला, गंतव्य – LukeN

+0

नोट करें कि 'strlcpy() 'और' strlcat () 'उदार लाइसेंस के तहत बहुत आसानी से उपलब्ध है: http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/lib/libc/string/strlcpy.c?content-type=text%2Fplain –

उत्तर

4

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

इस मामले में नोट 'समस्या' copy_string में नहीं है, आप वास्तव में 10chars की प्रतिलिपि बना रहे हैं - लेकिन आपके मुख्य कोड में 'पहले' के बाद स्मृति बस यादृच्छिक है।

+0

हे भगवान, मैंने नहीं सोचा था कि memcpy() '\ 0', बेवकूफ, बेवकूफ मुझे नहीं रोकता है। – LukeN

2

क्योंकि आप स्रोत आकार पर रोक नहीं रहे हैं, तो आप भाग्य के आकार पर रोक रहे हैं, जो स्रोत से बड़ा होता है, इसलिए आप स्रोत स्ट्रिंग और इसके पीछे कुछ कचरा कॉपी कर रहे हैं।

आप आसानी से देख सकते हैं कि आप अपने स्रोत स्ट्रिंग को अपने शून्य टर्मिनेटर के साथ कॉपी कर रहे हैं। लेकिन चूंकि आप 10 बाइट्स को याद कर रहे हैं और दोनों स्ट्रिंग्स "फर्स्ट" और "सेकेंड" 10 बाइट्स से कम हैं, तो आप उनके पिछले अतिरिक्त बाइट्स की प्रतिलिपि बना रहे हैं।

1

memcpy(dest, src, n-1) के उपयोग अपरिभाषित व्यवहार का आह्वान करता है, तो dest और src दोनों कम से कम लंबाई में n-1 नहीं हैं।

उदाहरण के लिए, First\0 लंबाई में छह वर्ण हैं, लेकिन आप n-1 (9) वर्णों को पढ़ते हैं; स्ट्रिंग शाब्दिक के अंत से पहले स्मृति की सामग्री अपरिभाषित है, जैसा कि आप उस स्मृति को पढ़ते समय अपने प्रोग्राम का व्यवहार करते हैं।

0

अतिरिक्त "सामान" वहां है क्योंकि आपने बफर आकार memcpy पर पारित कर दिया है। यह उन कई पात्रों की प्रतिलिपि बनाने जा रहा है, भले ही स्रोत छोटा हो।

मैं चीजों को थोड़ा अलग तरीके से करते हैं:

void copy_string(char *dest, char const *src, size_t n) { 
    *dest = '\0'; 
    strncat(dest, src, n); 
} 

strncpy के विपरीत, strncat काम करने के लिए कैसे ज्यादातर लोगों यथोचित उम्मीद करेंगे परिभाषित किया गया है।

+0

लोग अक्सर 'strncat' को' strlcat' के रूप में काम करने की अपेक्षा करते हैं, यानी वे उम्मीद करते हैं कि यह लक्ष्य बफर की * पूर्ण * लंबाई ले, जबकि वास्तविकता में यह concatenation के लिए उपलब्ध लंबाई का * शेष * लेता है। – AnT

+0

आप वास्तव में 'if (n> 0) strncat (dest, src, n - 1)' (मानते हैं कि 'n' गंतव्य बफर का आकार है) चाहते हैं। – caf

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