मैं C में किसी फ़ंक्शन से कई मान कैसे लौटाऊं?


87

अगर मेरे पास एक फ़ंक्शन है जो एक परिणाम intऔर परिणाम पैदा करता है string, तो मैं उन दोनों को एक फ़ंक्शन से कैसे वापस कर सकता हूं?

जहां तक ​​मैं बता सकता हूं कि मैं केवल एक चीज वापस कर सकता हूं, जैसा कि फ़ंक्शन नाम से पहले के प्रकार से निर्धारित होता है।


6
तक stringकर क्या आपका मतलब है "मैं सी ++ उपयोग कर रहा हूँ और यह std::stringवर्ग" या "मैं सी का उपयोग कर रहा है और इस एक है char *सूचक या char[]सरणी।"
क्रिस लुत्ज

खैर, मेरे विशेष मामले में, वे दो ints थे: एक मैं क्या तुलना कर रहा था के 'स्कोर' के लिए, और एक जहां अधिकतम स्कोर पाया गया था के 'सूचकांक' के लिए। मैं एक स्ट्रिंग उदाहरण का उपयोग करना चाहता था यहाँ अधिक सामान्य मामले के लिए
टोनी स्टार्क

संदर्भ द्वारा स्ट्रिंग को पास करें और इंट को वापस दें। सबसे तेज़ तरीका। कोई संरचना की आवश्यकता है।
स्टीफन स्टीगर

1
एक ऐसा कार्य नहीं है जो 2 परिणाम देता है जो एक से अधिक कार्य करता है? अंकल बॉब क्या कहेंगे?
डंकन

जवाबों:


123

मुझे नहीं पता कि आपका क्या stringहै, लेकिन मैं यह मानने जा रहा हूं कि यह अपनी स्मृति का प्रबंधन करता है।

आपके पास दो समाधान हैं:

1: एक वापसी structजिसमें आपकी ज़रूरत के सभी प्रकार शामिल हैं।

struct Tuple {
    int a;
    string b;
};

struct Tuple getPair() {
    Tuple r = { 1, getString() };
    return r;
}

void foo() {
    struct Tuple t = getPair();
}

2: मानों को पास करने के लिए पॉइंटर्स का उपयोग करें।

void getPair(int* a, string* b) {
    // Check that these are not pointing to NULL
    assert(a);
    assert(b);
    *a = 1;
    *b = getString();
}

void foo() {
    int a, b;
    getPair(&a, &b);
}

जो आप उपयोग करने के लिए चुनते हैं वह काफी हद तक व्यक्तिगत पसंद पर निर्भर करता है जो आपको अधिक पसंद है।


7
मुझे लगता है कि यह इस बात पर अधिक निर्भर करता है कि रिटर्न मान कितने संबंधित हैं। यदि int एक त्रुटि कोड है और स्ट्रिंग एक परिणाम है, तो इन्हें एक संरचना में एक साथ नहीं रखा जाना चाहिए। वह मूर्खतापूर्ण है। उस स्थिति में, मैं इंट को वापस करूंगा और स्ट्रिंग को एक char *और size_tलंबाई के रूप में पास करूंगा जब तक कि फ़ंक्शन के लिए यह बिल्कुल महत्वपूर्ण नहीं है कि वह स्वयं स्ट्रिंग और / या वापस आ जाए NULL
क्रिस लुट्ज़

@ क्रिस मैं आपसे पूरी तरह सहमत हूं, लेकिन मुझे उन चरों के उपयोग शब्दार्थ का कोई अंदाजा नहीं है, जिनकी उन्हें जरूरत है।
ट्रैविस गोकेल

अच्छी बात क्रिस। मुझे लगता है कि एक और बात यह है कि मूल्य बनाम संदर्भ है। अगर मुझे गलती नहीं है कि मैं संरचना को लौटाने के लिए उदाहरण के रूप में दिखाया गया है, तो वापसी पर एक प्रति बनाई जाएगी, क्या यह सही है? (मैं C पर थोड़ा संकोची हूं) जबकि दूसरी विधि पास-पास-संदर्भ का उपयोग करती है और इस प्रकार अधिक मेमोरी आवंटित करने की आवश्यकता नहीं होती है। बेशक, सूचक के माध्यम से संरचना को लौटाया जा सकता है और उसी लाभ को साझा किया जा सकता है? (यह सुनिश्चित करने के लिए कि वह ठीक से याद कर रहा है और पाठ्यक्रम के सभी को आवंटित कर रहा है)
RTHarston

@ थूकविकेटर: सी में संदर्भ शब्दार्थ बिल्कुल नहीं है (जो कि C ++ के लिए अनन्य है), इसलिए सब कुछ एक मूल्य है। दो पॉइंटर्स सॉल्यूशन (# 2) एक फंक्शन में पॉइंटर्स की कॉपियाँ पास कर रहा है, जो getPairतब डेरेफेर होते हैं । आप जो कर रहे हैं उसके आधार पर (ओपी ने कभी स्पष्ट नहीं किया कि क्या यह वास्तव में एक सी सवाल है), आवंटन एक चिंता का विषय हो सकता है, लेकिन यह आमतौर पर सी ++ भूमि में नहीं है (वापसी मूल्य अनुकूलन यह सब बचाता है) और सी भूमि में, डेटा प्रतियां आमतौर पर स्पष्ट रूप से (के माध्यम से strncpyया जो कुछ भी) होती हैं।
ट्रैविस गोकेल

@TravisGockel सुधार के लिए धन्यवाद। मैं इस तथ्य का उल्लेख कर रहा था कि पॉइंटर्स का उपयोग किया जाता है, इसलिए यह मूल्यों की नकल नहीं कर रहा है, बस साझा करना जो पहले से ही आवंटित किया गया था। लेकिन आप यह कहने में सही हैं कि सी। में पास-बाय-रेफरेंस को ठीक से नहीं कहा जाता है और ज्ञान के अन्य महान सोने की डली के लिए भी धन्यवाद। मुझे भाषाओं के बारे में ये छोटी चीजें सीखना बहुत पसंद है। :)
RTHarston

10

Option 1: एक इंट और स्ट्रिंग के साथ एक संरचना की घोषणा करें और एक संरचनात्मक चर लौटाएं।

struct foo {    
 int bar1;
 char bar2[MAX];
};

struct foo fun() {
 struct foo fooObj;
 ...
 return fooObj;
}

Option 2: आप पॉइंटर के माध्यम से दो में से एक को पास कर सकते हैं और पॉइंटर के माध्यम से वास्तविक पैरामीटर में बदलाव कर सकते हैं और दूसरे को हमेशा की तरह वापस कर सकते हैं:

int fun(char **param) {
 int bar;
 ...
 strcpy(*param,"....");
 return bar;
}

या

 char* fun(int *param) {
 char *str = /* malloc suitably.*/
 ...
 strcpy(str,"....");
 *param = /* some value */
 return str;
}

Option 3विकल्प के समान 2. आप सूचक के माध्यम से दोनों को पास कर सकते हैं और फ़ंक्शन से कुछ भी नहीं लौटा सकते हैं:

void fun(char **param1,int *param2) {
 strcpy(*param1,"....");
 *param2 = /* some calculated value */
}

विकल्प 2 के संबंध में, आपको स्ट्रिंग की लंबाई में भी पास होना चाहिए। int fun(char *param, size_t len)
क्रिस लुत्ज

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

7

चूंकि आपका एक परिणाम प्रकार एक स्ट्रिंग है (और आप सी का उपयोग कर रहे हैं, सी ++ नहीं), मैं आउटपुट पैरामीटर के रूप में पॉइंटर्स पास करने की सलाह देता हूं। उपयोग:

void foo(int *a, char *s, int size);

और इसे इस तरह से कॉल करें:

int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);

सामान्य तौर पर, कॉलिंग फ़ंक्शन में आवंटन करना पसंद करते हैं, फ़ंक्शन के अंदर नहीं, ताकि आप अलग-अलग आवंटन रणनीतियों के लिए जितना संभव हो उतना खुला रह सकें।


6

दो अलग-अलग दृष्टिकोण:

  1. पॉइंटर द्वारा अपने रिटर्न मानों को पास करें, और फ़ंक्शन के अंदर उन्हें संशोधित करें। आप अपने कार्य को शून्य घोषित करते हैं, लेकिन यह संकेत के रूप में पारित मूल्यों के माध्यम से लौट रहा है।
  2. एक संरचना को परिभाषित करें जो आपके रिटर्न मूल्यों को एकत्र करता है।

मुझे लगता है कि # 1 थोड़ा अधिक स्पष्ट है कि क्या हो रहा है, हालांकि यदि आपके पास बहुत अधिक रिटर्न मान हैं तो यह थकाऊ हो सकता है। उस स्थिति में, विकल्प # 2 काफी अच्छी तरह से काम करता है, हालांकि इस उद्देश्य के लिए विशेष संरचनाएं बनाने में कुछ मानसिक उपरि शामिल हैं।


1
C में संदर्भ नहीं है ;-), हालांकि पोस्टर का उपयोग करने के बाद से string, यह C ++ मानने के लिए सुरक्षित हो सकता है ...
ट्रैविस Gockel

पूरी तरह से उस के बारे में भूल गया! मैंने पॉइंटर्स का उपयोग करने के लिए अपने उत्तर को संशोधित किया है, लेकिन मैं स्पष्ट रूप से बहुत लंबे समय तक सी ++ भूमि में रहा हूं। :)
जेम्स थॉम्पसन

6

एक संरचना बनाएं और दो मानों को अंदर सेट करें और संरचना चर वापस करें।

struct result {
    int a;
    char *string;
}

आपको char *अपने कार्यक्रम के लिए जगह आवंटित करनी होगी ।


3

अपने फ़ंक्शन पैरामीटर के रूप में पॉइंटर्स का उपयोग करें। फिर उन्हें कई मान वापस करने के लिए उपयोग करें।


2

फ़ंक्शन के संदर्भ में मापदंडों को पारित करके।

उदाहरण:

 void incInt(int *y)
 {
     (*y)++;  // Increase the value of 'x', in main, by one.
 }

इसके अलावा वैश्विक चर का उपयोग करके, लेकिन यह अनुशंसित नहीं है।

उदाहरण:

int a=0;

void main(void)
{
    //Anything you want to code.
}

4
void main(void)ओह यह कैसे बर्न्स!
क्रिस लुट्ज़

आपका मतलब क्या है? @ क्रिस लुत्ज़
Badr

6
mainएक स्थिति कोड वापस करना है। * निक्स के तहत, इसे घोषित करना अधिक सामान्य है int main(int argc, char *argv[]), मेरा मानना ​​है कि विंडोज में समान सम्मेलन हैं।
डंकन

2

एक दृष्टिकोण मैक्रोज़ का उपयोग करना है। इसे हेडर फ़ाइल में रखेंmultitype.h

#include <stdlib.h>

/* ============================= HELPER MACROS ============================= */

/* __typeof__(V) abbreviation */

#define TOF(V) __typeof__(V)

/* Expand variables list to list of typeof and variable names */

#define TO3(_0,_1,_2,_3) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2; TOF(_3) v3;
#define TO2(_0,_1,_2)    TOF(_0) v0; TOF(_1) v1; TOF(_2) v2;
#define TO1(_0,_1)       TOF(_0) v0; TOF(_1) v1;
#define TO0(_0)          TOF(_0) v0;

#define TO_(_0,_1,_2,_3,TO_MACRO,...) TO_MACRO

#define TO(...) TO_(__VA_ARGS__,TO3,TO2,TO1,TO0)(__VA_ARGS__)

/* Assign to multitype */

#define MTA3(_0,_1,_2,_3) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2; _3 = mtr.v3;
#define MTA2(_0,_1,_2)    _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2;
#define MTA1(_0,_1)       _0 = mtr.v0; _1 = mtr.v1;
#define MTA0(_0)          _0 = mtr.v0;

#define MTA_(_0,_1,_2,_3,MTA_MACRO,...) MTA_MACRO

#define MTA(...) MTA_(__VA_ARGS__,MTA3,MTA2,MTA1,MTA0)(__VA_ARGS__)

/* Return multitype if multiple arguments, return normally if only one */

#define MTR1(...) {                                                           \
    typedef struct mtr_s {                                                    \
      TO(__VA_ARGS__)                                                         \
    } mtr_t;                                                                  \
    mtr_t *mtr = malloc(sizeof(mtr_t));                                       \
    *mtr = (mtr_t){__VA_ARGS__};                                              \
    return mtr;                                                               \
  }

#define MTR0(_0) return(_0)

#define MTR_(_0,_1,_2,_3,MTR_MACRO,...) MTR_MACRO

/* ============================== API MACROS =============================== */

/* Declare return type before function */

typedef void* multitype;

#define multitype(...) multitype

/* Assign return values to variables */

#define let(...)                                                              \
  for(int mti = 0; !mti;)                                                     \
    for(multitype mt; mti < 2; mti++)                                         \
      if(mti) {                                                               \
        typedef struct mtr_s {                                                \
          TO(__VA_ARGS__)                                                     \
        } mtr_t;                                                              \
        mtr_t mtr = *(mtr_t*)mt;                                              \
        MTA(__VA_ARGS__)                                                      \
        free(mt);                                                             \
      } else                                                                  \
        mt

/* Return */

#define RETURN(...) MTR_(__VA_ARGS__,MTR1,MTR1,MTR1,MTR0)(__VA_ARGS__)

यह एक फ़ंक्शन से चार चर तक लौटने और उन्हें चार चर तक असाइन करना संभव बनाता है। एक उदाहरण के रूप में, आप उन्हें इस तरह से उपयोग कर सकते हैं:

multitype (int,float,double) fun() {
    int a = 55;
    float b = 3.9;
    double c = 24.15;

    RETURN (a,b,c);
}

int main(int argc, char *argv[]) {
    int x;
    float y;
    double z;

    let (x,y,z) = fun();

    printf("(%d, %f, %g\n)", x, y, z);

    return 0;
}

यह वह है जो यह प्रिंट करता है:

(55, 3.9, 24.15)

समाधान उतना पोर्टेबल नहीं हो सकता क्योंकि इसके लिए C99 या बाद में वैरिएड मैक्रोज़ और फॉर-स्टेटमेंट वेरिएबल डिक्लेरेशन की आवश्यकता होती है। लेकिन मुझे लगता है कि यहां पोस्ट करना काफी दिलचस्प था। एक और मुद्दा यह है कि संकलक आपको चेतावनी नहीं देगा यदि आप उन्हें गलत मान देते हैं, तो आपको सावधान रहना होगा।

अतिरिक्त उदाहरण, और यूनियनों का उपयोग करके कोड का एक स्टैक-आधारित संस्करण, मेरे गितुब भंडार में उपलब्ध है


1
एक बड़ी पोर्टेबिलिटी समस्या गैर-मानक विशेषता है__typeof__
एमएम

टाइपोफ के बजाय, आप शायद आकार का उपयोग कर सकते हैं। रिटर्न मानों का आकार प्राप्त करें और उन सभी को संग्रहीत करने के लिए पर्याप्त रूप से एक सरणी आवंटित करें। तब आप इसे वापस कर सकते हैं।
क्लैस। S
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.