मैं निम्नलिखित प्रश्न पर काम कर रहा हूं:

'सी' कोड लिखें जो एक संरचित प्रकार को परिभाषित करता है जिसे मॉड्यूलस्ट्रक्चर कहा जाता है, ऐसे सदस्यों के साथ जो मॉड्यूल के नाम को एक वर्ण सरणी के रूप में संग्रहीत करते हैं, मॉड्यूल को पूर्णांक के रूप में लेने वाले छात्रों की संख्या, मॉड्यूल को एक सूचक के रूप में लेने वाले छात्रों के नाम स्ट्रिंग्स की सरणी और फ्लोट्स की एक सरणी के रूप में संग्रहीत छात्रों के लिए परिणाम।

मैं अनिश्चित हूं कि छात्र संख्या को जाने बिना संरचना में एक फ्लोट सरणी कैसे हो, इसलिए मैंने अभी माना कि उनका मतलब फ्लोट सरणी के लिए सूचक था।

मैंने यही बनाया है:

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

typedef struct mS{
    char name[50];
    int studentNum;
    char (*studentNames)[50];
    float *studentGrades;
}moduleStruct;

void deleteModule(moduleStruct* ms);
void deleteModule(moduleStruct* ms){
    free(ms->studentNames);
    free(ms->studentGrades);
    free(ms);
}

int main(int argc, char* argv[])
{   moduleStruct* m1 = malloc(sizeof(moduleStruct));

    strcpy(m1->name, "Programming");

    m1 -> studentNum = 5;

    char students[][50]  = {"Alan", "Bob", "Charles", "James", "Peter"};
    m1 -> studentNames = malloc(sizeof(students));
    memcpy(m1 -> studentNames, &students, sizeof(students));

    float grades[5]= {1.1, 2.2, 3.3, 4.4, 5.5};
    m1->studentGrades = malloc(sizeof(grades));
    memcpy(m1->studentGrades, grades, sizeof(grades));

    printf("%s\n", m1->name);
    printf("%d\n", m1->studentNum);
    printf("%s\n", m1->studentNames[2]);
    printf("%f\n", m1->studentGrades[4]);

    deleteModule(m1);

    printf("%s\n", m1->name);
    return 0;
}

तो मेरे पास 3 प्रश्न हैं:

  1. क्या छात्र संख्या को जाने बिना सीधे फ्लोट सरणी का उपयोग करने का कोई तरीका है?
  2. इस समाधान को कैसे सुधारें?
  3. क्या कोई तरीका है जहां मुझे छात्र नामों में अधिकतम नाम आकार को पूर्व-परिभाषित करने की आवश्यकता नहीं है?
1
Mohamed Moustafa 4 पद 2019, 03:31
1
x = malloc(...); x = somethingelse; एक मेमोरी लीक है, आप मॉलोक ब्लॉक के बारे में भूल जाते हैं और अपने पॉइंटर को किसी और चीज़ पर इंगित करते हैं। इसके बजाय आप शायद मूल स्थान से डेटा को हीप स्टोरेज में कॉपी करना चाहते हैं
 – 
M.M
4 पद 2019, 04:16
@ एमएम संपादित कोड, क्या आप कृपया इसे देख सकते हैं?
 – 
Mohamed Moustafa
4 पद 2019, 04:26
1
आप अभी भी heapStudents के साथ वही समस्या करते हैं। साथ ही float studentGrades[]; float *studentGrades; होना चाहिए, जिस तरह से आप इसे वैसे भी इस्तेमाल कर रहे हैं
 – 
M.M
4 पद 2019, 04:27
@ एमएम हाँ, इसके लिए खेद है। मैं उन्हें संपादित करना भूल गया। संरचना में अधिकतम आकार तय किए बिना स्ट्रिंग सरणी के साथ काम करने का कोई तरीका है?
 – 
Mohamed Moustafa
4 पद 2019, 04:50

2 जवाब

सही बल्ले से:

main.c: In function 'main':
main.c:32:14: warning: format '%f' expects argument of type 'double', but argument 2 has type 'float *' [-Wformat=]
   32 |     printf("%f\n", m1->studentGrades);
      |             ~^     ~~~~~~~~~~~~~~~~~
      |              |       |
      |              double  float *
main.c:32:14: warning: format '%f' expects argument of type 'double', but argument 2 has type 'float *' [-Wformat=]

तो चलिए मान को प्रिंट करने के लिए इसे ठीक करते हैं। printf("%f\n", *m1->studentGrades);

Programming
5
Alan
1.100000

वह बेहतर है।


char* heapStudents = malloc(sizeof(students));
heapStudents = *students;
m1 -> studentNames = heapStudents;

यह सही नहीं लगता। आइए देखें कि क्या हो रहा है।

Breakpoint 2, main () at main.c:19
19          char students[][20]  = {"Alan", "Bob", "Charles", "James", "Peter"};
(gdb) s
20          char* heapStudents = malloc(sizeof(students));
(gdb) p students
$5 = {"Alan", '\000' <repeats 15 times>, "Bob", '\000' <repeats 16 times>, "Charles", '\000' <repeats 12 times>,
  "James", '\000' <repeats 14 times>, "Peter", '\000' <repeats 14 times>}
(gdb) x students
0x22fdd0:       0x6e616c41
(gdb) s
21          heapStudents = *students;
(gdb) s
22          m1 -> studentNames = heapStudents;
(gdb) p *heapStudents
$8 = 65 'A'
(gdb) x heapStudents
0x22fdd0:       0x6e616c41

आप स्टैक पर वर्ण सरणियों की एक सरणी आवंटित करते हैं (0x6e616c41 पर)। फिर आप ढेर पर समान मात्रा में स्मृति आवंटित करते हैं, और सूचक को *heapStudents के रूप में सहेजते हैं। फिर आप पॉइंटर को "पता" के साथ students कैरेक्टर ऐरे में 0वें एलिमेंट के डीकेड पॉइंटर के मान के बराबर ओवरराइट कर देते हैं, जिससे प्रक्रिया में malloc'd मेमोरी लीक हो जाती है। उफ़।

चलो इसे ठीक करते हैं।

m1->studentNames = malloc(sizeof(students));
memcpy(m1->studentNames, &students, sizeof(students));

अब हम मेमोरी आवंटित करते हैं और malloc द्वारा दिए गए पते को इंगित करने के लिए m1 द्वारा इंगित संरचना में *studentNames पॉइंटर असाइन करते हैं। फिर हम स्टैक ऐरे को हीप पर आवंटित मेमोरी में कॉपी करते हैं। हमने कोई मेमोरी लीक नहीं की है, क्योंकि हम बाद में free(m1->studentNames) पर कॉल कर सकते हैं।


studentGrades के लिए भी यही सुधार लागू किया जाना चाहिए। लेकिन चलो कुछ अलग करने की कोशिश करते हैं; पहले ढेर पर एक सरणी आवंटित किए बिना ढेर पर स्मृति आवंटित करना।

m1->studentGrades = malloc(sizeof(float[5]));
m1->studentGrades[0] = 1.1;
m1->studentGrades[1] = 2.2;
m1->studentGrades[2] = 3.3;
m1->studentGrades[3] = 4.4;
m1->studentGrades[4] = 5.5;

ध्यान दें कि हम सरणी अनुक्रमण का उपयोग float* studentGrades सूचक के साथ कर सकते हैं।


प्रश्नों पर उचित:

क्या छात्र संख्या को जाने बिना सीधे फ्लोट सरणी का उपयोग करने का कोई तरीका है?

छात्रों की अधिकतम संख्या को जाने बिना, आप अपने सरणियों को आरंभ करने के लिए #define MAX_STUDENTS 100 कर सकते हैं, फिर m1->studentNum का उपयोग पुनरावृति करने के लिए कर सकते हैं। या, स्टैक पर आवंटन करना छोड़ दें और केवल malloc(m1->studentNum * sizeof(var))/calloc(m1->studentNum, sizeof(var)); का उपयोग करें।

वैकल्पिक रूप से, आवश्यकता पड़ने पर realloc का उपयोग करें।

दूसरे छात्र के नाम का उपयोग कैसे करें?

अपनी संरचना परिभाषा बदलें ताकि आपके पास पॉइंटर्स की एक सरणी हो जो चरित्र सरणी को इंगित करे। char* studentNames[20]; 20 पॉइंटर्स रखने के लिए फिर अपने डेटा को हीप पर एक स्थान पर स्टोर करें, और पॉइंटर को स्ट्रक्चर के ऐरे मेंबर में सेव करें:

m1->studentNames[0] = strcpy(calloc(20, sizeof(char)), "Alan");
m1->studentNames[1] = strcpy(calloc(20, sizeof(char)), "Bob");
m1->studentNames[2] = strcpy(calloc(20, sizeof(char)), "Charles");
m1->studentNames[3] = strcpy(calloc(20, sizeof(char)), "James");
m1->studentNames[4] = strcpy(calloc(20, sizeof(char)), "Peter");

"बॉब" प्रिंट करने के लिए printf("%s\n", m1->studentNames[1]); का प्रयोग करें। आदि।

वैकल्पिक रूप से, संरचना में एक डबल पॉइंटर का उपयोग करें और इसे ढेर पर पॉइंटर्स की एक सरणी को इंगित करें। इस तरह से गतिशील रूप से 20-तत्व सीमा से ऊपर की मेमोरी आवंटित की जा सकती है।

फ़्लोट ऐरे में पॉइंटर को ठीक से कैसे सेट करें और प्रत्येक सदस्य तक कैसे पहुँचें?

यदि आपके पास संरचना में float studentGrades[20]; है, तो आप इस तरह एक सूचक बना सकते हैं

float *p = &m1->studentGrades[0];
printf("%f %f\n", p[0], p[1]); // prints 1.100000 2.200000

कुल मिलाकर:

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

typedef struct mS{
    char name[50];
    int studentNum;
    char* studentNames[20];
    float studentGrades[20];
} moduleStruct;

int main(void) {
    moduleStruct *m1 = malloc(sizeof(moduleStruct));

    strcpy(m1->name, "Programming");

    m1->studentNum = 5;

    //char students[][20]  = {"Alan", "Bob", "Charles", "James", "Peter"};
    m1->studentNames[0] = strcpy(calloc(20, sizeof(char)), "Alan");
    m1->studentNames[1] = strcpy(calloc(20, sizeof(char)), "Bob");
    m1->studentNames[2] = strcpy(calloc(20, sizeof(char)), "Charles");
    m1->studentNames[3] = strcpy(calloc(20, sizeof(char)), "James");
    m1->studentNames[4] = strcpy(calloc(20, sizeof(char)), "Peter");

    /*float grades[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
    m1->studentGrades = malloc(sizeof(grades));
    memcpy(m1->studentGrades, &grades, sizeof(grades));*/

    //m1->studentGrades[0] = malloc(sizeof(float[5]));
    m1->studentGrades[0] = 1.1;
    m1->studentGrades[1] = 2.2;
    m1->studentGrades[2] = 3.3;
    m1->studentGrades[3] = 4.4;
    m1->studentGrades[4] = 5.5;

    printf("%s\n", m1->name);
    printf("%d\n", m1->studentNum);
    printf("%s\n", m1->studentNames[0]);
    printf("%f\n", m1->studentGrades[0]);

    return 0;
}

संपादित करें

तो मेरे पास 2 प्रश्न हैं:

(प्रश्न 0 से 2 हो सकता है, लेकिन मैं निश्चित रूप से 3 देखता हूँ!)

क्या छात्र संख्या को जाने बिना सीधे फ्लोट सरणी का उपयोग करने का कोई तरीका है?

ऊपर देखो।

इस समाधान को कैसे सुधारें?

implicit declaration of function 'deleteModule' को हटाने के अलावा? निचे देखो।

क्या कोई तरीका है जहां मुझे छात्र नामों में अधिकतम नाम आकार को पूर्व-परिभाषित करने की आवश्यकता नहीं है?

क्या संरचना में पॉइंटर्स की एक सरणी के लिए एक पॉइंटर होता है। realloc यह सरणी हर बार जब आप किसी छात्र को जोड़ते हैं। छात्र के नाम को संग्रहीत करने के लिए एक malloc'd वर्ण सरणी पर इंगित करने के लिए सरणी में से एक पॉइंटर असाइन करें।

typedef struct mS{
    // ...
    char **studentNames;
}
// ...
char str[] = "Alan";
m1->studentNames = realloc(m1->studentNames, ++(m1->studentNum)*sizeof(*m1->studentNames);
m1->studentNames[m1->studentNum-1] = strcpy(calloc(strlen(str)+1, sizeof(char)), str);

नाम को स्टोर करने के लिए 5 बाइट्स आवंटित किए जाते हैं, और एक पॉइंटर का आकार (शायद 8B) नाम के पते को स्टोर करने के लिए m1->studentNames के स्थान पर जोड़ा जाता है।

1
LegendofPedro 4 पद 2019, 05:09
यदि 100 से अधिक छात्र हों तो क्या होगा? क्या इससे समस्या नहीं होगी? मैंने आपके द्वारा प्रदान की गई कुछ युक्तियों का उपयोग करने के लिए अपना प्रश्न कोड संपादित किया है। मैंने स्टैक सरणियों को मुख्य रूप से रखा क्योंकि वे बड़ी संख्या में छात्रों के उपयोग के लिए अधिक सुविधाजनक लगते हैं (बजाय एक-एक करके छात्र को m1->studentNames पर असाइन करने के)। मैंने एक डिलीट मॉड्यूल फ़ंक्शन भी जोड़ा। मैंने फ्लोट पॉइंटर का उपयोग किया क्योंकि यह अज्ञात संख्या में ग्रेड को संग्रहीत करने के लिए अधिक उपयुक्त लगता है।
 – 
Mohamed Moustafa
4 पद 2019, 05:08
मुद्दा यह है कि MAX_STUDENTS को आपकी आवश्यकता से अधिक होने के लिए परिभाषित किया जाए। समाधान ढेर से बचने और गतिशील रूप से (ढेर पर) सब कुछ आवंटित करना है। आप बड़ी संख्या में छात्रों को परिभाषित करने की संभावना नहीं रखते हैं क्योंकि उन्हें प्रोग्राम में हार्डकोड करने के बजाय फ़ाइल/स्टडिन/आदि से एक समय में एक (फ़ंक्शन के साथ?) जोड़ा जाएगा।
 – 
LegendofPedro
4 पद 2019, 05:11

आपके पास 2 दृष्टिकोण होंगे:

  1. या तो मान लें कि मॉड्यूल में अधिकतम क्षमता होगी (काफी यथार्थवादी, लेकिन शायद वह नहीं जो अभ्यास के लिए वांछित है)
  2. गतिशील रूप से आवंटित सरणियाँ, जिसमें आप आवश्यकतानुसार आवंटित करते हैं

अधिकतम (निश्चित) क्षमता

#define moduleCapacity 200
#define moduleMaxName 50

struct moduleStruct {
    char name[moduleMaxName];
    unsigned int studentsCount;
    const char *studentsName[moduleCapacity];
    float studentsGrade[moduleCapacity];
};
void populateModule(
    struct moduleStruct *target,
    const char *moduleName,
    const unsigned int studentsCount,
    const char* studentsName[],
    const float studentsGrade[]) {

    strncpy(target->name, moduleName, moduleMaxName);
    target->studentsCount = studentsCount;
    for(unsigned int i = 0; i < studentsCount; ++i) {
       if(i >= moduleCapacity) return; // student over the limit are thrown away, sorry first come first served basis
       target->studentsName[i] = studentsName[i];
       target->studentsGrade[i] = studentsGrade[i];
    }
}

void printModule(struct moduleStruct *input) {
    printf("name : %s\n", input->name);
    printf("students : %i\n", input->studentsCount);
    for(unsigned int i = 0; i < input->studentsCount; ++i) {
        printf("%u %s %f\n", i+1, input->studentsName[i], input->studentsGrade[i]);
    }
}

int main(int argc, char** argv) {
    struct moduleStruct m1;
    const char *names[] = {"Alan", "Bob", "Charles", "James", "Peter"};
    const float grades[] = {1.1f, 2.2f, 3.3f, 4.4f, 5.5f};
    populateModule(
        &m1,
        "Programming",
        5,
        names,
        grades
    );
    printModule(&m1);
}

गतिशील रूप से आवंटित सरणियाँ

#define moduleMaxName 50

struct moduleStruct {
    char name[moduleMaxName];
    unsigned int studentsCount;
    const char **studentsName;
    float *studentsGrade;
};


void populateModule(
    struct moduleStruct *target,
    const char *moduleName,
    const unsigned int studentsCount,
    const char* studentsName[],
    const float studentsGrade[]) {

    strncpy(target->name, moduleName, moduleMaxName);
    target->studentsCount = studentsCount;
    // we have the student count, we can allocate an array that is sized just for the class size
    target->studentsName = calloc(target->studentsCount, sizeof(char*)); 
    target->studentsGrade = calloc(target->studentsCount, sizeof(float));
    for(unsigned int i = 0; i < studentsCount; ++i) {
       target->studentsName[i] = studentsName[i];
       target->studentsGrade[i] = studentsGrade[i];
    }
}

// printModule & main remain the same
0
dvhh 4 पद 2019, 05:20