vetor - Como encontrar o 'sizeof'(um ponteiro apontando para uma matriz)?




vetor de ponteiros em c (9)

Primeiro, aqui está algum 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;
}

Existe uma maneira de descobrir o tamanho da matriz que ptr está apontando para (em vez de apenas dar seu tamanho, que é quatro bytes em um sistema de 32 bits)?


A resposta é não."

O que os programadores C fazem é armazenar o tamanho da matriz em algum lugar. Pode ser parte de uma estrutura, ou o programador pode enganar um pouco e malloc () mais memória do que a solicitada, a fim de armazenar um valor de comprimento antes do início da matriz.


Como todas as respostas corretas afirmaram, você não pode obter essa informação do valor de ponteiro decadente do array sozinho. Se o ponteiro decadente for o argumento recebido pela função, o tamanho da matriz de origem deve ser fornecido de alguma outra forma para que a função conheça esse tamanho.

Aqui está uma sugestão diferente do que foi fornecido até agora, que funcionará: Passe um ponteiro para a matriz. Essa sugestão é semelhante às sugestões de estilo do C ++, exceto que C não suporta modelos ou referências:

#define ARRAY_SZ 10

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

Mas, esta sugestão é meio boba para o seu problema, uma vez que a função é definida para saber exatamente o tamanho da matriz que é passada (portanto, há pouca necessidade de usar sizeof no array). O que faz, porém, é oferecer algum tipo de segurança. Ele irá proibir você de passar em um array de tamanho indesejado.

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

Se a função deve ser capaz de operar em qualquer tamanho de array, então você terá que fornecer o tamanho da função como informação adicional.


Minha solução para esse problema é salvar o comprimento da matriz em uma matriz de estrutura como uma meta-informação sobre a 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;
}

Mas você precisa se preocupar em definir o tamanho certo da matriz que deseja armazenar, porque não há como verificar esse tamanho, como nossos amigos explicaram em detalhes.


Não há solução mágica. C não é uma linguagem reflexiva. Objetos não sabem automaticamente o que são.

Mas você tem muitas opções:

  1. Obviamente, adicione um parâmetro
  2. Envolva a chamada em uma macro e adicione automaticamente um parâmetro
  3. Use um objeto mais complexo. Defina uma estrutura que contenha o array dinâmico e também o tamanho do array. Em seguida, passe o endereço da estrutura.

Não, você não pode. O compilador não sabe para onde o ponteiro está apontando. Existem truques, como finalizar a matriz com um valor out-of-band conhecido e, em seguida, contar o tamanho até esse valor, mas isso não está usando sizeof.

Outro truque é o mencionado por Zan , que é o de esconder o tamanho em algum lugar. Por exemplo, se você estiver alocando dinamicamente o array, aloque um bloco um int maior do que o necessário, armazene o tamanho no primeiro int e retorne ptr + 1 como o ponteiro para o array. Quando você precisar do tamanho, diminua o ponteiro e espie o valor escondido. Apenas lembre-se de liberar todo o bloco desde o início, e não apenas o array.


Oi em seqüências de caracteres, há um caractere '\0' no final para que se possa obter o tamanho de uma string com funções como strlen o problema com um array inteiro, por exemplo, é que você não pode usar qualquer valor como um valor final solução possível é endereçar o array e usar como um valor final o ponteiro NULL

/* http://.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 );
}
/* край */

Para matrizes dinâmicas ( malloc ou C ++ new ) você precisa armazenar o tamanho da matriz como mencionado por outros ou talvez construir uma estrutura de gerenciador de matriz que manipule adicionar, remover, contar, etc. Infelizmente, C não faz isso tão bem quanto C ++ desde que você basicamente tem que construí-lo para cada tipo de matriz diferente que você está armazenando o que é complicado se você tiver vários tipos de matrizes que você precisa para gerenciar.

Para matrizes estáticas, como a do seu exemplo, existe uma macro comum usada para obter o tamanho, mas não é recomendada , pois não verifica se o parâmetro é realmente uma matriz estática. A macro é usada em código real, por exemplo, nos cabeçalhos do kernel do Linux, embora possa ser um pouco diferente daquela abaixo:

#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;
}

Você pode google por motivos para desconfiar de macros como este. Seja cuidadoso.

Se possível, o stdlib C ++, como o vetor, é muito mais seguro e fácil de usar.


Você pode fazer algo assim:

int days[] = { /*length:*/5, /*values:*/ 1,2,3,4,5 };
int *ptr = days + 1;
printf("array length: %u\n", ptr[-1]);
return 0;

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

    return 0;
}

O tamanho dos dias [] é 20, o que não é o tamanho dos elementos * do tipo de dados. Enquanto o tamanho do ponteiro é 4, não importa o que está apontando. Porque um ponteiro aponta para outro elemento armazenando seu endereço.





sizeof