मूल रूप से मैं मदद करने के लिए एनम और एक नए फ़ंक्शन का उपयोग करके अपने कोड में डुप्लिकेट को हटाने का प्रयास कर रहा हूं।

मान लें कि मेरे पास निम्नलिखित के साथ एक संरचना है:

typedef struct user {
    bool empty;
    int lineNumber;
    char *errMessage;
    char *username;
    char *password;
    char *uid;
    char *gid;
    char *gecos;
    char *dir;
    char *shell;
} user;

और मैं निम्नलिखित की तरह एक एनम बना देता हूं:

typedef enum {username, password, uid, gid, gecos, dir, shell} userValue;

मैं जो करने की कोशिश कर रहा हूं वह एक फ़ंक्शन में पैरामीटर userValue enumParam भेजता है और उसके द्वारा संरचना में किस सदस्य को मैं एक्सेस करना चाहता हूं। सहायक समारोह का उदाहरण:

void parseHelper(userValue enumParam) {
    user *newStruct;
    newStruct -> enumParam = "hello";
}

उपयोग का उदाहरण:

parseHelper(password)

Expected: newStruct->password should point to "hello"

लेकिन यह मदद नहीं कर रहा है क्योंकि मुझे निम्न त्रुटि प्राप्त होती है:

'उपयोगकर्ता {उर्फ संरचना उपयोगकर्ता}' में 'वैल' नाम का कोई सदस्य नहीं है

1
Cows42 2 सितंबर 2017, 19:57

5 जवाब

सबसे बढ़िया उत्तर

नहीं मेरे दोस्त।

Enums केवल पूर्णांक हैं, वे कोई स्ट्रिंग प्रतिस्थापन नहीं हैं :)

3
P__J__ 2 सितंबर 2017, 19:59

मेरे पास आपके लिए एक प्रस्ताव है।

सबसे पहले, अपनी enum सूची (userValue_max) में एक अंतिम आइटम जोड़ें:

typedef enum {username, password, uid, gid, gecos, dir, shell, userValue_max} userValue;  

अब, अपने struct को थोड़ा अलग तरीके से परिभाषित करें, जिसमें स्ट्रिंग्स की एक सरणी है:

typedef struct user
{
    bool empty;
    int lineNumber;
    char *errMessage;
    char *field[userValue_max];
} user;  

अब अपना कोड इस प्रकार लिखें:

void parseHelper(userValue enumParam) {
    user *newStruct = malloc(sizeof(user)); // Allocating memory here!!
    newStruct->field[enumParam] = "hello";
}  
2
pablo1977 2 सितंबर 2017, 21:13

जिस तरह से मैं इसके बारे में जाऊंगा वह फ़ंक्शन पॉइंटर्स का उपयोग कर रहा है। यह बहुत साफ समाधान नहीं है लेकिन इसे काम करना चाहिए ..

मूल रूप से इस समाधान में एनमों को उसी क्रम में होना चाहिए जिसमें चार पॉइंटर्स को संरचना के भीतर परिभाषित किया गया हो। (मैं उन्हें इस तरह की संरचना में इंडेक्स में मैन्युअल रूप से सेट करना पसंद करूंगा:

typedef enum {
    username = 0, 
    password = 1,
    uid = 2,
    gid = 3,
    gecos = 4,
    dir = 5,
    shell = 6
} userValue;

अब एनम को संरचना (उपयोगकर्ता नाम) में एनम द्वारा दर्शाए गए पहले चार * से एक इंडेक्स के रूप में इस्तेमाल किया जा सकता है। यह चार * के लिए एक सूचक प्राप्त करके किया जा सकता है और सूचक अंकगणित का उपयोग करके इसे बढ़ा सकता है।

पूर्ण कोड उदाहरण (सही निष्पादन की पुष्टि करने के लिए प्रयुक्त डिबगर):

#include <string.h>

typedef struct user
{
    bool empty;
    int lineNumber;
    char *errMessage;
    char *username;
    char *password;
    char *uid;
    char *gid;
    char *gecos;
    char *dir;
    char *shell;
} user;

typedef enum { 
    username = 0,
    password = 1,
    uid = 2,
    gid = 3,
    gecos = 4,
    dir = 5,
    shell = 6
} userValue;

void parseHelper(userValue enumParam)
{
    user newStruct;
    memset(&newStruct, 0, sizeof(user));

    char** selected = &newStruct.username;
    selected = (char**)(selected + ((int)enumParam));
    *selected = "hello";
}

int main()
{
    parseHelper(username);
    parseHelper(password);
    parseHelper(uid);
    parseHelper(gid);
    parseHelper(gecos);
    parseHelper(dir);
    parseHelper(shell);
    return 0;
}

-संपादित करें हो सकता है कि एक ही परिणाम प्राप्त करने का एक अधिक पठनीय तरीका पहले char* (इस मामले में उपयोगकर्ता नाम) को char* की एक सरणी में डालना है, और मानक सरणी सिंटैक्स का उपयोग करके वांछित ऑफसेट पर जाने के लिए

void parseHelper(userValue enumParam)
{
    user newStruct;
    memset(&newStruct, 0, sizeof(user));

    // Other fields is an array of char * which starts at username...
    char** otherFields = &newStruct.username;
    otherFields[(int)enumParam] = "hello";
}

-- विकल्प 2

यदि आप संरचना परिभाषा को संशोधित करने में सक्षम हैं, और कहीं और आप विशेष रूप से उनके नाम से तारों तक पहुंचना चाहते हैं (उदाहरण के लिए user->username), तो आप अपनी संरचना में चार पॉइंटर्स की एक सरणी घोषित कर सकते हैं जैसे:

typedef struct user
{
    bool empty;
    int lineNumber;
    char *otherFields[7];
    // otherFields[0] - username
    // otherFields[1] - password
    // otherFields[2] - uid
    // otherFields[3] - gid
    // otherFields[4] - gecos
    // otherFields[5] - dir
    // otherFields[6] - shell
} user;

और फिर अनुक्रमणिका से सरणी का उपयोग करके आवश्यकतानुसार भरें:

void parseHelper(userValue enumParam)
{
    user newStruct;
    memset(&newStruct, 0, sizeof(user));

    newStruct.otherFields[enumParam] = "hello";
}

हुड के तहत, यह समाधान पहले वाले के समान है। हालांकि, इसमें वांछित char* तक पहुंचने के लिए एनम के उपयोग को सरल बनाने का अतिरिक्त लाभ है, जबकि शेष कोड में किसी विशेष स्ट्रिंग तक पहुंचने के लिए स्ट्रिंग नाम का उपयोग करने का लाभ खो देता है।

1
Brian Zammit 3 सितंबर 2017, 01:51

-> ऑपरेटर एक पॉइंटर के सदस्य चर को एक संरचना में एक्सेस करने के लिए है। महत्वपूर्ण बात यह है कि इन सदस्य चर के नाम भिन्न नहीं हो सकते हैं। घोषणा पत्र में आपने उन्हें जिस भी नाम से पुकारा है, आप उन्हें उसी नाम से पुकारें।

यहां आप 'वैल' नाम के सदस्य चर का उपयोग करने का प्रयास कर रहे हैं, लेकिन ऐसा कोई सदस्य चर नहीं है। इसलिए त्रुटि।

इस फ़ंक्शन में आपको संरचना के संभावित नामों से मेल खाने के लिए शर्तों के तहत एनम के संभावित मूल्यों को रखना होगा।

0
Alex Morrison 2 सितंबर 2017, 20:11

आप वह नहीं कर सकते जो आप सीधे दिखाने की कोशिश कर रहे हैं जैसा कि आप दिखाते हैं क्योंकि गणना स्थिरांक पूर्णांक के नाम हैं, संरचना सदस्यों के नाम नहीं। आप सदस्य नाम की पहचान करने के लिए किसी भी प्रकार के चर का उपयोग करके संरचना सदस्य का संदर्भ सीधे नहीं लिख सकते हैं - आपको स्पष्ट रूप से एक सदस्य का नाम देना चाहिए (इसलिए यह संरचना में एक हार्ड-वायर्ड ऑफसेट है)।

हालांकि, मान लें कि आपके पास अज्ञात संघ और संरचना सदस्यों के लिए आपके कंपाइलर में सी 11 समर्थन है, और यह मानते हुए कि आप संरचना प्रकार को फिर से परिभाषित कर सकते हैं (यह पूरी तरह से निश्चित और अचल नहीं है, कुछ बाहरी बल, जैसे ट्यूटर या ए द्वारा पूर्व-निर्धारित) मानक), आप इस तरह के कोड के साथ जो चाहते हैं उसके काफी करीब पहुंच सकते हैं:

#include <stdio.h>
#include <stdbool.h>

typedef struct user
{
    bool empty;
    int lineNumber;
    char *errMessage;
    union
    {
        struct
        {
            char *username;
            char *password;
            char *uid;
            char *gid;
            char *gecos;
            char *dir;
            char *shell;
        };
        char *field[7];
    };
} user;

typedef enum {username, password, uid, gid, gecos, dir, shell} userValue;

static void parseHelper(user *u, userValue enumParam, char *value)
{
    u->field[enumParam] = value;
}

int main(void)
{
    user u;
    u.empty = false;
    u.lineNumber = 1;
    u.errMessage = "no error";
    parseHelper(&u, password, "secret");
    parseHelper(&u, username, "me");
    parseHelper(&u, uid, "0");
    parseHelper(&u, gid, "1");
    parseHelper(&u, gecos, "Yours Truly");
    parseHelper(&u, dir, "/home/me");
    parseHelper(&u, shell, "/bin/sea");

    printf("%s:%s:%s:%s:%s:%s:%s\n", u.username,
           u.password, u.uid, u.gid, u.gecos, u.dir, u.shell);
    return 0;
}

चलाते समय, यह आउटपुट उत्पन्न करता है:

me:secret:0:1:Yours Truly:/home/me:/bin/sea

ऐसे कई कारक हैं जो यह काम करते हैं।

  1. संरचना सदस्य नाम अलग नाम रिक्त स्थान में हैं, इसलिए गणना तत्व नाम संरचना सदस्य नामों में हस्तक्षेप नहीं करते हैं।
  2. आप जिन सभी क्षेत्रों का इलाज करने का प्रयास कर रहे हैं वे एक ही प्रकार के हैं (char *)।
  3. जब आपके पास किसी संरचना में एक अनाम संघ होता है, तो आप संघ के तत्वों को नाम से एक्सेस कर सकते हैं।
  4. जब आपके पास एक संघ के भीतर एक अनाम संरचना होती है, तो आप संरचना के भीतर के तत्वों को नाम से एक्सेस कर सकते हैं।

यदि आप C90 या C99 के साथ फंस गए हैं, तो आप एक समान प्रभाव प्राप्त कर सकते हैं, लेकिन यह अधिक क्रियात्मक है:

#include <stdio.h>
#include <stdbool.h>

typedef struct user
{
    bool empty;
    int lineNumber;
    char *errMessage;
    union
    {
        struct
        {
            char *username;
            char *password;
            char *uid;
            char *gid;
            char *gecos;
            char *dir;
            char *shell;
        } f;
        char *field[7];
    } u;
} user;

typedef enum {username, password, uid, gid, gecos, dir, shell} userValue;

static void parseHelper(user *u, userValue enumParam, char *value)
{
    u->u.field[enumParam] = value;
}

int main(void)
{
    user u;
    u.empty = false;
    u.lineNumber = 1;
    u.errMessage = "no error";
    parseHelper(&u, password, "secret");
    parseHelper(&u, username, "me");
    parseHelper(&u, uid, "0");
    parseHelper(&u, gid, "1");
    parseHelper(&u, gecos, "Yours Truly");
    parseHelper(&u, dir, "/home/me");
    parseHelper(&u, shell, "/bin/sea");

    printf("%s:%s:%s:%s:%s:%s:%s\n", u.u.f.username, u.u.f.password,
           u.u.f.uid, u.u.f.gid, u.u.f.gecos, u.u.f.dir, u.u.f.shell);
    return 0;
}

यह निश्चित रूप से वही आउटपुट उत्पन्न करता है।

0
Jonathan Leffler 2 सितंबर 2017, 21:13