سؤال

أحاول إنشاء دالة التي تأخذ مجموعة كحجة ، إضافة القيم إلى ذلك (زيادة حجمها إذا لزم الأمر) وإرجاع عدد من البنود.حتى الآن لدي:

int main(int argc, char** argv) {
    int mSize = 10;
    ent a[mSize];
    int n;
    n = addValues(a,mSize);

    for(i=0;i<n;i++) {
       //Print values from a
    }
}

int addValues(ent *a, int mSize) {
    int size = mSize;

    i = 0;

    while(....) { //Loop to add items to array
        if(i>=size-1) { 
            size = size*2;
            a = realloc(a, (size)*sizeof(ent));
        }
        //Add to array
        i++;
    }
    return i;
}

يعمل هذا إذا mSize هو كبير بما يكفي لاحتواء كل إمكانات عناصر المصفوفة, ولكن إذا كان يحتاج تغيير الحجم ، أحصل على خطأ تجزئة.

كما أنني حاولت:

int main(int argc, char** argv) {
    ...
    ent *a;
    ...
}

int addValues(ent *a, int mSize) {
    ...
    a = calloc(1, sizeof(ent);
    //usual loop
    ...
}

ولكن دون جدوى.

أفترض أن هذا هو لأنه عندما اتصل realloc ، نسخة من 'a' هو أشار في مكان آخر - كيف يمكن تعديل هذا بحيث 'a' يشير دائما إلى نفس الموقع ؟

أنا ذاهب عن هذا بشكل صحيح ؟ هل هناك طرق أفضل للتعامل مع الهياكل الديناميكية في C ؟ يجب أن يكون تنفيذ قائمة مرتبطة للتعامل مع هذه ؟

هل كانت مفيدة؟

المحلول

والمشكلة الرئيسية هنا هي أن تحاول استخدام realloc مع صفيف المخصصة المكدس. لديك:

ent a[mSize];

وهذا التخصيص التلقائي على المكدس. إذا كنت تريد استخدام realloc () عن ذلك لاحقا، فإن إنشاء مجموعة على malloc كومة باستخدام ()، مثل هذا:

ent *a = (ent*)malloc(mSize * sizeof(ent));

وهكذا إلى أن مكتبة malloc (وبالتالي realloc ()، وما إلى ذلك) يعرف عن مجموعة الخاصة بك. من ينظر الى ذلك، قد يكون مربكا C99 طول متغير صفائف ، لذلك تأكد من أنك تفهم الفرق هناك قبل محاولة إصلاح هذا.

وحقا، رغم ذلك، إذا كنت تكتب المصفوفات الحيوية في C، عليك أن تحاول استخدام تصميم OOP العش لتغليف المعلومات حول صفائف وإخفائه من المستخدم. تريد توحيد المعلومات (مثل المؤشر وحجم) حول مجموعة الخاص بك إلى البنية والعمليات (مثل تخصيص، إضافة عناصر، وإزالة العناصر، تحرير، الخ) في وظائف خاصة التي تعمل مع البنية الخاصة بك. لذلك قد يكون لديك:

typedef struct dynarray {
   elt *data;
   int size;
} dynarray;

وكنت قد تحدد بعض الوظائف للعمل مع dynarrays:

// malloc a dynarray and its data and returns a pointer to the dynarray    
dynarray *dynarray_create();     

// add an element to dynarray and adjust its size if necessary
void dynarray_add_elt(dynarray *arr, elt value);

// return a particular element in the dynarray
elt dynarray_get_elt(dynarray *arr, int index);

// free the dynarray and its data.
void dynarray_free(dynarray *arr);

وهذه الطريقة لا يكون لدى المستخدم أن يتذكر بالضبط كيفية تخصيص الأشياء أو ما حجم المصفوفة في الوقت الراهن. نأمل أن يحصل على انك بدأته.

نصائح أخرى

وحاول إعادة صياغة بحيث مؤشر إلى مؤشر إلى مجموعة يتم تمريرها في، أي ent **a. فإنك سوف تكون قادرا على تحديث المتصل على الموقع الجديد للمجموعة.

هذا هو لطيف سبب لاستخدام OOP.نعم ، يمكنك أن تفعل OOP على ج ، حتى أنها تبدو جميلة إذا فعلت بشكل صحيح.

في هذه الحالة بسيطة لا تحتاج الميراث ولا تعدد الأشكال فقط التغليف وطرق المفاهيم:

  • تحديد هيكل مع طول بيانات المؤشر.ربما عنصر الحجم.
  • كتابة جالبة/واضع الوظائف التي تعمل على مؤشرات إلى أن البنية.
  • إن 'تنمو' وظيفة تعديل بيانات المؤشر داخل البنية ، ولكن أي البنية المؤشر يبقى ساري المفعول.

إذا قمت بتغيير تعريف متغير في main أن يكون

ent *a = NULL;

ورمز ستعمل أكثر وكأنك تصور من خلال عدم تحرير صفيف المخصصة المكدس. وضع لNULL يعمل لأن يعامل realloc هذا كما لو أن المستخدم يسمى malloc (حجم). نضع في اعتبارنا أنه مع هذا التغيير، النموذج الأولي لادفاليو يحتاج إلى تغيير ل

int addValues(ent **a, int mSize)

وهذا رمز يحتاج إلى معالجة حالة الفشل realloc. على سبيل المثال

while(....) { //Loop to add items to array
    tmp = realloc(*a, size*sizeof(ent));
    if (tmp) {
        *a = tmp;
    } else {
        // allocation failed. either free *a or keep *a and
        // return an error
    }
    //Add to array
    i++;
}

وأتوقع أن معظم تطبيقات realloc ستخصص داخليا مرتين قدر الذاكرة إذا كان المخزن المؤقت الحالي يحتاج تغيير حجم مما يجعل رمز الأصلي

size = size * 2;

لا لزوم لها.

ويتم تمرير مؤشر مجموعة من حيث القيمة. ما يعنيه هذا هو:

int main(int argc, char** argv) {
    ...
    ent *a; // This...
    ...
}

int addValues(ent *a, int mSize) {
    ...
    a = calloc(1, sizeof(ent); // ...is not the same as this
    //usual loop
    ...
}

وحتى تغيير قيمة في وظيفة addValues لا يغير قيمة في main. لتغيير قيمة في main تحتاج إلى تمرير إشارة إلى أن addValues. في الوقت الراهن، يتم نسخ قيمة وتمريرها إلى addValues. لتمرير إشارة إلى استخدام:

int addValues (int **a, int mSize)

ووالذي يطلق عليه مثل:

int main(int argc, char** argv) {
    ...
    ent *a; // This...
    ...
    addValues (&a, mSize);
}

في لaddValues، والوصول إلى عناصر مثل هذا:

(*a)[element]

ووإعادة تخصيص مجموعة مثل هذا:

(*a) = calloc (...);

وXahtep يفسر كيف يتصل بك يمكن أن تتعامل مع حقيقة أن realloc () قد نقل مجموعة إلى موقع جديد. طالما كنت تفعل هذا، يجب أن يكون على ما يرام.

وrealloc () قد تحصل مكلفة إذا كنت بدء العمل مع صفائف كبيرة. وذلك عندما حان الوقت لبدء التفكير في استخدام هياكل البيانات الأخرى - قائمة مرتبطة، شجرة ثنائية، الخ

وكما ذكرتم يجب تمرير المؤشر إلى مؤشر لتحديث قيمة المؤشر.
ولكن أود أن أقترح إعادة تصميم وتجنب هذه التقنية، في معظم الحالات، يمكن ويجب تجنبها. دون أن يعرفوا بالضبط ما كنت تحاول تحقيق ذلك من الصعب أن أقترح تصميم بديل، ولكن أنا متأكد من 99٪ أنها طريقة أخرى قابلة للتنفيذ. وكما خافيير حزين - اعتقد الشيئية وسوف تحصل دائما على أفضل مدونة.

هل مطلوب فعلا لاستخدام C؟ وهذا من شأنه أن يكون الطلب الكبير من C ++ الصورة "الأمراض المنقولة جنسيا :: ناقلات"، وهو بالتحديد مجموعة حيوي الحجم (resizeble بسهولة مع مكالمة واحدة لم يكن لديك لكتابة وتصحيح نفسك).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top