2015-11-03 12 views
5

मैं मूव के साथ तारों की एक सरणी कैसे जोड़ सकता हूं। मैंने कोशिश की लेकिन मैं समझ नहीं पा रहा हूं कि मूव ऑपरेशन को सही तरीके से कैसे काम करना है।मूव के साथ कई तारों को कैसे सम्मिलित करें?

program Project2; 

{$POINTERMATH ON} 

procedure Concat(var S: String; const A: Array of String); 
var 
    I, J: Integer; 
    Len: Integer; 
begin 
    Len := 0; 
    for I := 0 to High(A) do 
    Len := Len + Length(A[I]); 

    SetLength(S, Length(S) + Len); 

    for I := 0 to High(A) do 
    Move(PWideChar(A[I])[0], S[High(S)], Length(A[I]) * SizeOf(WideChar)); 
end; 

var 
    S: String; 
begin 
    S := 'test'; 
    Concat(S, ['test', 'test2', 'test3']); 
end. 
+0

RTL इस तरह के एक समारोह है। * System.pas * में '_LStrCatN' और इसके यूनिकोड समकक्ष देखें। जब आप एक ही कथन में तीन से अधिक तारों को जोड़ते हैं, तो संकलक स्वचालित रूप से उस फ़ंक्शन पर कॉल उत्पन्न करता है, जैसा कि 's1 + s2 + s3 + s4 + s5' में होता है। आरटीएल समारोह में एक ही इंटरफ़ेस नहीं है; यह एक सरणी के बजाय स्टैक पर तारों की अपनी सूची स्वीकार करता है। जब तक आप असेंबली लिखते हैं तब तक आप आरटीएल फ़ंक्शन को सीधे कॉल नहीं कर सकते। –

उत्तर

7

मैं बहुत की तरह इस समारोह लिखना चाहते हैं:

procedure Concat(var Dest: string; const Source: array of string); 
var 
    i: Integer; 
    OriginalDestLen: Integer; 
    SourceLen: Integer; 
    TotalSourceLen: Integer; 
    DestPtr: PChar; 
begin 
    TotalSourceLen := 0; 
    OriginalDestLen := Length(Dest); 
    for i := low(Source) to high(Source) do begin 
    inc(TotalSourceLen, Length(Source[i])); 
    end; 
    SetLength(Dest, OriginalDestLen + TotalSourceLen); 

    DestPtr := PChar(Pointer(Dest)) + OriginalDestLen; 
    for i := low(Source) to high(Source) do begin 
    SourceLen := Length(Source[i]); 
    Move(Pointer(Source[i])^, DestPtr^, SourceLen*SizeOf(Char)); 
    inc(DestPtr, SourceLen); 
    end; 
end; 

यह काफी है आत्म व्याख्यात्मक। जटिलताओं के कारण जटिलताएं होती हैं। रेंज जांच सक्षम होने पर रिक्त स्ट्रिंग के वर्णों को इंडेक्स करने का कोई भी प्रयास अपवादों का कारण बन जाएगा।

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

Move(Pointer(Source[i])^, DestPtr^, SourceLen*SizeOf(Char)); 

एक आश्चर्य हो सकता है तो क्या होता है Source[i] खाली है। उस स्थिति में Pointer(Source[i])nil है और आप पहुंच उल्लंघन की अपेक्षा कर सकते हैं। वास्तव में, कोई त्रुटि नहीं है क्योंकि तीसरे तर्क द्वारा निर्दिष्ट चाल की लंबाई शून्य है, और nil पॉइंटर वास्तव में कभी-कभी संदर्भित नहीं होता है।

टिप्पणी की दूसरी लाइन यहाँ है:

DestPtr := PChar(Pointer(Dest)) + OriginalDestLen; 

हम PChar(Pointer(Dest)) बजाय PChar(Dest) का उपयोग करें। उत्तरार्द्ध यह जांचने के लिए कोड आमंत्रित करता है कि Dest खाली है या नहीं, और यदि ऐसा होता है तो एक पॉइंटर को एक नल-टर्मिनेटर में मिलता है। हम उस कोड को निष्पादित करने से बचना चाहते हैं, और Dest में दिए गए पते को सीधे प्राप्त करें, भले ही यह nil हो।

+0

निबंध पॉइंटर्स की जांच के लिए सम्मिलन का उपयोग किया जा सकता है। – user15124

+4

कुछ भी जोर देने की आवश्यकता नहीं है। इस तरह लिखने का पूरा बिंदु यह है कि यह खाली तारों के साथ काम करता है। आप वैसे भी क्या जोर दे सकते हैं? कोड शून्य पॉइंटर्स स्वीकार करना चाहिए, वे वैध इनपुट हैं। –

+0

इसके अलावा पहले उत्तर 'कॉल @ UniqueStringU' और' पाश जो आगे प्रदर्शन में कमी होगी में कॉल @ UStrToPWChar' है! – user15124

3

दूसरा पाश में आप S पहले से ही सही आकार है कि सभी तत्वों के साथ भरा करने के लिए भूल जाते हैं, इसलिए आपको दूसरे चर का उपयोग करने के लिए Move

procedure Concat(var S: String; const A: Array of String); 
var 
    I, Len, Sum: Integer; 
begin 
    Len := 0; 
    for I := 0 to High(A) do 
    Inc(Len, Length(A[I])); 
    Sum := Length(S); 
    SetLength(S, Sum + Len); 
    for I := 0 to High(A) do 
    begin 
    if Length(A[I]) > 0 then 
     Move(A[I][1], S[Sum+1], Length(A[I]) * SizeOf(Char)); 
    Inc(Sum, Length(A[I])); 
    end; 
end; 

की गंतव्य पैरामीटर पता करने के लिए है स्रोत पैरामीटर को PWideChar कास्टिंग पूरी तरह से अनावश्यक है क्योंकि Move फ़ंक्शन प्रकार का पुराना सामान्य सिंटैक्स था टी आप जो कुछ भी चाहते हैं उसे पास करने की अनुमति देता है (बिना किसी प्रकार के पैरामीटर)।

+0

'[] 'नोटेशन का उपयोग करके' AnsiString' के पहले अक्षर तक पहुंचने से स्ट्रिंग खाली होने पर अपवाद बढ़ जाएगा। स्ट्रिंग को अनुक्रमणित करने से पहले या तो 'ए [आई] <> शून्य' या 'लंबाई (ए [आई])> 0' जांचें, या फिर इसके बजाय 'पेंसिखार' टाइपकास्ट का उपयोग करें (स्ट्रिंग खाली होने पर सुरक्षित है): 'पंसिहर (ए [मैं])^'। साथ ही, एक स्थानीय चर को उसी समय घोषित करने के रूप में प्रारंभ करना ('var Sum: Integer = 1;') डेल्फी में कानूनी नहीं है। आप 'एस' के मूल डेटा को शामिल करने के लिए' एस' को फिर से आवंटित कर रहे हैं, लेकिन मूल डेटा के अंत में 'Sum' शुरू नहीं कर रहे हैं, इसलिए आप इसे जोड़ने के बजाय इसे ओवरराइट करने जा रहे हैं। –

+0

@ उपयोगकर्ता15124: जब तक कि आवेषण अक्षम नहीं होते हैं, वह है। –

+0

@ user15124 यदि आप कोड फॉर्म का उपयोग करते हैं तो आपको जो जवाब मिल गया है, वह ठीक काम करेगा। –

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