Получение размера массива в C. Не могу понять вывод - PullRequest
2 голосов
/ 13 декабря 2011

Мне любопытно, почему я получаю следующее поведение в своем коде.

#include <stdio.h>
#include <stdlib.h>


int main(int argc, char *argv[])
{
    int M=24;
    int arr[M];
    int N=24;
    int* ptr=(int*) malloc(sizeof(int)*N); /*Allocate memory of size N  */

    printf("Size of your malloced array is %lu\n",sizeof(ptr)/sizeof(ptr[0])); /* Get the size of memory alloctaed. Should be the same as N?*/

    printf ("Size of your normal arrays is %lu\n",sizeof(arr)/sizeof(arr[0])); /* Ditto  */

    free(ptr);

    return 0;
}

Вывод

Size of your malloced array is 2
Size of your normal arrays is 24

Я бы подумал, что вывод будет 24 в обоих местах.Как тогда получить размер ошибочного массива? Если я как-то "забыл" его?

Конечно, указатель ptr будет содержать некоторую информацию о размере ошибочного массива, так как когда мы вызываем free(ptr), он освобождает массив только с неправильной привязкой

Ответы [ 6 ]

7 голосов
/ 13 декабря 2011

Когда вы используете sizeof() для указателя, вы получаете размер указателя. Не размер выделенного массива. В вашем случае указатель составляет, вероятно, 8 байт, а int - 4 байта, поэтому вы получаете 2.

Короче говоря, вы не можете получить размер выделенного массива. Вы должны следить за этим самостоятельно.


РЕДАКТИРОВАТЬ: Обратите внимание, что некоторые компиляторы действительно поддерживают эту функцию в качестве расширения:

Например, MSVC поддерживает _msize(): http://msdn.microsoft.com/en-us/library/z2s077bc.aspx

3 голосов
/ 13 декабря 2011

Хотя sizeof() работает как вы ожидаете с массивами фиксированной длины и переменной длины, он ничего не знает о размерах malloc() 'ed массивов.

При применении к указателю sizeof() просто возвращает размер указателя.

В более общем смысле, учитывая указатель на malloc() 'ed блок, стандартного способа определить размер этого блока не существует.

См. Вопросы и ответы по C 7,27 и 7,28 .

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

1 голос
/ 13 декабря 2011

Вы не можете получить во время выполнения размер массива, если у вас есть только указатель на (первый элемент) массива. В C нет конструкций, позволяющих вам это сделать. Вы должны сами следить за длиной.

Если у вас есть массив, а не указатель, вы можете найти его длину, но не указатель на элемент массива.

В вашем коде ptr является указателем, и поэтому вы не можете определить длину массива, на который он указывает. С другой стороны, arr является массивом, и вы можете узнать его длину с помощью sizeof(arr)/sizeof(arr[0]).

0 голосов
/ 14 декабря 2011

Следует помнить о sizeof, что это время компиляции оператор 1 ;он возвращает количество байтов на основе типа операнда.

Тип arr равен int [24], поэтому sizeof arr будет соответствовать количеству байтов, необходимому для хранения 24 int значений.Тип ptr равен int *, поэтому sizeof ptr будет соответствовать количеству байтов, необходимых для хранения одного значения int *.Поскольку это происходит во время компиляции, у sizeof нет способа узнать, на какой блок памяти ptr указывает или насколько он велик.

Как правило, вы не можете определить, на какой объем памяти указывает указатель, исходя из самого значения указателя;эта информация должна отслеживаться отдельно.

Стилистический нит: предпочтительный способ написать вызов malloc -

int *ptr = malloc(sizeof *ptr * N);

В C вам не нужно приводить результат malloc к целевому типу указателя 2 , и это может скрыть полезную диагностику, если вы забудете включить stdlib.h или иным образом не иметь прототип для malloc в области видимости.

Во-вторых, обратите внимание, что я передаю выражение *ptr в качестве операнда sizeof, а не (int).Это минимизирует количество ошибок в случае, если вы измените тип ptr, но забудете изменить тип в соответствующем вызове malloc.Это работает, потому что sizeof не пытается оценить операнд (то есть он не пытается разыменовать ptr);он вычисляет только свой тип .


1 Исключение из этого правила возникает, когда sizeof применяется к массиву переменной длины;поскольку размер массива не определен до времени выполнения, оператор sizeof, примененный к VLA, будет оцениваться во время выполнения.

2 Обратите внимание, что это не случай в C ++;приведение требуется, но если вы пишете на C ++, вы должны все равно использовать new и delete вместо malloc и free.Кроме того, это верно только с C89;в старых версиях C malloc возвращалось char * вместо void *, поэтому для этих версий требовалось приведение .Если вы не работаете над очень старой реализацией (такой как старый VAX mini, на котором установлена ​​древняя версия VMS), это не должно быть проблемой.
0 голосов
/ 13 декабря 2011

Как указывает этот другой вопрос , не существует переносимого способа получения размера динамического массива, поскольку malloc может выделить больше памяти, чем запрошено. Кроме того, управление запросами malloc зависит от операционной системы. Например, * nix вызовет sbrk и сохранит запросы где-нибудь. Итак, когда вы вызываете sizeof(ptr), он возвращает размер указателя, а не размер массива. С другой стороны, если ваш массив фиксирован, его размер определяется во время компиляции, поэтому компилятор может заменить sizeof(arr) размером фиксированного массива, что обеспечит вам «правильный» размер.

0 голосов
/ 13 декабря 2011

Размер указателя составляет 4 байта на 32-битных машинах и 8 байтов на 64-битных машинах. Я предполагаю, что вы работаете на 64-битной машине, так как размер int равен 4, и вы получили, что sizeof(ptr)/sizeof(ptr[0]) равно 2.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...