33

質問に続いて:配列のアドレスがCの値と等しいのはなぜですか?

#include <stdio.h>
#define N 10    
char str2[N]={"Hello"};
int main(){
    printf("sizeof(str2): %d bytes\n", sizeof(str2));
    printf("sizeof(&str2): %d bytes\n", sizeof(&str2));
    return 0;
}

出力:

sizeof(str2): 10 bytes
sizeof(&str2): 4 bytes

私はそれstr2だけが配列の最初の要素のアドレスであることを知っていますstr2。そして、それがstr2引数である場合sizeof、配列str2全体のサイズを返します。

さらに、&str2はarrの最初の要素のアドレスでもありますが、str2タイプが異なります(char (*)[N]==配列へのポインター)。しかし、それがの議論であるとき、どのよう&str2に振る舞いますsizeofか?

4

4 に答える 4

115

との違い&strstrいつstr宣言されchar str[10]ますか?

読み取り sizeof演算子:

6.5.3.4 sizeof演算子、1125:
演算子を配列型に 適用するsizeofと、結果は配列内の合計バイト数になります。

したがって、宣言によればsizeof(str2)、完全な配列サイズは10バイトになります(Nは10として定義され、charサイズは1バイトであるため)。
一方、式sizeof(&str2)&str2は、は配列のアドレスであり、そのアドレスのサイズはシステム上で4バイトです。(アドレスサイズは、64ビットなどの一部のシステムでは8バイトになる場合があります)。

さらに、&str2arrの最初の要素のアドレスもありますstr2か?

いいえ、値的に は両方&str2ともstr同じですが、意味的には両方とも異なります。1つは10文字の配列のアドレスであり、もう1つは文字のアドレスです。

あなたがそれらの間のあなた自身の例で見た1つの違いは(@ouahが答えでこれを説明した)です。

  • タイプstrchar[10]
  • タイプ&strchar(*)[10]

2番目: 図に従うと、他の違いを観察するのに役立ちます。

for declaration: 
#define N 10
char str2[N] = {"Hello"};

str2 Array in memory is something like:
----------------------------------------

str
+----+----+----+----+----+----+----+----+----+----++----+
|'H' |'e' |'l' |'l' |'o' |'\0'|'\0'|'\0'|'\0'|'\0'|| '@'|
+----+----+----+----+----+----+----+----+----+----++----+
 201   202  203 204  205   206  207  208  209  210   211
▲ ▲     ▲                                             ▲
| |     |                                             |
|(str2) (str2 + 1)                                    | 
|                                                     |
|-----------------------------------------------------|
|201                                                  | 
|                                                     |
|                                                     |
(&str2) = 201                           (&str2 + 1) = 211


* assuming str address start from 201
* str[N] is 10 char long 201-210, partially initialized
* at uninitialized position, str2[i] = '\0'
* location 211 is unallocated, having garbage value,
  access to this location is illegal-Undefined Behavior

上の図では、次のようなコードを記述できます。

#include <stdio.h>
#define N 10    
int main(){
   char str2[N]={"Hello"};
  
   printf("\n %p, %p\n",str2, str2+1);
   printf("\n %p, %p\n",(&str2), (&str2+1));
}  

出力:

 0xbf67e142, 0xbf67e143

 0xbf67e142, 0xbf67e14c

コードパッドへのリンク:

最初の行では、出力アドレスが1バイト異なりますが、2番目の行では、配列のポインターであるため、違いは10バイトであることに注意してください(上の図を参照)。

ポインタ演算の規則に従って、ポインタ変数に1を追加すると、それはそれ自体のタイプの次の要素を指し始めます。&str2は配列を指すアドレスであるため、これが10バイトの違いの理由です。

3番目の違い:

そう*str2することで、最初の要素にアクセスできます。最初*(&str2)の要素は提供されませんが、代わりに、最初の要素のアドレスが提供されます。

ここで例が役立ちます:

#include <stdio.h>
#define N 10    
int main(){
   char str2[N]={"Hello"};
   printf("\n%p %c, %p %c\n",str2, *(str2), *(&str2), **(&str2));
}  

出力:

0xbf587046 H, 0xbf587046 H

コードパッドリンク

出力で

str2 gives  0xbf587046 
*(str2)     H 
*(&str2)    0xbf587046 
**(&str2)   H 

つまり*(&str2) == str2、値はアドレスです。したがって、*(str2) = **(&str2)値はHです。

編集:上記で&str、との 違いを示しました。はタイプの配列です。strstrchar[10]

との違いchar *strchar str[]両方のメモリへの保存方法

以下のような2つの宣言があるとします。

char *str1 = "hello";   
char str2[] = "hello";  

上記の宣言には、定数文字列リテラルを指すstr1へのポインタがあります(文字列の最初の文字のアドレスを保持することによって)。charh"hello"

Cの文字列はchar[N](配列)型であるsizeof("hello")ため、"hello"文字列は6文字の長さの配列であるため6になります(\0nul、文字列の終了、helloの型が含まれますchar[6])。

メモリには、"hello"文字列は次のように保存されます。

 str1         23   24   25   26   27   28
+----+      +----+----+----+----+----+----+
| 23 |      | h  | e  |  l | l  | o  | \0 |    
+----+      +----+----+----+----+----+----+
   +-----------▲

here the address of the hello string is the first address = 23.  
str1: is a pointer capable of storing an address. 
"hello" consists of 6 chars

char* str1 = "hello";基本的に、上の図に示すように、文字列helloのアドレスをポインタ変数に格納しますstr1

str1注:必要に応じて、他の文字列を指すように変更できます。ただし、文字列を変更することはできませんhello。たとえば、次のコードが有効です。

 char* str1 = "hello";  // str1 points to hello  str1-->"hello"
 str1 = "world";  //Now, str1 points to world  str1-->"world"

ここstr1で、他の定数文字列の世界を指します。

 str1         93   94   95   96   97   98 
+----+      +----+----+----+----+----+----+
| 93 |      | w  | o  |  r | l  | d  | \0 |    
+----+      +----+----+----+----+----+----+
   +-----------▲

here address of world string is first address = 93.  
str1: value change to point string world. 

注意すべき重要な点:str1定数文字列を指しているため、たとえばメモリ位置にアクセス/インデックス付けして文字列を変更することはできませんstr1[i] = 'A'読み取り専用メモリに書き込んでおり、実行時にこの動作が定義されていないため、違法になります(ただし、構文的には正しいため、コンパイルエラーは発生しません)。

繰り返しstr1ますが、ポインタsizeof(str1)は同じマシン上で4を与えるためです。

私の次のコードとその実行:

#include <stdio.h>
int main(){
   char* str1="Hello";
   printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));
   str1 = "world";
   printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));
   return 1;
}  

出力:

str1: Hello, address: 0x80485e8, sizeof(str1): 4
str1: world, address: 0x8048619, sizeof(str1): 4

コードパッドリンク

したがって、新しい文字列を割り当てるには、新しい文字列のアドレスを割り当てるだけです。しかしstrcpy()、読み取り専用のメモリ位置に書き込もうとすることはできません。これは違法です。

2番目の宣言char str2[] = "hello";str2[]は、\0は文字(または文字列)の終了した配列ですが、ポインタではありません。この宣言では、サイズにデフォルトサイズが指定されていないため、定数文字列「hello」のサイズが6であることがわかります。タイプstr2は。ですchar[6]

これを行うchar str2[] = "hello";と、charの配列が作成され、hello文字列がその配列にコピーされます。つまりstr2、単なるポインタではなく、完全な文字列を格納する配列です。

概念的には

       str2:
       103  104  105  106  107  108
      +----+----+----+----+----+----+
      | h  | e  |  l | l  | o  | \0 |    
      +----+----+----+----+----+----+

この場合、最近コードで実行が許可されていないstr2[] = "world";str2 = "world"コンパイル時エラーになります。

サンプルコード:

#include<stdio.h>
int main(){
 char str2[] = "hello";
 str2[] = "world";
 str2 = "world"; 
 return 1; 
}

コンパイルエラー:

In function 'main':
Line 4: error: expected expression before ']' token
Line 5: error: incompatible types in assignment

Codescapeリンク

この配列str2が定数でない場合は、その内容を変更できます。たとえば、実行str2[2] = 'A'は完全に有効です。strcpyを呼び出してコンテンツを変更することもできます(アドレス空間は変更されません)

       strcpy(str2, "world");

       str2:
       103  104  105  106  107  108
      +----+----+----+----+----+----+
      | w  | o  |  r | l  | d  | \0 |    
      +----+----+----+----+----+----+

      Note that when "world" is copied into a same memory space, the addresses of both "world" and "hello"
      string are the same.  

コード例:

#include<stdio.h>
int main(){
 char str2[] = "hello";
 printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
 str2[2] = 'A';
 printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
 strcpy(str2, "world");
 printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
 return 1; 
}

出力:

str2: hello, address: 0xbf58d056, sizeof(str2): 6
str2: heAlo, address: 0xbf58d056, sizeof(str2): 6
str2: world, address: 0xbf58d056, sizeof(str2): 6

コードパッドリンク

注:文字列値は、同じアドレス空間では異なります。sizeof(str2)= 6は、バイト単位の配列のサイズである古い回答から完全に理解されています。

2次元配列に関する同様の説明を読むには、次のように読みます。との違いchar* str[]char str[][]、両方がメモリに格納する方法

于 2013-03-02T17:45:56.630 に答える
21

&str2ポインタです。つまり、プラットフォーム上のポインタのサイズが表示されているだけです。

于 2013-03-02T17:38:10.497 に答える
10

str2タイプchar [10](つまり、配列10 ofchar`)

&str2タイプchar (*)[10](つまり、の配列へのポインタ10charです。

したがってsizeof (&str2) 、ポインタ型のオブジェクトのサイズが得られますchar (*)[10]

于 2013-03-02T17:38:34.277 に答える
1

を使用arrすると+、最初の要素を指す-constポインターに減衰します。char (* const) arr一部の操作:sizeof(arr)および、は、サイズ、を含む&arrすべてのタイプ情報を使用します。char arr[10]10

于 2021-05-01T18:45:23.500 に答える