المتغيرات والمؤشرات والكائنات وعناوين الذاكرة:لماذا أحصل على هذه النتيجة الغريبة؟

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

  •  03-07-2019
  •  | 
  •  

سؤال

بعد أن اعتقدت أنني فهمت كيفية عملها، جربت هذا:

NSString *str1 = [NSString stringWithCString:"one"];
NSString *str2 = [NSString stringWithCString:"two"];
NSLog(@"str1: %x, %@", &str1, str1); //bfffd3cc, one
NSLog(@"str2: %x, %@", &str2, str2); //bfffd3c8, two

str1 = str2;
NSLog(@"str1: %x, %@", &str1, str1); //bfffd3cc, two

قيمة المؤشر (مثل str1 وstr2) هي عنوان ذاكرة.عندما تذهب إلى هذا العنوان، فإنك تصل إلى "المنطقة" في الذاكرة حيث يتم تخزين الكائن.

لكن:عندما أقوم بتعيين str2 إلى str1، يجب أن تحتوي str1 كقيمة على عنوان الذاكرة لنفس الكائن المشار إليه بواسطة str2، أليس كذلك؟والغريب هنا أن قيمة المؤشر تظل كما هي (عنوان الذاكرة bfffd3cc)، حيث يتغير الشيء الموجود خلف ذلك العنوان.هذا في الواقع غير منطقي تمامًا بالنسبة لي؛) لأنني أعتقد أن عنوان الذاكرة هو الكائن (أو موطن الكائن في لبنة الذاكرة، أيًا كان).لذلك توقعت هذا:

NSString *str1 = [NSString stringWithCString:"one"];
NSString *str2 = [NSString stringWithCString:"two"];
NSLog(@"str1: %x, %@", &str1, str1); //bfffd3cc, one
NSLog(@"str2: %x, %@", &str2, str2); //bfffd3c8, two

str1 = str2;
NSLog(@"str1: %x, %@", &str1, str1); //bfffd3c8, two

خلاف ذلك، ما زلت لم أفهم هذه النقطة.العلاقة بين قيمة "متغير المؤشر" و"القيمة الحقيقية"، لنفترض الكائن الموجود خلف عنوان الذاكرة هذا.

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

المحلول

تذكر أن متغير المؤشر هو متغير بحد ذاته، لذلك له عنوان.لذا &str1 يؤدي إلى عنوان متغير المؤشر، و str1 هو تعبير ينتج عنه ما يحمله متغير المؤشر - عنوان الكائن الذي يشير إليه.

افترض أن:

  • الكائن الذي يحمل NSString "واحد" موجود على العنوان 0x00000100
  • الكائن الذي يحمل NSString "two" موجود على العنوان 0x00000200

ثم قد تبدو مؤشراتك كما يلي:

عند التهيئة:

str1
0xbfffd3c8  +---------------+
            |               |
            |  0x00000100   |
            |    ("one")    |
            +---------------+

str2
0xbfffd3cc  +---------------+
            |               |
            |  0x00000200   |
            |    ("two")    |
            +---------------+

=======================================

بعد str1 = str2; تكليف:

str1
0xbfffd3c8  +---------------+
            |               |
            |  0x00000200   |
            |    ("two")    |
            +---------------+

str2
0xbfffd3cc  +---------------+
            |               |
            |  0x00000200   |
            |    ("two")    |
            +---------------+

نصائح أخرى

وكنت تطبع مرجع المؤشر، والذي هو عنوان المؤشر، لا قيمة المؤشر.

و&str1 يأخذ عنوان المؤشر.

وطيب، ونتذكر كيف قلنا أن كل شيء قدير "يعيش" في بعض العناوين في الذاكرة؟ وهذا مؤشر هو مجرد رقم، وهو الرقم الذي هو العنوان؟

مؤشرات

وحسنا هي الأشياء أيضا، وعلى هذا النحو <م> أنها لها عناوين.

عند طباعة &str1، كنت طبع الذاكرة عن طريق مؤشر المحتلة. عند طباعة str1، كنت طبع قيمة المؤشر، الذي هو عنوان الذاكرة التي نقطة ل.

عند طباعة *str1 كنت dereferencing المؤشر، والطباعة <م> أن طباعة أشارت إلى قيمة.


وبالمناسبة، والعمل الجيد: لقد قرأت أسئلتك الماضيين، وكنت الحصول عليه، والائتمان الخاصة بك كتابة كود لإثبات أو دحض هذا الفهم الخاص بك هو الصحيح. هذا هو بالضبط ما يجب أن تقوم به، وكنت على الطريق الصحيح.

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

وقد تجد كل هذا أسهل للفهم إذا كنت تستخدم شيء من هذا القبيل [إينتس] والمؤشرات إلى [إينتس].

وهي، في الواقع، صحيحة مع الحساب المخصص (IIRC، ويضمن أن sizeof (دولي) == sizeof (الفراغ *)) مؤشرات

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

وتعيين تتصرف مثل الاحالة بين الأعداد الصحيحة. في الواقع:

#include <stdio.h>

int main() {
        char *str1 = "Ciao";
        char *str2 = "Mondo";
        printf("%x\n", str1);
        printf("%x\n", str2);
        str1 = str2;
        printf("%x\n", str1);
}

والمطبوعات:

:~$ ./a.out
80484f8
80484fd
80484fd

وstr1 هو مؤشر إلى قيمة NSString.

و&str1 يعني: عنوان متغير str1. هذا هو المراوغة المزدوج.

وانا اعتقد ان كنت تريد عنوان القيمة، أي str1 نفسها، وليس &str1.

لنفترض أن قيمة الكائن NSString تحتوي على @"one" يقع في عنوان 0x12345678 و@"two" هو في 0x1234ABC0.

في البداية قيمة str1 هي 0x12345678 وقيمة str2 هو 0x1234ABC0. يتم تخزين هذه القيم اثنين في الذاكرة على التوالي في عناوين 0xbfffd3cc و0xbfffd3c8. هذه هي عناوين str1 وstr2 المتغيرات، أي قيم &str1 و&str2.

عند إرسال str1 = str2، وقيمة التغييرات تعيين str1 أن تكون نفس قيمة str2، أي قيمة str1 هي ثم 0x1234ABC0. هذا هو عنوان الكائن @"two". ولكن عنوان متغير str1 (0xbfffd3cc) لا تتغير.

وعملت

وكائنات في الهدف-C على استخدام المؤشرات. وذلك من أجل التعامل مع الكائن NSString الخاص بك، عليك أن تأخذ مؤشر إلى ذلك. وهو ما str1، مؤشر إلى كائن NSString.

إذا كنت تريد إرسال رسالة إلى NSString الخاص بك، يمكنك استخدام بناء الجملة [str1 تنفيذ DoSomething].

إذا كنت ترغب في طباعة سلسلة الخاص بك، لديك لتمرير المؤشر إلى NSLog وأقول NSLog أن نقاط مؤشر إلى NSString، والتي تتم من قبل حكم التنسيق "٪ @".

والآن، إذا كنت ترغب فقط في طباعة عنوان أشار إليه str1، لا يزال لديك لتمرير str1 المؤشر ولكن يجب أن أقول NSLog التي كنت تطبع على أنها قيمة ست عشرية باستخدام قاعدة التنسيق "٪ س".

وشيء من هذا القبيل يجب طباعة ما تريد:

// First print str1 as an hexadecimal value
// Then print the content of the NSString object str1 points to
NSLog(@"str1: %x, %@", str1, str1);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top