أعضاء صفيف الكتابة فوق العنصر الأخير

StackOverflow https://stackoverflow.com/questions/895628

  •  23-08-2019
  •  | 
  •  

سؤال

مع القطعة التالية من التعليمات البرمجية، أحصل على نتيجة Wierd للغاية. لماذا يتم كتابة قيمة العنصر الأخير جميع عناصر الصفيف السابقة؟ أظن أن هناك مشكلة أكبر من هذه المشكلة المنحة.

#include <stdio.h>

main()
{
    int i, cases;
    char num[1000000];

    scanf("%d", &cases);
    char* array[cases];

    //store inputs in array
    for(i=0; i<cases; i++)
    {
        scanf("%s", &num);
        array[i] = &num;
    }

    //print out array items and their memory addresses
    for(i=0; i<cases; i++)
    {
        printf("%d %s\n", i, array[i]);  //print (array index) (array value) 
        printf("%d %p\n", i, &array[i]); //print (array index) (array address) 
    }
}

Inputs:
3 <-- number of lines to follow
0   <-- put in array[0]
1   <-- put in array[1]
2   <-- put in array[2]

Outputs
0 3         <-- why is this being overwritten with the last element?
0 0013BCD0
1 3         <-- why is this being overwritten with the last element?
1 0013BCD4
2 3
2 0013BCD8

لا يوجد حل صحيح

نصائح أخرى

upshot هنا هو الخط array[i] = &num; أنت تحدد قيمة array[i] عنصر لمعلومات num مجموعة مصفوفة؛ حيث array هل صفيف شار، أظن أنه اقتطاع num عنوان الصفيف، والبايت منخفضة الترتيب يحدث فقط ليكون 3.

ومع ذلك. ومع ذلك، فإن char num [1000000] هو شكل بشدة، ويجب ألا تفعل ذلك، على الإطلاق. تخصيص على كومة، واختيار عدد أصغر، من أجل السماء. أيضا، لن يمنحك Scanf ("٪ s"، & num) بالفعل ما تريد. هنا تلميح؛ استخدم حلقة Getc () لقراءة الأرقام؛ هذا يتجنب الحاجة إلى القيام بأي بائع محام من مجموعة SCANF ().

ذلك لأنك تضع كل فهرس من الصفيف نفس العنوان (عنوان Char Num [1000000]؛).

إنه خطأ سيقودك إلى تخصيص ديناميكي (Calloc، Malloc، الجديد، إلخ).

هتافات!

داخل حلقة الأولى الخاصة بك، يجب أن تكون (لكنك لست) تكتب كل مدخلات في عنصر مختلف في صفيف الأسطوانات؛ بدلا من ذلك، كنت دائما تكتب إلى نفس المكان، أي &num.

char * صفيف [الحالات]؛

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

يستبدل

//store inputs in array
for(i=0; i<cases; i++)
{
    scanf("%s", &num);
    array[i] = &num;
}

مع

array[0] = num;
//store inputs in array
for(i=0; i<cases; i++)
{
    scanf("%s", array[i]);
    array[i+1] = array[i] + strlen(array[i]) + 1;
}

لمسح كل سلسلة في المساحة الأولى المتاحة في num[], ، وتعيين العنصر التالي من array[] للإشارة إلى المساحة المتاحة التالية. الآن لك printf() من السلاسل سوف تعمل. الأصلي كان مسح كل سلسلة في بداية num[].

ملحوظة: scanf() مع unadorned %s هو سيء كما gets(), ، لأنه لا يضع حد لكمية البيانات التي سيتم تخفيفها. لا تستخدمه في التعليمات البرمجية الحقيقية.

يستبدل

    printf("%d %p\n", i, &array[i]); //print (array index) (array address) 

مع

    printf("%d %p\n", i, (void*)(array[i])); //print (array index) (array address) 

لطباعة العناوين فعلا المخزنة في a[], ، بدلا من عناوين عناصر a[]. وبعد يلقي المطلوب لأن %p تتوقع مؤشر-إلىvoid لذلك يجب عليك تقديم واحدة.

هذا هو الرمز الخاص بك هو ثابت:

#include <stdio.h>

main(void)
{
    int i, cases;

    scanf("%d", &cases);
    char* array[cases];

    //store inputs in array
    for(i=0; i<cases; i++)
    {
        char *num = malloc(100000);
        scanf("%s", num);
        array[i] = num;
    }

    //print out array items and their memory addresses
    for(i=0; i<cases; i++)
    {
        printf("%d %s\n", i, array[i]);  //print (array index) (array value)
        printf("%d %p\n", i, (void*)&array[i]); //print (array index) (array address)
    }
    return 1;
}

يمكنك استخدام كذلك

char *num = calloc(100000, sizeof(char));

وهو دفاعي قليلا. لا أعرف لماذا تحتاج إلى 100000. يمكنك القيام بذلك بشكل حيوي باستخدام Malloc. هذا سوف ينطوي على المزيد من العمل ولكنه قوي جدا.

ما هو Hapenning في التعليمات البرمجية هو أن تخزين السلسلة٪ S إلى عنوان NUM الذي لا يتغير، ثم قمت بتعيين عنصر الصفيف [i] عنصر لهذا العنوان. تعيين في C هو شيء آخر ثم تخزين المرجع، أنت لا تخزن العنصر نفسه - سيكون هذا مضيعة للمساحة. بحيث تشير جميع عناصر الصفيف إلى العنوان (تخزين المرجع فقط)، فإن القيمة في تغيير العنوان، وبالتالي هل هذا هو المرجع، ولهذا السبب يتغير جميعا إلى 2 (وليس 3 كما ذكرت في رسالتك).

إنه لأمر مثل هذه الأشياء التي يبدو أن C ++. يتم تحليل إدخال المستخدم والمخصصات الديناميكية بشكل آمن، وفي نسيم. لا أستطيع التفكير في نظام لديك هذا النوع من واجهة المستخدم، حيث لا يمكنك التبديل إلى C ++.

بالطبع، إذا لم يكن هذا مجرد اختبار مقتطف من التعليمات البرمجية الأخرى التي تعاني من المشكلة، ثم بالطبع ...


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

إذا فهمت بشكل صحيح، فأنت تريد حفظ سلاسل إدخال المستخدم Sereival (إخراج المثال الخاص بك مضللة بعض الشيء، لأنك تظهر أرقام فقط).

أنت تقوم بإعداد الصفيف لعقد مؤشرات جميع (عدد الحالات) إلى السلاسل، ولكنك فقط حجز الذاكرة للحصول على سلسلة واحدة. تحتاج إلى القيام بذلك مقابل كل سلسلة، لذلك الحالات. للحفاظ على الأشياء بسيطة من حيث درس "تخصيص الذاكرة الديناميكي"، أوصي بذلك بهذه الطريقة: char* array[cases][10000]; هذا يمنحك الحالات سلاسل من شخصيات 10K.

ربما لا ترغب أيضا في الحصول على مؤشرات منفصلة لعناصر الصفيف الخاصة بك. يبدأ هذا من الشعور إذا كنت ترغب في فرز عناصر صفيف عندما تكون هذه العناصر أكبر من المؤشرات نفسها. في هذه الحالة، لا يكون مكسبتك في الأداء أن يتحرك (نسخ) قطع كبيرة، ولكن فقط المؤشرات (عادة 4 بايت). في حالتك، INT INT هو أيضا 4 بايت. وأنت لا فرز على أي حال :)

scanf() أمر خطير، أن أقول أقل. في تطبيقك الثاني، تقوم بتوجيهه لكتابة سلسلة إلى عنوان الصفيف. يبدو أن هذا خطأ بسيطا، ولكن يمكن أن يؤدي إلى العديد من المشاكل. ربما تريد أن تفعل ذلك بهذه الطريقة: scanf("%d", &array[i]); (لسوء الحظ، ليس لدي مترجم في متناول اليد، لذلك أنا لست متأكدا 100٪). إسقاط السطر التالي :)


سؤال لتخفيض المتخصصين: لماذا يكون ذلك من المستحيل أن يكون لديك قوائم مجتمعة مع كتل التعليمات البرمجية؟

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