المتغيرات والمؤشرات والكائنات وعناوين الذاكرة:لماذا أحصل على هذه النتيجة الغريبة؟
-
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);