Primero, aquí está el código:

int main() 
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", sizeof(days));
    printf("%u\n", sizeof(ptr));

    return 0;
}

Hay una forma de averiguar el tamaño de la matriz que ptr apunta (en lugar de sólo dar a su tamaño, que es de cuatro bytes en un sistema de 32 bits)?

  • Yo siempre he usado paréntesis con sizeof – seguro que lo hace ver como una llamada a una función, pero creo que es más claro.
  • ¿Por qué no? ¿Tienes algo en contra de superfluo paréntesis? Creo que lee un poco más fácilmente con ellos, a mí mismo.
  • Especialmente si estás haciendo algo como malloc(sizeof(int) * 4).
  • Heh. Me parece que estorban, y … sin sentido, ya que lo hace se ve como una llamada a una función, que en realidad no lo es. No considero que claro.
  • bueno .. suponiendo que el lado izquierdo de la llamada que es un puntero a int, me gustaría escribir como int *ptr = malloc(4 * sizeof *ptr); lo que para mí es mucho más clara. Menos paréntesis para leer, y llevar el literal constsant al frente, como en las matemáticas.
  • no asignar una matriz de punteros cuando significaba una matriz de enteros!
  • No hay un «puntero que apunta a una matriz» aquí. Sólo un puntero que apunta a un int.
  • Algunos compiladores tienen construido ins para este propósito, gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html

InformationsquelleAutor jkidv | 2009-01-29

13 Comentarios

  1. 245

    No, No puede. El compilador no sabe lo que el puntero apunta. Hay trucos, como la conclusión de la matriz con un conocido fuera-de-banda de valor y, a continuación, contando el tamaño hasta ese valor, pero que no está usando sizeof.

    Otro truco es el mencionado por Zan, que es para guardar el tamaño en algún lugar. Por ejemplo, si usted es la asignación dinámica de la matriz, asignar un bloque de un entero (int) más grande que el que usted necesita, alijo que el tamaño de la primera de tipo int, y volver ptr+1 como el puntero a la matriz. Cuando usted necesita el tamaño, decrementar el puntero y dar un vistazo a la escondidos valor. Sólo recuerde para liberar el bloque entero desde el principio, y no sólo la matriz.

    • Lo siento por esta publicación de un comentario tan tarde pero si el compilador no sabe lo que es el puntero que apunta a cómo lo hace libre de saber cuánta memoria queda claro? Sé que esta información se almacena internamente para funciones como de uso libre. Así que mi pregunta es ¿por qué’ el compilador de hacerlo también?
    • porque la libre descubre el tamaño en tiempo de ejecución. El compilador no puede saber el tamaño, ya que podría hacer que la matriz de un tamaño diferente dependiendo del tiempo de ejecución de factores (argumentos de línea de comandos, el contenido de un archivo, fase de la luna,etc).
    • Rápido de seguimiento, ¿por qué no hay una función que puede devolver el tamaño de la forma libre ¿?
    • Bueno, si se pudiera garantizar que la función se llama sólo con malloced la memoria y la biblioteca de pistas de la malloced la memoria la forma en que la mayoría de los que he visto hacer (mediante el uso de un int antes de que el puntero devuelto), entonces usted podría escribir uno. Pero si el puntero es una matriz estática o similares, sería un fracaso. Del mismo modo, no hay ninguna garantía de que el tamaño de malloced memoria es accesible para el programa.
    • No es este un problema si el puntero no está dentro de ningún memoria asignada a todos? Nunca seríamos capaces de encontrar el fuera-de-banda de valor ni deberíamos ser capaces de encontrar el escondido tamaño de la matriz. Estoy fuera de aquí?
    • hay un montón de problemas con los «trucos». Por eso me llamó trucos. La lengua no proporcionan un soporte robusto para descubrir el lado de una asignación de la matriz, y va a ser para usted para encontrar la solución adecuada para su caso de uso.
    • ¿cree usted que hay una manera mejor de hacerlo en un lenguaje intermedio? Decir, LLVM IR?
    • Otra cosa a tener en cuenta es que el tamaño de la registrada por el malloc/free el sistema puede no ser el tamaño que usted pidió. Usted malloc 9 bytes y obtener 16. Malloc 3K bytes y obtener 4K. O situaciones similares.
    • Puede usted explicar cuál es la diferencia entre los días y las ptr es? Ambos son punteros de entero que contiene la dirección del primer elemento de la matriz.
    • Tiene una tarjeta de identificación.
    • Es posible que si se pasa el puntero a toda la matriz como char (*ptr)[tamaño] ? En este caso ptr se define como char (*ptr)[tamaño] = &días;. Pero no estoy seguro de cómo podemos obtener el tamaño dentro de la función.
    • no, eso no ayudará. El puntero no conserva la información de tamaño.

  2. 76

    La respuesta es «No».

    Lo que los programadores de C hacer es almacenar el tamaño de la matriz en algún lugar. Puede ser parte de una estructura, o el programador puede hacer un poco de trampa y malloc() más memoria de la que ha sido solicitada con el fin de almacenar un valor de longitud antes del inicio de la matriz.

    • Eso es lo que pascal cadenas se implementan
    • y al parecer las cadenas pascal son la razón de excel se ejecuta tan rápido!
    • Es rápido. Yo lo uso en una lista de cadenas de aplicación de la mina. Es super-rápida búsqueda lineal porque es: el tamaño de la carga, prefetch pos+tamaño, comparar el tamaño de buscar el tamaño, si la igualdad de strncmp, mover a la siguiente cadena, repetir. Es más rápido que el binario de búsqueda hasta cerca de 500 cadenas.
  3. 45

    Para la dinámica de las matrices (malloc o C++ nueva) que usted necesita para almacenar el tamaño de la matriz como se ha mencionado por otros o tal vez crear un administrador de la matriz de la estructura que se encarga de agregar, quitar, contar, etc. Desafortunadamente C no hacer esto tan bien como C++, ya que, básicamente, tiene que construir para cada matriz diferente tipo de almacenamiento que es engorroso si tiene varios tipos de matrices que usted necesita para administrar.

    Para las matrices estáticas, tales como el de tu ejemplo, es común la macro utiliza para obtener el tamaño, pero es no se recomienda como no comprueba si el parámetro es realmente una matriz estática. La macro se utiliza en el código real, aunque, por ejemplo, en las cabeceras del kernel de Linux, aunque puede ser ligeramente distinto al de abajo:

    #if !defined(ARRAY_SIZE)
        #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
    #endif
    
    int main()
    {
        int days[] = {1,2,3,4,5};
        int *ptr = days;
        printf("%u\n", ARRAY_SIZE(days));
        printf("%u\n", sizeof(ptr));
        return 0;
    }

    Usted puede buscar en google por razones para desconfiar de las macros como este. Tener cuidado.

    Si es posible, el C++ stdlib tales como el vector que es mucho más seguro y más fácil de usar.

    • ARRAY_SIZE es un paradigma común utilizado por la experiencia de los programadores de todas partes.
    • Sí, es un paradigma común. Usted todavía tiene que utilizar con cautela, aunque como es fácil olvidar y utilizar en una matriz dinámica.
    • Sí, buen punto, pero la pregunta era sobre el puntero, no el de la estática de la matriz de uno.
    • Que ARRAY_SIZE macro siempre funciona si su argumento es una matriz (es decir, la expresión de la matriz de tipo). Por su llamada «matriz dinámica», nunca se obtiene una «matriz» (expresión del tipo de matriz). (Por supuesto, no se puede, ya que los tipos de matriz incluyen su tamaño en tiempo de compilación.) Usted acaba de obtener un puntero al primer elemento. Su objeción «no comprueba si el parámetro es realmente una matriz estática» no es realmente válida, ya que son diferentes uno es una matriz y la otra no.
    • Hay una función de plantilla flotando alrededor que hace la misma cosa, pero evitar el uso de punteros.
    • Creo que se quedan atrapados en la semántica. Mi punto era, simplemente, que las macros no tienen la comprobación de tipos. Si se pasa un puntero a la macro, usted no va a obtener el resultado deseado. Si usted puede utilizar las plantillas de C++ equivalente, es más seguro, pero el OP le preguntó acerca de C.
    • El ARRAY_SIZE macro, con un nombre diferente, se utiliza en K&R C 2ª edición. No es una buena práctica en la actualidad, pero el lenguaje no ofrece una solución.

  4. 17

    Hay una solución limpia con las plantillas de C++, sin el uso de sizeof(). El siguiente getSize() función devuelve el tamaño de una matriz estática:

    #include <cstddef>
    
    template<typename T, size_t SIZE>
    size_t getSize(T (&)[SIZE]) {
        return SIZE;
    }

    Aquí está un ejemplo con un foo_t estructura:

    #include <cstddef>
    
    template<typename T, size_t SIZE>
    size_t getSize(T (&)[SIZE]) {
        return SIZE;
    }
    
    struct foo_t {
        int ball;
    };
    
    int main()
    {
        foo_t foos3[] = {{1},{2},{3}};
        foo_t foos5[] = {{1},{2},{3},{4},{5}};
        printf("%u\n", getSize(foos3));
        printf("%u\n", getSize(foos5));
    
        return 0;
    }

    De salida:

    3
    5
    • Yo nunca he visto la notación T (&)[SIZE]. Puede usted explicar lo que esto significa? También se podría mencionar constexpr en este contexto.
    • Que bueno si usas c++ y, en realidad tiene una variable de un tipo de matriz. Ninguno de ellos es el caso de la pregunta: el Lenguaje es C, y la cosa que el OP quiere obtener el tamaño de la matriz es un simple puntero.
    • sería este código conducir a código de la hinchazón por recrear el mismo código diferente para cada tamaño y tipo de combinación o es que por arte de magia optimizado de la existencia por el compilador?
    • Que la sintaxis de C++ para una referencia de tipo de matriz (sin nombre de la variable, sólo un tamaño y tipo elemento).
    • Esta función está optimizado del todo en tiempo de compilación; no hay magia que se necesita; no combina nada a una sola definición, es simplemente inline se la llevó a un constante en tiempo de compilación. (Pero en una versión de depuración, sí, usted tiene un montón de funciones separadas que volver constantes diferentes. Enlazador de la magia puede combinar aquellos que utilizan la misma constante. El autor de la llamada no pasa SIZE como un arg, es una plantilla param que tiene que ser ya conocido por la definición de la función.)
    • Como de C++17, tenemos std::size(), que es similar a su getSize() función y además tiene una sobrecarga para los contenedores, que proporcionan una size() función miembro.

  5. 5

    Para este ejemplo específico, sí, lo hay, SI utiliza las definiciones de tipos (ver más abajo). Por supuesto, si lo haces de esta manera, estás igual de bien fuera para uso SIZEOF_DAYS, ya que usted sabe lo que el puntero apunta.

    Si usted tiene un (void *) puntero, como es devuelto por malloc() o similares, entonces, no, no hay ninguna manera de determinar qué estructura de datos es el puntero que apunta a y por lo tanto, no hay manera de determinar su tamaño.

    #include <stdio.h>
    
    #define NUM_DAYS 5
    typedef int days_t[ NUM_DAYS ];
    #define SIZEOF_DAYS ( sizeof( days_t ) )
    
    int main() {
        days_t  days;
        days_t *ptr = &days; 
    
        printf( "SIZEOF_DAYS:  %u\n", SIZEOF_DAYS  );
        printf( "sizeof(days): %u\n", sizeof(days) );
        printf( "sizeof(*ptr): %u\n", sizeof(*ptr) );
        printf( "sizeof(ptr):  %u\n", sizeof(ptr)  );
    
        return 0;
    } 

    De salida:

    SIZEOF_DAYS:  20
    sizeof(days): 20
    sizeof(*ptr): 20
    sizeof(ptr):  4
  6. 4

    No hay ninguna solución mágica. C no es un reflexivo de la lengua. Los objetos no se sabe automáticamente lo que son.

    Pero usted tiene muchas opciones:

    1. Obviamente, agregar un parámetro
    2. Envoltura de la llamada en una macro y agregar automáticamente un parámetro
    3. El uso de un objeto más complejo. Definir una estructura que contiene la matriz dinámica y también el tamaño de la matriz. A continuación, pasa la dirección de la estructura.
  7. 3

    Como todas las respuestas correctas que se han dicho, usted no puede obtener esta información a partir de la caries puntero de valor de la matriz a solas. Si la caries puntero es el argumento recibido por la función, el tamaño de los originarios de la matriz tiene que ser proporcionada en alguna otra forma para que la función llegado a saber que tamaño.

    He aquí una sugerencia diferente de lo que se ha hecho hasta ahora,que va a trabajar: Pasar un puntero a la matriz en su lugar. Esta propuesta es similar a la de C++ estilo de sugerencias, excepto que el C no admite plantillas o referencias:

    #define ARRAY_SZ 10
    
    void foo (int (*arr)[ARRAY_SZ]) {
        printf("%u\n", (unsigned)sizeof(*arr)/sizeof(**arr));
    }

    Pero, esta sugerencia es un poco tonto para su problema, ya que la función está definida para conocer exactamente el tamaño de la matriz que se pasa (por lo tanto, hay poca necesidad de usar sizeof a todos en la matriz). Lo que sí hace, sin embargo, es ofrecer algún tipo de seguridad. Se va a prohibir el paso en una matriz de un tamaño indeseado.

    int x[20];
    int y[10];
    foo(&x); /* error */
    foo(&y); /* ok */

    Si la función se supone para ser capaces de operar sobre cualquier tamaño de la matriz, entonces usted tendrá que proporcionar el tamaño de la función como información adicional.

    • +1 para que «no Se puede obtener esta información a partir de la caries valor del puntero de la matriz solos» y proporcionar una solución.
  8. 2

    Mi solución a este problema es para guardar la longitud de la matriz en una estructura de Matriz como una meta-información acerca de la matriz.

    #include <stdio.h>
    #include <stdlib.h>
    
    struct Array
    {
        int length;
    
        double *array;
    };
    
    typedef struct Array Array;
    
    Array* NewArray(int length)
    {
        /* Allocate the memory for the struct Array */
        Array *newArray = (Array*) malloc(sizeof(Array));
    
        /* Insert only non-negative length's*/
        newArray->length = (length > 0) ? length : 0;
    
        newArray->array = (double*) malloc(length*sizeof(double));
    
        return newArray;
    }
    
    void SetArray(Array *structure,int length,double* array)
    {
        structure->length = length;
        structure->array = array;
    }
    
    void PrintArray(Array *structure)
    {       
        if(structure->length > 0)
        {
            int i;
            printf("length: %d\n", structure->length);
            for (i = 0; i < structure->length; i++)
                printf("%g\n", structure->array[i]);
        }
        else
            printf("Empty Array. Length 0\n");
    }
    
    int main()
    {
        int i;
        Array *negativeTest, *days = NewArray(5);
    
        double moreDays[] = {1,2,3,4,5,6,7,8,9,10};
    
        for (i = 0; i < days->length; i++)
            days->array[i] = i+1;
    
        PrintArray(days);
    
        SetArray(days,10,moreDays);
    
        PrintArray(days);
    
        negativeTest = NewArray(-5);
    
        PrintArray(negativeTest);
    
        return 0;
    }

    Pero debes tener cuidado acerca de establecer el derecho de la longitud de la matriz que desea guardar, porque no hay forma de comprobar esta longitud, como nuestros amigos de forma masiva, explicó.

  9. 2
    int main() 
    {
        int days[] = {1,2,3,4,5};
        int *ptr = days;
        printf("%u\n", sizeof(days));
        printf("%u\n", sizeof(ptr));
    
        return 0;
    }

    Tamaño de los días[] es de 20 que no es de los elementos * tamaño del tipo de datos.
    Mientras que el tamaño de puntero es de 4 no importa lo que está señalando.
    Porque un puntero que señala a otro elemento mediante el almacenamiento de su dirección.

    • sizeof(ptr) es el tamaño del puntero y sizeof(*ptr) es el tamaño del puntero para que
  10. 1

    No, usted no puede utilizar sizeof(ptr) para encontrar el tamaño de la matriz de la ptr está señalando.

    A pesar de que la asignación de memoria adicional(más que el tamaño de la matriz) será útil si desea almacenar la longitud de espacio extra.

  11. 0
     #define array_size 10
    
     struct {
         int16 size;
         int16 array[array_size];
         int16 property1[(array_size/16)+1]
         int16 property2[(array_size/16)+1]
     } array1 = {array_size, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    
     #undef array_size

    array_size es pasar a la tamaño variable:

    #define array_size 30
    
    struct {
        int16 size;
        int16 array[array_size];
        int16 property1[(array_size/16)+1]
        int16 property2[(array_size/16)+1]
    } array2 = {array_size};
    
    #undef array_size

    De uso es:

    void main() {
    
        int16 size = array1.size;
        for (int i=0; i!=size; i++) {
    
            array1.array[i] *= 2;
        }
    }
  12. -1

    hola en cadenas es un '\0' carácter al final lo que uno puede obtener el tamaño
    de una cadena de caracteres con funciones como strlen el problema con una matriz de enteros, por ejemplo, es que u no puede usar cualquier valor como un valor final para una posible solución es la dirección de la matriz y su uso como un valor final de la NULL puntero

    /* http://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array */
    #include <stdio.h>
    /* the following function will produce the warning:
     * ‘sizeof’ on array function parameter ‘a’ will
     * return size of ‘int *’ [-Wsizeof-array-argument]
     */
    void foo( int a[] )
    {
        printf( "%lu\n", sizeof a );
    }
    /* so we have to implement something else one possible
     * idea is to use the NULL pointer as a control value
     * the same way '\0' is used in strings but this way
     * the pointer passed to a function should address pointers
     * so the actual implementation of an array type will
     * be a pointer to pointer
     */
    typedef char * type_t; /* line 18 */
    typedef type_t ** array_t;
    /*
     *    -- --
     *   -**-**-
     *   -$$$$$-
     *    -999-
     *     -^-
     *      -
     */
    int main( void )
    {
        array_t initialize( int, ... );
        /* initialize an array with four values "foo", "bar", "baz", "foobar"
         * if one wants to use integers rather than strings than in the typedef
         * declaration at line 18 the char * type should be changed with int
         * and in the format used for printing the array values 
         * at line 45 and 51 "%s" should be changed with "%i"
         */
        array_t array = initialize( 4, "foo", "bar", "baz", "foobar" );
    
        int size( array_t );
        /* print array size */
        printf( "size %i:\n", size( array ));
    
        void aprint( char *, array_t );
        /* print array values */
        aprint( "%s\n", array ); /* line 45 */
    
        type_t getval( array_t, int );
        /* print an indexed value */
        int i = 2;
        type_t val = getval( array, i );
        printf( "%i: %s\n", i, val ); /* line 51 */
    
        void delete( array_t );
        /* free some space */
        delete( array );
    
        return 0;
    }
    /* the output of the program should be:
     * size 4:
     * foo
     * bar
     * baz
     * foobar
     * 2: baz
     */
    #include <stdarg.h>
    #include <stdlib.h>
    array_t initialize( int n, ... )
    {
        /* here we store the array values */
        type_t *v = (type_t *) malloc( sizeof( type_t ) * n );
        va_list ap;
        va_start( ap, n );
        int j;
        for ( j = 0; j < n; j++ )
            v[j] = va_arg( ap, type_t );
        va_end( ap );
        /* the actual array will hold the addresses of those
         * values plus a NULL pointer
         */
        array_t a = (array_t) malloc( sizeof( type_t *) * ( n + 1 ));
        a[n] = NULL;
        for ( j = 0; j < n; j++ )
            a[j] = v + j;
        return a;
    }
    int size( array_t a )
    {
        int n = 0;
        while ( *a++ != NULL )
            n++;
        return n;
    }
    void aprint( char *fmt, array_t a )
    {
        while ( *a != NULL )
            printf( fmt, **a++ );   
    }
    type_t getval( array_t a, int i )
    {
        return *a[i];
    }
    void delete( array_t a )
    {
        free( *a );
        free( a );
    }
    /* край */
    • El código está lleno de comentarios, pero creo que haría todo más fácil si agrega algunos explicación general de cómo funciona esto fuera de código, como texto normal. Puede usted por favor editar a su pregunta y a hacerlo? Gracias!
    • Creación de una matriz de punteros a cada elemento de modo que usted puede lineal-buscar para NULL es probablemente la menos eficiente alternativa imaginable para almacenar separado size directamente. Especialmente si usted en realidad con esta capa extra de indirección todo el tiempo.

Dejar respuesta

Please enter your comment!
Please enter your name here