为什么sizeof(msg)比字符串短?

时间:2015-11-19 10:11:06

标签: c pointers

我刚开始学习如何编程,我正在使用这本名为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?为什么它会在不同的机器上返回不同的尺寸?

4 个答案:

答案 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,但这是实现定义的。