我刚开始学习如何编程,我正在使用这本名为Head First C的书。本书中有一些部分名为 Brain Power 。在其中一个部分中写了。
void fortune_cookie(char msg[])
{
printf("Message reads: %s\n", msg);
printf("msg occupies %i bytes\n", sizeof(msg));
}
输出:
饼干让你发胖
msg占用8个字节
脑力问题是:为什么你认为sizeof(msg)
比整个字符串的长度短?什么是msg
?为什么它会在不同的机器上返回不同的尺寸?
答案 0 :(得分:3)
在这个特殊情况下
char msg[]
与
相同 char * msg
所以你真正看到的是sizeof(char *)
的输出。
由于指针的大小取决于架构/编译器,因此您将在不同的机器中看到不同的输出。
另请注意,当sizeof
运算符生成类型为size_t
的结果时,您应该使用%zu
格式说明符来打印结果。
答案 1 :(得分:2)
为什么你认为sizeof(msg)比整个字符串的长度短?
因为arrays
在作为参数传递给某个函数时会衰减为指针。
int arr[10];
printf("%zu", sizeof(arr));
这将返回40
。考虑int
的大小为4
但是当发送到函数时
void func(int arr[])
{
printf("%lu", sizeof(arr));
}
这将返回sizeof(int*)
什么是msg?
msg
是发送到函数的char
数组。
为什么它会在不同的机器上返回不同的颜色?
因为不同的机器架构的内存地址大小会有所不同,因此sizeof(int*)
会有所不同。
答案 2 :(得分:1)
以下代码应该回答您的问题:
#include <stdio.h>
#include <string.h>
void foo(char *msg){
printf("\n");
printf("Sizeof MSG = %zu\n", sizeof(msg));
printf("Length of MSG = %zu\n", strlen(msg));
}
int main(void) {
char msg[10] = "Michi";
printf("Sizeof MSG = %zu\n", sizeof(msg));
printf("Length of MSG = %zu\n", strlen(msg));
foo(msg);
return 0;
}
输出:
Sizeof MSG = 10
Length of MSG = 5
Sizeof MSG = 8
Length of MSG = 5
为什么Sizeof MSG = 10
位于main
内?因为您打印了数组的大小。
为什么Sizeof MSG = 8
位于foo
内?因为你打印指针的大小,你的机器(就像我的)恰好是8
。
当用作函数参数时,数组衰减指向其第一个元素。
换句话说,这样的事情:
#include <stdio.h>
#include <string.h>
void foo(int *msg){
printf("\n");
printf("Sizeof MSG = %zu\n", sizeof(msg));
printf("Length of MSG = %zu\n", strlen(msg));
}
int main(void) {
int msg[10] = {1,2,3,4,5};
printf("Sizeof MSG = %zu\n", sizeof(msg));
printf("Length of MSG = %zu\n", strlen(msg));
foo(msg);
return 0;
}
不行,可能你的编译器会警告你:
error: passing argument 1 of ‘strlen’ from incompatible pointer type
因为strlen
定义如下:
size_t strlen(const char *str)
您可以看到strlen
需要char*
而不是int*
。
要修复它,你需要传递长度,如下所示:
#include <stdio.h>
#include <string.h>
void foo(int *msg, size_t length){
size_t i=0;
printf("\n\n");
printf("Sizeof MSG = %zu\n",length);
for (i = 0; i<length;i++){
printf("%d ",msg[i]);
}
}
int main(void) {
int msg[] = {1,2,3,4,5,6,7,8,9,10};
size_t length = sizeof msg / sizeof msg[0];
size_t i=0;
printf("\n");
printf("Sizeof MSG = %zu\n",length);
for (i = 0; i<length;i++){
printf("%d ",msg[i]);
}
foo(msg, length);
return 0;
}
输出:
Sizeof MSG = 10
1 2 3 4 5 6 7 8 9 10
Sizeof MSG = 10
1 2 3 4 5 6 7 8 9 10
答案 3 :(得分:0)
在C字符串中,数组不是第一类数据类型,因此不能传递副本。虽然支持参数类型语法char msh[]
,但它与char* msg
具有相同的语义。数组参数语法只是用来向人类开发人员表明函数期望msg
引用数组而不是指向单个项的指针。
如果msg
是一个以空字符结尾的字符串,或者是一个带有sentinel值的数组,则可能不需要传递数组长度,但在许多情况下,这样做很有用。
您可以使用的技巧是将数组包装在struct
中,这是第一类类型,可以通过复制或指针传递。出于性能原因,通过指针传递通常是优选的,但无论哪种方式,成员的大小都是已知的。
typedef struct { char data[32] ; } sMsgContainer ;
void fortune_cookie( const sMsgContainer msg )
{
printf( "Message reads: %s\n", msg.data ) ;
printf( "msg occupies %i bytes\n", sizeof(msg) ) ;
printf( "msg.data occupies %i bytes\n", sizeof(msg.data) ) ;
}
void fortune_cookie2( sMsgContainer* msgp )
{
printf( "Message reads: %s\n", msgp.data ) ;
printf( "msgp occupies %i bytes\n", sizeof(msgp) ) ;
printf( "msgp->data occupies %i bytes\n", sizeof(msg->data) ) ;
}
然后给出:
sMsgContainer msg = {"Cookies make you happy"} ;
fortune_cookie( msg ) ;
fortune_cookie2( &msg ) ;
输出
Message reads: Cookies make you happy
msg occupies 32 bytes
msg.data occupies 32 bytes
Message reads: Cookies make you happy
msgp occupies 4 bytes
msgp->data occupies 32 bytes
出于对齐目的,msg
的长度可能大于msg.data
,但这是实现定义的。