2015-11-19 3 views
3

Я только начал изучать, как программировать, и я использую эту книгу под названием Head First C. В этой книге есть разделы в разделе Brain Power. В одном из этих разделов было написано.Почему sizeof (msg) короче строки?

void fortune_cookie(char msg[]) 
{ 
    printf("Message reads: %s\n", msg); 
    printf("msg occupies %i bytes\n", sizeof(msg)); 
} 

Выход:

печенье сделать вас жир

тзд занимает 8 байт

Вопрос Brain Держава: Почему вы думаете, sizeof(msg) короче, чем длина всей строки? Что такое msg? Почему он будет возвращать разные размеры на разных машинах?

+0

Возможный дубликат [Как найти «sizeof» (указатель, указывающий на массив)?] (Http://stackoverflow.com/questions/492384/how-to-find-the-sizeofa-pointer-pointing -to-an-array) – BlackDwarf

ответ

3

В данном конкретном случае

char msg[] 

такой же, как

char * msg 

так, что вы действительно видите, является выход sizeof(char *).

Поскольку размер указателя зависит от архитектуры/компилятора, вы увидите другой вывод на другой машине.

Кроме того, обратите внимание, что оператор sizeof производит результат типа size_t, вы должны использовать спецификатор формата %zu, чтобы распечатать результат.

2

Как вы думаете, размер size (msg) короче длины всей строки?

Потому что arrays распад указателей при передаче в качестве параметров некоторой функции.

int arr[10]; 
printf("%zu", sizeof(arr)); 

Это вернет 40. Учитывая размер int является 4

Но при отправке функции

void func(int arr[]) 
{ 
    printf("%lu", sizeof(arr)); 
} 

Это возвращение было sizeof(int*)


Что такое сообщ?

msg - массив из char, который отправляется функции.


Почему бы это вернуть differentsizes на разных машинах?

Поскольку размер адреса памяти будет отличаться для разных архитектур машин, делая таким образом sizeof(int*).

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 
+0

Вы имеете в виду 'шт' не' мир' –

+0

@BasileStarynkevitch OOOPS, спасибо: D – Michi

0

В строках С и массивы не являются типы данных первого класса, так не может быть Пройдена копия. Хотя поддерживается синтаксис типа аргумента char msh[], он имеет идентичную семантику до char* msg. Синтаксис аргумента массива делает немного больше, чем показывать человеческому разработчику, что функция ожидает, что msg ссылается на массив, а не на указатель на один элемент.

Где msg - это строка с нулевым завершением или массив со значением часового, возможно, нет необходимости передавать длину массива, но во многих случаях это полезно сделать.

Трюк, который вы можете использовать, состоит в том, чтобы обернуть массив в 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 для целей выравнивания, но это зависит от реализации.

Смежные вопросы