ماذا يحدث عندما تتم تهيئة مصفوفة الأحرف من سلسلة حرفية؟

4

كما أفهمها ، يعمل الرمز التالي على النحو التالي:

char* cptr = "Hello World";

يعيش "مرحبا العالم" في .rodata قسم من ذاكرة البرنامج. السلسلة الحرفية "Hello World" إرجاع مؤشر إلى العنوان الأساسي للسلسلة ، أو عنوان العنصر الأول في ما يسمى "المصفوفة" ، حيث يتم وضع الأحرف بالتسلسل في الذاكرة سيكون "H". هذا هو الرسم التخطيطي الصغير حيث أتخيل السلسلة الحرفية التي يتم تخزينها في الذاكرة:

0x4 : 'H'
0x5 : 'e'
0x6 : 'l'
0x6 : 'l'
0x7 : 'o'
0x8 : ' '
0x9 : 'W'
0xa : 'o'
0xb : 'r'
0xc : 'l'
0xd : 'd'
0xe : '\0'

لذلك يصبح الإعلان أعلاه:

char* cptr = 0x4;

يشير cptr الآن إلى السلسلة الحرفية. أنا فقط اختلق العناوين.

0xa1 : 0x4

الآن كيف يعمل هذا الرمز؟

char cString[] = "Hello World";

أفترض ذلك كما في الحالة السابقة "Hello World" ينخفض أيضًا إلى عنوان "H" و 0x4.

char cString[] = 0x4;

أنا أقرأ = كعامل تخصيص زائد الحمل عند استخدامه مع تهيئة صفيف char. كما أفهم ، عند تهيئة السلسلة C فقط ، فإنها تنسخ حرفًا بادئًا بدءًا من العنوان الأساسي المحدد في السلسلة C حتى تصل إلى '\ 0' عند نسخ الحرف الأخير. كما أنها تخصص ذاكرة كافية لجميع الأحرف. نظرًا لأن مشغلي التحميل الزائد هم في الواقع مجرد وظائف ، أفترض أن التنفيذ الداخلي مشابه strcpy() .

أرغب في تأكيد أحد مبرمجي C الأكثر خبرة على افتراضاتي حول كيفية عمل هذا الرمز. هذا هو تصوري للسلسلة C بعد نسخ الرموز من السلسلة الحرفية فيه:

0xb4 : 'H'
0xb5 : 'e'
0xb6 : 'l'
0xb6 : 'l'
0xb7 : 'o'
0xb8 : ' '
0xb9 : 'W'
0xba : 'o'
0xbb : 'r'
0xbc : 'l'
0xbd : 'd'
0xbe : '\0'

مرة أخرى ، العناوين عشوائية ، والنقطة هي أن السلسلة C في المكدس تختلف عن السلسلة الحرفية في .rodata قسم في الذاكرة.

ما أحاول القيام به؟ أحاول استخدام مؤشر حرف للاحتفاظ مؤقتًا بالعنوان الأساسي للسلسلة الحرفية ، واستخدام نفس مؤشر الحرف (العنوان الأساسي للسلسلة الحرفية) لتهيئة السلسلة C.

char* cptr = "Hello World";
char cString[] = cptr;

أفترض ذلك "Hello World" يقيم إلى عنوانه الأساسي ، 0x4 . لذا يجب أن يبدو هذا الرمز كما يلي:

char* cptr = 0x4;
char cString[] = 0x4;

أفترض أنه لا ينبغي أن يكون مختلفًا عن char cString[] = "Hello World"; نظرًا لأن "Hello World" يتم تقييمها إلى عنوانها الأساسي ، وهذا هو ما يتم تخزينه في مؤشر char!

ومع ذلك ، أعطاني مجلس التعاون الخليجي خطأ:

error: invalid initializer
char cString[] = cptr;
                 ^
  1. كيف لا يمكنك استخدام مؤشر char كعنصر مؤقت مؤقت لتخزين العنوان الأساسي لسلسلة حرفية؟
  2. كيف يعمل هذا الرمز؟ هل افتراضاتي صحيحة؟
  3. هل يؤدي استخدام سلسلة حرفية في الرمز إلى إرجاع العنوان الأساسي إلى "المصفوفة" حيث يتم تخزين الأحرف في الذاكرة؟

3 الاجابة

5
افضل جواب

إن فهمك لتخطيط الذاكرة أكثر أو أقل صحة. لكن المشكلة التي تواجهها هي واحدة من دلالات التهيئة في C.

ال = الرمز في الإعلان هنا ليس عامل التعيين. بدلاً من ذلك ، فإن بناء الجملة هو الذي يحدد المُهيئ لمتغير يتم نسخه. في الحالة العامة ، T x = y; ليس هو نفسه T x; x = y; .

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

لماذا القواعد مثل هذا؟ "أسباب تاريخية".

:مؤلف
3
افضل جواب

التعريف الثاني char cString[] = "Hello World"; هو اختصار لهذا التعريف المكافئ:

char cString[12] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0' };

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

:مؤلف
3
افضل جواب

I am assuming that as in the previous situation "Hello World" also degrades to the address of 'H' and 0x4.

ليس صحيحا: cString[] يحصل على عنوان جديد تمامًا في الذاكرة. يخصص المترجم 12 char s إليها ، ويهيئها مع محتوى "Hello World" سلسلة حرفية.

I assume that "Hello World" evaluates to its base address, 0x4. Does using a string literal in the code return the base address to the "array" where the chars are stored in the memory?

cString يمكن تحويلها إلى char* في وقت لاحق ، يسفر عن عنوانه الأساسي ، لكنه يظل مصفوفة في السياقات العادية. على وجه الخصوص ، إذا قمت باستدعاء sizeof(cString) ستحصل على حجم المصفوفة ، وليس حجم المؤشر.

How come you can't use a char pointer as a temporary placeholder to store the base address of a string literal?

تستطيع. ومع ذلك ، بمجرد تعيين سلسلة حرفية char * ، فإنه يتوقف عن كونه سلسلة حرفية ، على الأقل فيما يتعلق بالمترجم. يصبح char * المؤشر ، لا يختلف عن الآخر char * مؤشرات.

لاحظ أن جامعي لغة C الحديثة يجمعون بين أحرف السلاسل المتطابقة كتحسين ، لذا إذا كتبت

#define HELLO_WORLD "Hello World"
...
char* cptr = HELLO_WORLD;
char cString[] = HELLO_WORLD;

وتشغيل التحسين ، فإن المترجم سيزيل النسخ المكررة من السلسلة الحرفية.

:مؤلف
فوق
قائمة طعام