2012-08-08 25 views
12

मेरे पास एक ऐसा फ़ंक्शन है जो एक फ़्लोटिंग पॉइंट सरणी में पॉइंटर लेता है। अन्य स्थितियों के आधार पर, मुझे पता है कि सूचक वास्तव में 2x2 या 3x3 मैट्रिक्स को इंगित कर रहा है। (वास्तव में स्मृति को प्रारंभ में आवंटित किया गया था, उदाहरण के लिए फ्लोट एम [2] [2]) महत्वपूर्ण बात यह है कि मैं फ़ंक्शन बॉडी में यह दृढ़ संकल्प करना चाहता हूं, फ़ंक्शन तर्क के रूप में नहीं।फिक्स्ड साइज की एक बहुआयामी-सरणी में सरल पॉइंटर कैसे डाला जाए?

void calcMatrix(int face, float * matrixReturnAsArray) 
{ 
    // Here, I would much rather work in natural matrix notation 
    if(is2x2) 
    { 
     // ### cast matrixReturnAsArray to somethingAsMatrix[2][2] 
     somethingAsMatrix[0][1] = 2.002; 
     // etc.. 
    } 
    else if(is3x3) 
    { //etc... 
    } 

} 

मुझे पता है कि मैं इस समस्या को बेहतर ढंग से संबोधित करने के लिए टेम्पलेट्स और अन्य तकनीकों का उपयोग कर सकता हूं। मेरा सवाल वास्तव में ### टिप्पणी पर इस तरह का कलाकार बनाने के बारे में है। सी ++ में काम करना

typedef float Matrix_t[2][2]; 

Matrix_t* someThingAsMatrix = (Matrix_t*) matrixReturnAsArray; 

इस सी ++ और नहीं सी है, हालांकि, आप एक मैट्रिक्स बनाने चाहिए:

+2

मुझे लगता है कि आप गलत समस्या को हल करने की कोशिश कर रहे हैं (यानी "कैसे डालना है?" * शायद ही कभी सही समस्या है)। मैंने "बहु-आयामी सरणी का आसानी से उपयोग कैसे करें" की समस्या का एक सरल समाधान लिखा है? एक बार: http://ideone.com/gytw7 –

+0

एक बहुआयामी * कुछ * के लिए 'फ्लोट *' अंक नहीं है (वास्तव में भयानक कास्टिंग को छोड़कर जो आपको नहीं करना चाहिए और मुझे आश्चर्य होगा अगर एक कंपाइलर चलो आप)। एक फ्लोट पर एक 'फ्लोट *' अंक, जो एकल-आयामी फ्लोट सरणी में पहला मान हो सकता है। लेकिन यह किसी भी उप-सरणी को इंगित नहीं करता है, क्योंकि आपको एक बहुआयामी सरणी की आवश्यकता होगी। 2x2 और 3x3 दोनों 2 डी हैं, इसलिए दोनों 'फ्लोट **' हो सकते हैं। वास्तव में, हालांकि, आप एक समर्पित 'मैट्रिक्स' कक्षा का निर्माण और उपयोग करने से बेहतर होगा (या खोज)। – KRyan

+0

ठीक है, मैं अपने इनपुट तर्क को फ्लोट ** में बदल सकता हूं।लेकिन क्या आप कह रहे हैं कि मामले में एएमडीएआरए [3] [3] तैरते हैं, तत्वों का भंडारण निरंतर होने की गारंटी नहीं है? – NoahR

उत्तर

20
float (*somethingAsMatrix)[2] = (float (*)[2]) matrixReturnAsArray; 
+0

धन्यवाद। यह निश्चित रूप से अब काम करता है। मैं सिर्फ स्पष्ट कर रहा हूं कि अगर घोषणा घोषणा मामले में तत्वों की गारंटीकृत संगत व्यवस्था के बारे में मुझे गलतफहमी है तो एमएमएड्रे [3] [3]; – NoahR

+1

@NoahR: यह आपके द्वारा सुझाए गए उपयोग के साथ संगत और संगत है। –

+0

मैंने इस तकनीक की कोशिश की और मैक ओएस एक्स सी ++ कंपाइलर ने कहा 'त्रुटि: असंगत प्रकार' डबल (*) [एलडीएन] 'से' डबल (*) [एलडीएन] 'को असाइन करना। ध्यान दें कि दो रिपोर्ट किए गए प्रकार समान हैं! तो वे असाइन करने योग्य क्यों नहीं हैं? मेरा कोड इस 'डबल (* एफ) [एलडीएन] जैसा दिखता है; एफ = (डबल (*) [एलडीएन]) एएफ; 'मैंने घोषणा में आरंभ करने की भी कोशिश की और एक ही त्रुटि संदेश मिला। – Jason

1

कास्टिंग इस तरह की हमेशा क्लीनर, और आसान typedef के विवेकपूर्ण उपयोग के साथ, से निपटने के लिए है कक्षा। (या बेहतर अभी तक, एक ओपन सोर्स एक के लिए देखो।)

+1

कुछ टिंगएसमैट्रिक्स का उपयोग करें [1] [1] = 2.0 एफ; देता है: 'फ्लोट' को 'फ्लोट [2]' – NoahR

+2

के असाइनमेंट में असंगत प्रकार अभी भी टाइपिफ़ीफ़ उपयोगी है, लेकिन आपको इसकी आवश्यकता है: 'टाइपपीफ फ्लोट मैट्रिक्सरो [2]; MatrixRow * someThingAsMatrix = (MatrixRow *) matrixReturnAsArray; 'जो ecatmur के उत्तर के बराबर है। –

4

float * फ्लोट की सरणी के पहले तत्व को इंगित कर सकता है, और उस सरणी प्रकार को reinterpret_castable होना चाहिए। और उस कास्ट का परिणाम float [][] के पहले तत्व को इंगित कर सकता है और इसलिए उस प्रकार के reinterpret_castable होना चाहिए, और इसी तरह। आप इस तरह के डाले रचना करने में सक्षम होना चाहिए और सिर्फ सीधे

float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(matrixReturnAsArray); 

प्रकार float ** का एक तर्क के समान नहीं है और इस तरह से नहीं किया जाना चाहिए है।

अपरिभाषित व्यवहार से बचने के लिए पॉइंटर को वास्तविक बहु-आयामी सरणी से उत्पन्न होना चाहिए, और यदि float* सीधे उपयोग किया जाता है तो आप बहु-आयामी मैट्रिक्स की पहली पंक्ति से अधिक तक नहीं पहुंच सकते हैं।

void foo(float *f) { 
    f[3] = 10.; 

    float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(f); 
    arr[1][1] = 10.; 
} 

void main() { 
    float a[2][2]; 
    foo(&a[0][0]); // f[3] = 10.; is undefined behavior, arr[1][1] = 10. is well defined 

    float b[4]; 
    foo(&b[0]); // f[3] = 10.; is well-defined behavior, arr[1][1] = 10. is undefined 
} 

को देखते हुए float arr[2][2]; कुछ भी नहीं गारंटी देता है कि &arr[0][1] + 1, &arr[1][0] रूप में ही है जहाँ तक मैं निर्धारित करने के लिए सक्षम है। तो यद्यपि आप f[i*width + j] कर एक बहु-आयामी सरणी के रूप में एक एकल आयामी सरणी का उपयोग कर सकते हैं, आप एक बहु-आयामी सरणी को एक आयामी सरणी जैसे इलाज नहीं कर सकते हैं।

गलत तरीके से गलत तरीके से गुजरने या गलत reinterpret_cast निष्पादित करने पर भरोसा करने के बजाय सी ++ की संकलन-समय प्रकार-सुरक्षा का उपयोग करना बेहतर है। कच्चे सरणियों का उपयोग कर आप कच्चे सरणी प्रकार आप चाहते हैं के लिए संदर्भ का उपयोग करना चाहिए प्रकार- सुरक्षा प्राप्त करने के लिए: यदि आप मूल्य से सरणियों पारित करने के लिए आप कच्चे सरणियों का उपयोग नहीं कर सकते हैं

void foo(float (&f)[2][2]) {} 
void foo(float (&f)[3][3]) {} 

और बदले एसटीडी की तरह कुछ का उपयोग करना चाहिए :: सरणी:

void foo(std::array<std::array<float,2>,2> f) {} 
void foo(std::array<std::array<float,3>,3> f) {} 
+1

'sizeof (टी [एन]) नहीं है 'बिल्कुल' N * sizeof (टी) 'होने की गारंटी है? –

+1

मुझे उस मानक में एक गैर-मानक नोट के बारे में पता है जो इसका उल्लेख करता है। यदि आप कुछ भी मानक पा सकते हैं तो कृपया मुझे बताएं। – bames53

+1

5.3.3p2 सीधे बताता है कि यह आवश्यक है। मेरे लिए मानदंड दिखता है ("नोट" के अंदर नहीं) –