[英]What does sizeof(&array) return?
跟隨這個問題: 為什么數組的地址等於它在 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
的參數時,它的行為如何?
&str
和str
之間的區別,當str
被聲明為char str[10]
? 讀取sizeof
運算符:
6.5.3.4 sizeof 運算符,1125:
將sizeof
運算符應用於數組類型時,結果是數組中的總字節數。
因此,根據您的聲明, sizeof(str2)
給出了 10 個字節的完整數組大小(因為 N 定義為 10,而 char 大小為 1 個字節)。
而在表達式sizeof(&str2)
, &str2
是一個數組的地址,並且該地址的大小在您的系統上是 4 個字節。 (地址大小在某些系統中可能是 8 個字節,例如 64 位)。
另外,
&str2
也是 arrstr2
第一個元素的地址?
不, &str2
和str
在值方面是相同的,但在語義上是不同的。 一個是 10 個字符數組的地址,另一個是一個字符的地址。
您在自己的示例中看到的一個區別是(@ouah 在回答中對此進行了解釋)。
str
類型是char[10]
&str
類型是char(*)[10]
第二:遵循圖表將幫助您觀察其他差異。
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
請注意,在第一行,輸出地址相差一個字節,但在第二行中,相差 10 個字節,因為它是數組的指針(如上圖所示)。
根據指針算法的規則,當你給一個指針變量加 1 時,它開始指向它自己類型的下一個元素。 這就是 10 字節差異的原因,因為&str2
是一個數組地址。
第三個區別:
通過執行*str2
您可以訪問 thr 第一個元素。 而*(&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
並且 value 是地址。 因此*(str2) = **(&str2)
值是H
。
編輯:上面我展示了&str
和str
之間的區別,其中str
是char[10]
類型的數組。
char *str
和char str[]
之間的區別以及兩者在內存中的存儲方式假設我們有如下兩個聲明:
char *str1 = "hello";
char str2[] = "hello";
在上面的聲明中, str1
是一個指向char
的指針,它指向一個常量字符串文字(通過保存"hello"
字符串中第一個字符h
地址)。
C 中的字符串是char[N]
(數組)類型,這就是sizeof("hello")
給出 6 的原因,因為"hello"
字符串是 6 個字符長的數組(包括\\0
nul,字符串終止,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()
,它會嘗試在只讀內存位置上寫入並且這是非法的。
在第二個聲明中char str2[] = "hello";
, str2[]
是一個以\\0
結尾的字符(或字符串)數組,但不是指針。 注意,因為在這個聲明中 size 沒有給出默認 size ,我們看到常量字符串“hello”的大小是 6。 str2
類型是char[6]
。
當我們做char str2[] = "hello";
一個字符數組被創建,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
如果這個數組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 從舊答案中可以完全理解,即數組的大小(以字節為單位)。
要閱讀有關二維數組的類似描述,請閱讀: char* str[]
和char str[][]
之間的區別以及兩者如何存儲在內存中?
&str2
是一個指針。 所以你只是在你的平台上看到一個指針的大小。
str2
是char [10]
類型(即 char` 的數組10 of
)
&str2
是char (*)[10]
(即指向char
數組10
的指針)。
所以sizeof (&str2)
產生指針類型char (*)[10]
對象的大小
可以將char arr[10]
視為在幕后聲明兩個對象:
char * const arr
。 (所以你不能重新分配給arr
)arr
相關聯的大小[10]
,因此您可能會在索引超出范圍時收到警告。以上分別引出了兩個事實:
arr
進行指針算術時僅使用信息char * const arr
arr
。
因此
arr
上的指針算術將在一個char
偏移,而不是在char [10]
,即arr+1
指向arr[1]
。
sizeof(arr)
和&arr
,利用所有信息, char * const arr
, [10]
。
所以
sizeof(arr)
返回sizeof(char) * 10
(或sizeof(*arr) * 10
,更便攜),即在此操作中使用與arr
關聯的大小[10]
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.