sizeof(& array)返回什么?

时间:2013-03-02 17:36:35

标签: c string pointers sizeof

关注问题:How come an array's address is equal to its value in 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中第一个元素的地址。当str2sizeof的参数时,它返回整个数组str2的大小。

此外,&str2也是arr str2中第一个元素的地址,但是来自不同类型(char (*)[N] ==指向数组的指针)。但&str2如果是sizeof的参数?

,它是如何表现的呢?

4 个答案:

答案 0 :(得分:108)

&str被声明为str时,strchar str[10]之间的差异?

阅读sizeof运营商:

  

6.5.3.4 sizeof运算符,1125:
  将sizeof运算符应用于数组类型时,结果是数组中的总字节数。

因此,根据您的声明,sizeof(str2)给出了10个字节的完整数组大小(因为N定义为10,char大小为1个字节)。
而在表达式sizeof(&str2)中,&str2是数组的地址和系统中4字节的地址大小。 (地址大小在某些系统中可能是8字节,例如64位)。

  

此外,&str2也是arr str2中第一个元素的地址?

&str2str的值相同,但在语义上都不同。一个是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

A link for codepad:

注意第一行输出地址差异是一个字节,但是第二行差异是10个字节,因为它的数组的指针(如上图所示)。

根据指针数学规则,当你向指针变量添加1时,它开始指向它自己类型的下一个元素,这是10个字节差异的原因,因为&str2是数组地址..

第三次差异:

通过执行*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

Codepad link

输出

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

这意味着*(&str2) == str2,值是地址。因此*(str2) = **(&str2)值为H

修改:上面我显示了&strstr之间的差异,其中strchar[10]类型的数组。

char *strchar str[]之间的差异以及两者如何存储在内存中

假设我们有两个声明如下:

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

在上面的声明中str1是一个指向char的指针,它指向一个常量字符串文字(通过保存h字符串中第一个字符"hello"的地址)。

C中的字符串是char[N](数组)类型,这就是sizeof("hello")给出6的原因,因为"hello"字符串是6个字符长数组(包括\0 nul,字符串终止,你好的类型是char[6])。

在内存中,"hello"字符串的存储方式如下:

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

here address of hello string is first address = 23.  
str1: is pointer capable to store 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

Codepad link

因此,要分配新字符串,我只需指定新字符串的地址。但我无法调用strcpy()来尝试在只读内存位置写入,这是非法的。

在第二个声明char str2[] = "hello";中,str2[]是一个\0终止的字符数组(或字符串),但不是指针。请注意,因为在这个声明中,大小没有给出默认大小我们是那个常量字符串的大小&#34;你好&#34;这是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 link

如果此数组str2不是常量,我们可以修改其内容,例如,执行str2[2] = 'A'完全有效。我们也可以调用strcpy来改变内容(并且地址空间不会改变)

       strcpy(str2, "world");

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

      Note world coped into same memory space, address of world and hello
      string is name. 

代码示例:

#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

Codepad link

注意:相同地址空间的字符串值不同。 sizeof(str2) = 6从旧答案中完全理解,即以字节为单位的数组大小。

阅读关于二维数组读取的类似描述:Difference between char* str[] and char str[][] and how both stores in memory?

答案 1 :(得分:19)

&str2是一个指针。所以你只是看到平台上指针的大小。

答案 2 :(得分:8)

str2的类型为char [10](即数组10 of char`)

&str2的类型为char (*)[10](即指向10的数组char的指针。)

因此sizeof (&str2)会产生指针类型char (*)[10]

的对象大小

答案 3 :(得分:1)

2021 年读者:

可以将 char arr[10] 视为在幕后声明两个对象:

  • 指向数组第一个元素的常量指针 char * const 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,更便携),即在此操作中使用与 [10] 关联的大小 arr。< /p>