虽然问题已经得到回答和接受,但我添加了更多描述(也回答了原始问题),我想这对新用户会有帮助。 (正如我搜索的那样,此描述在其他任何地方都没有解释(至少在 stackoverflow 上),因此我现在添加。
初读: sizeof Operator
6.5.3.4 sizeof 运算符,1125:
当您将sizeof 运算符应用于数组类型时,结果是数组中的总字节数。
据此,当sizeof 应用于静态数组标识符的名称(不是通过 malloc 分配的)时,结果是整个数组的字节大小,而不仅仅是地址。这是few exceptions to the rule that the name of an array is converted/decay to a pointer to the first element of the array 之一,这可能只是因为实际数组大小是固定的并且在编译时已知,此时sizeof 运算符会计算。
为了更好地理解它,请考虑以下代码:
#include<stdio.h>
int main(){
char a1[6], // One dimensional
a2[7][6], // Two dimensional
a3[5][7][6]; // Three dimensional
printf(" sizeof(a1) : %lu \n", sizeof(a1));
printf(" sizeof(a2) : %lu \n", sizeof(a2));
printf(" sizeof(a3) : %lu \n", sizeof(a3));
printf(" Char : %lu \n", sizeof(char));
printf(" Char[6] : %lu \n", sizeof(char[6]));
printf(" Char[5][7] : %lu \n", sizeof(char[7][6]));
printf(" Char[5][7][6]: %lu \n", sizeof(char[5][7][6]));
return 1;
}
它的输出:
sizeof(a1) : 6
sizeof(a2) : 42
sizeof(a3) : 210
Char : 1
Char[5] : 6
Char[5][7] : 42
Char[5][7][6]: 210
检查上面在@codepad 工作,注意char 的大小是一个字节,如果你在上面的程序中用int 替换char,那么每个输出将在你的机器上乘以sizeof(int)。
char* str[] 和 char str[][] 之间的区别以及两者在内存中的存储方式
声明 1: char *str[] = {"forgs", "do", "not", "die"};
在这个声明中,str[] 是一个指向 char 的 指针数组。每个索引str[i] 指向{"forgs", "do", "not", "die"}; 中字符串的第一个字符。
逻辑上str在内存中的排列方式如下:
Array Variable: Constant Strings:
--------------- -----------------
str: 201 202 203 204 205 206
+--------+ +-----+-----+-----+-----+-----+-----+
343 | |= *(str + 0) | 'f' | 'o' | 'r' | 'g' | 's' | '\0'|
| str[0] |-------| +-----+-----+-----+-----+-----+-----+
| 201 | +-----------▲
+--------+ 502 503 504
| | +-----+-----+-----+
347 | str[1] |= *(str + 1) | 'd' | 'o' | '\0'|
| 502 |-------| +-----+-----+-----+
+--------+ +-----------▲
| | 43 44 45 46
351 | 43 | +-----+-----+-----+-----+
| str[2] |= *(str + 2) | 'n' | 'o' | 't' | '\0'|
| |-------| +-----+-----+-----+-----+
+--------+ +-----------▲
355 | |
| 9002 | 9002 9003 9004 9005
| str[3] | +-----+-----+-----+-----+
| |= *(str + 3) | 'd' | 'i' | 'e' | '\0'|
+--------+ | +-----+-----+-----+-----+
+-----------▲
Diagram: shows that str[i] Points to first char of each constant string literal.
Memory address values are assumption.
注意:str[] 存储在 continue 内存分配中,每个字符串都存储在内存中的随机地址(而不是 continue 空间中)。
[回答]
根据Codepad以下代码:
int main(int argc, char **argv){
char *str[] = {"forgs", "do", "not", "die"};
printf("sizeof(str): %lu, sizeof(str[0]): %lu\n",
sizeof(str),
sizeof(str[0])
);
return 0;
}
输出:
sizeof(str): 16, sizeof(str[0]): 4
(注意:在某些系统地址可以是2字节或8字节)
关于输出一也应该阅读glglgl的comment到问题:
在任何架构上,第一个值应该是第二个值的 4 倍。
在 32 位机器上,您应该得到 16 4,在 64 位机器上应该得到 32 8。在非常旧的机器上
或者在嵌入式系统上,你甚至可能得到 8 2,但永远不会得到 12 2,因为数组包含 4 个相同大小的元素
补充点:
- 因为每个
str[i] 指向一个char*(和字符串)是可变的,所以str[i] 可以分配一个新的字符串地址,例如:str[i] = "yournewname"; 对i = 0 to < 4 有效。
还有一点需要注意:
-
在我们上面的示例中,str[i] 指向无法修改的常量字符串;因此str[i][j] = 'A' 无效(我们不能在只读内存上写入),这样做会导致运行时错误。
但是假设如果str[i] 指向一个简单的字符数组,那么str[i][j] = 'A' 可以是一个有效的表达式。
考虑以下代码:
char a[] = "Hello"; // a[] is simple array
char *str[] = {"forgs", "do", "not", "die"};
//str[0][4] = 'A'; // is error because writing on read only memory
str[0] = a;
str[0][5] = 'A'; // is perfectly valid because str[0]
// points to an array (that is not constant)
在这里查看工作代码:Codepad
声明 2: char str[][6] = {"forgs", "do", "not", "die"};:
这里str 是一个大小为 4 * 6 的二维字符数组(其中每一行的大小相等)。(请记住,在这里您必须在 str 的声明中明确给出列值,但行是4 因为字符串的数量是 4)
在内存中str[][] 将如下图所示:
str
+---201---202---203---204---205---206--+
201 | +-----+-----+-----+-----+-----+-----+|
str[0] = *(str + 0)--►| 'f' | 'o' | 'r' | 'g' | 's' | '\0'||
207 | +-----+-----+-----+-----+-----+-----+|
str[1] = *(str + 1)--►| 'd' | 'o' | '\0'| '\0'| '\0'| '\0'||
213 | +-----+-----+-----+-----+-----+-----+|
str[2] = *(str + 2)--►| 'n' | 'o' | 't' | '\0'| '\0'| '\0'||
219 | +-----+-----+-----+-----+-----+-----+|
str[3] = *(str + 3)--►| 'd' | 'i' | 'e' | '\0'| '\0'| '\0'||
| +-----+-----+-----+-----+-----+-----+|
+--------------------------------------+
In Diagram:
str[i] = *(str + i) = points to a complete i-row of size = 6 chars.
str[i] is an array of 6 chars.
这种二维数组在内存中的排列方式称为Row-Major:
线性存储器中的多维数组是这样组织的,使得行一个接一个地存储。这是 C 编程语言使用的方法。
请注意两个图表中的差异。
- 在第二种情况下,完整的二维字符数组被分配在连续内存中。
- 对于任何
i = 0 to 2、str[i] 和str[i + 1],值相差6 个字节(即等于一行的长度)。
- 此图中的双边界线表示
str 表示完整的 6 * 4 = 24 个字符。
现在考虑您在问题中针对二维字符数组发布的类似代码,请查看Codepad:
int main(int argc, char **argv){
char str[][6] = {"forgs", "do", "not", "die"};
printf("sizeof(str): %lu, sizeof(str[0]): %lu\n",
sizeof(str),
sizeof(str[0])
);
return 0;
}
输出:
sizeof(str): 24, sizeof(str[0]): 6
根据sizeof 运算符对数组的处理,在应用 2-d 数组大小时应返回 24 字节的整个数组大小。
众所周知,sizeof 运算符在应用数组名称时返回整个数组的大小。所以对于sizeof(str),它返回 = 24,即完整的 2D 字符数组的大小,包含 24 个字符(6 列* 4 行)。
在这个str 的声明类型中是char[4][6]。
还有一个有趣的地方是str[i]代表一个数组聊天,它的类型是char[6]。而sizeof(str[0]) 是完整数组的大小 = 6(行长)。
补充点:
两个声明之间的另一个重要区别:
在Declaration-1中:char *str[] = {"forgs", "do", "not", "die"};,&str的类型是char*(*)[4],它是char指针数组的地址。
在Declaration-2中:char str[][6] = {"forgs", "do", "not", "die"};,&str的类型为char(*)[4][6],其地址为4行6列的二维char数组。
如果想阅读一维数组的类似描述:What does sizeof(&array) return?