変数、ポインタ、オブジェクト、およびメモリアドレス:なぜこの奇妙な結果が得られるのですか?
-
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
それ以外の場合、私はまだポイントを得られませんでした。 「ポインタ変数」の値との関係" real value"では、そのメモリアドレスの後ろに座っているオブジェクトを言うことができます。
解決
ポインタ変数は変数そのものなので、アドレスを持っていることに注意してください。したがって、& str1
はポインター変数のアドレスになり、 str1
はポインター変数が保持しているもの(結果として指すオブジェクトのアドレス)になります。 。
想定:
- NSStringを保持するオブジェクト" one"アドレス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
を印刷すると、ポインターの参照が解除され、それを印刷すると、ポイントされた値が印刷されます。
ちなみに、良い仕事です。最後の2つの質問を読んで、あなたはそれを手に入れています。あなたの理解が正しいことを証明または反証するために、あなたのクレジット執筆コードに。これはまさにあなたがすべきことであり、あなたは正しい軌道に乗っています。
あなたが抱えている問題の一部は、文字列が面白いものであり、文字列は実際には(定数)文字の配列であり、NSLogのような関数はcharへのポインタで通常のことを行うために書かれていることです文字列を印刷します。文字列へのポインタが与えられると、それは本当にループしています:ポインタの逆参照、ポイント先の文字の印刷、ポインタへの追加、次の文字の印刷、ポイントされた文字が値0の特殊文字になるまで文字列の終わりを見つけ、文字の出力を停止します。
intやintへのポインターなどを使用すると、これらすべてを理解しやすくなる場合があります。
ポインターは、実際には専用の算術演算を使用した整数です(IIRC、sizeof(int)== sizeof(void *))が保証されています
ポインタを参照する場合、保存されているアドレスを取得します。変数が自動の場合、ポインターが格納されているスタックのアドレスを取得します。そのため、これらの結果が取得されます。
割り当ては整数間の割り当てのように動作します。実際:
#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
値へのポインターです。
&amp; str1
は、 str1
変数のアドレスを意味します。これは二重間接です。
値のアドレス、つまり&amp; str1
ではなく、 str1
が必要だと思います。
@&quot; one&quot;
を含む NSString
オブジェクト値がアドレス 0x12345678
および @&quot; two&quotにあると仮定しましょう;
は 0x1234ABC0
にあります。
最初は str1
の値は 0x12345678
で、 str2
の値は 0x1234ABC0
です。
これらの2つの値は、メモリのアドレス 0xbfffd3cc
および 0xbfffd3c8
にそれぞれ保存されます。これらは、 str1
および str2
変数のアドレス、つまり&amp; str1
および&amp; str2
の値です。
str1 = str2
と記述すると、割り当てにより str1
の値が str2
の値、つまり str1
は 0x1234ABC0
です。これは、 @&quot; two&quot;
オブジェクトのアドレスです。ただし、 str1
変数( 0xbfffd3cc
)のアドレスは変更されません。
Objective-Cのオブジェクトは、ポインターを使用して処理されます。したがって、NSStringオブジェクトを処理するには、そのオブジェクトへのポインタを取得する必要があります。これは、str1がNSStringオブジェクトへのポインターであるものです。
NSStringにメッセージを送信する場合は、構文[str1 doSomething]を使用できます。
文字列を印刷する場合は、NSLogにポインターを渡し、NSLogにポインターがNSStringを指していることを伝える必要があります。これは、フォーマットルール&quot;%@&quot;によって行われます。
今、str1が指すアドレスを印刷したい場合、ポインタstr1を渡す必要がありますが、フォーマットルール&quot;%x&quot;を使用して16進値として印刷することをNSLogに伝える必要があります。
そのようなものはあなたが望むものを印刷するはずです:
// First print str1 as an hexadecimal value
// Then print the content of the NSString object str1 points to
NSLog(@"str1: %x, %@", str1, str1);