¿Cómo encontrar el ‘tamaño de’ (un puntero que apunta a una matriz)?

6 minutos de lectura

avatar de usuario
jkidv

En primer lugar, aquí hay un 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 alguna manera de averiguar el tamaño de la matriz que ptr está apuntando (en lugar de simplemente dar su tamaño, que es de cuatro bytes en un sistema de 32 bits)?

  • Siempre he usado paréntesis con sizeof; seguro que hace que parezca una llamada de función, pero creo que es más claro.

    –Paul Tomblin

    29 de enero de 2009 a las 16:44

  • ¿Por qué no? ¿Tienes algo en contra de los paréntesis superfluos? Creo que se lee un poco más fácilmente con ellos, yo mismo.

    –David Thornley

    29 de enero de 2009 a las 16:44

  • @Paul: bueno… suponiendo que el lado izquierdo de esa llamada sea un puntero a int, lo escribiría como int *ptr = malloc(4 * sizeof *ptr); que para mí es mucho más claro. Menos paréntesis para leer y llevar la constante literal al frente, como en matemáticas.

    – relajarse

    29 de enero de 2009 a las 17:32

  • @unwind: ¡no asigne una serie de punteros cuando se refiere a una serie de enteros!

    –Paul Tomblin

    29 de enero de 2009 a las 17:47

  • Aquí no hay un “puntero que apunte a una matriz”. Solo un puntero que apunta a un int.

    – nueva cuenta

    28 de febrero de 2013 a las 19:01

avatar de usuario
zan lince

La respuesta es no.”

Lo que hacen los programadores de C es almacenar el tamaño de la matriz en alguna parte. Puede ser parte de una estructura, o el programador puede hacer un poco de trampa y malloc() más memoria de la solicitada para almacenar un valor de longitud antes del inicio de la matriz.

  • Así es como se implementan las cadenas de pascal.

    – dsm

    29 de enero de 2009 a las 16:44

  • ¡y aparentemente las cadenas de pascal son la razón por la que Excel se ejecuta tan rápido!

    – Adam Naylor

    14 de julio de 2010 a las 19:48

  • @Adam: Es rápido. Lo uso en una lista de implementación de cadenas mías. Es súper rápido para la búsqueda lineal porque es: cargar tamaño, precargar pos+tamaño, comparar tamaño con tamaño de búsqueda, si es igual a strncmp, pasar a la siguiente cadena, repetir. Es más rápido que la búsqueda binaria hasta unas 500 cadenas.

    – Zan Lince

    14 de julio de 2010 a las 19:52


  • Su código está lleno de comentarios, pero creo que haría todo más fácil si agregara una explicación general de cómo funciona esto fuera del código, como texto normal. ¿Puedes editar tu pregunta y hacerlo? ¡Gracias!

    – Fabio dice Reincorporar a Mónica

    11 de marzo de 2017 a las 12:16

  • Creando una matriz de punteros a cada elemento para que pueda buscarlo linealmente NULL es probablemente la alternativa menos eficiente imaginable a simplemente almacenar una size directamente. Especialmente si en realidad usar esta capa adicional de indirección todo el tiempo.

    – Peter Cordes

    19 de junio de 2018 a las 3:03

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

#define array(type) struct { size_t size; type elem[0]; }

void *array_new(int esize, int ecnt)
{
    size_t *a = (size_t *)malloc(esize*ecnt+sizeof(size_t));
    if (a) *a = ecnt;
    return a;
}
#define array_new(type, count) array_new(sizeof(type),count)
#define array_delete free
#define array_foreach(type, e, arr) \
    for (type *e = (arr)->elem; e < (arr)->size + (arr)->elem; ++e)

int main(int argc, char const *argv[])
{
    array(int) *iarr = array_new(int, 10);
    array(float) *farr = array_new(float, 10);
    array(double) *darr = array_new(double, 10);
    array(char) *carr = array_new(char, 11);
    for (int i = 0; i < iarr->size; ++i) {
        iarr->elem[i] = i;
        farr->elem[i] = i*1.0f;
        darr->elem[i] = i*1.0;
        carr->elem[i] = i+'0';
    }
    array_foreach(int, e, iarr) {
        printf("%d ", *e);
    }
    array_foreach(float, e, farr) {
        printf("%.0f ", *e);
    }
    array_foreach(double, e, darr) {
        printf("%.0lf ", *e);
    }
    carr->elem[carr->size-1] = '\0';
    printf("%s\n", carr->elem);

    return 0;
}

avatar de usuario
Tᴏᴍᴇʀ Wᴏʟʙᴇʀɢ

Puedes hacer algo como esto:

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

avatar de usuario
Pedro Mortensen

Para arreglos dinámicos (malloc o C++ nuevo) necesita almacenar el tamaño de la matriz como lo mencionaron otros o tal vez construir una estructura de administrador de matrices que maneje agregar, eliminar, contar, etc. Desafortunadamente, C no hace esto tan bien como C ++, ya que básicamente tiene que construirlo para cada tipo de matriz diferente que está almacenando, lo cual es engorroso si tiene varios tipos de matrices que necesita administrar.

Para matrices estáticas, como la de su ejemplo, se usa una macro común para obtener el tamaño, pero es no recomendado ya que no verifica si el parámetro es realmente una matriz estática. Sin embargo, la macro se usa en código real, por ejemplo, en los encabezados del kernel de Linux, aunque puede ser ligeramente diferente a la siguiente:

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

Puede buscar en Google por razones para desconfiar de macros como esta. Ten cuidado.

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

  • ARRAY_SIZE es un paradigma común utilizado por programadores prácticos en todas partes.

    – SanjayaR

    29 de enero de 2009 a las 17:19

  • Sí, es un paradigma común. Sin embargo, aún debe usarlo con precaución, ya que es fácil de olvidar y usarlo en una matriz dinámica.

    – Ryan

    29 de enero de 2009 a las 17:27

  • Sí, buen punto, pero la pregunta que se hizo fue sobre el puntero, no el de matriz estática.

    –Paul Tomblin

    29 de enero de 2009 a las 17:40

  • Ese ARRAY_SIZE macro siempre funciona si su argumento es una matriz (es decir, expresión del tipo de matriz). Para su llamada “matriz dinámica”, nunca obtiene una “matriz” real (expresión del tipo de matriz). (Por supuesto, no puede, ya que los tipos de matriz incluyen su tamaño en tiempo de compilación). Solo obtiene un puntero al primer elemento. Su objeción “no verifica si el parámetro es realmente una matriz estática” no es realmente válida, ya que son diferentes ya que una es una matriz y la otra no.

    – nueva cuenta

    28 de febrero de 2013 a las 18:52


  • Hay una función de plantilla flotando que hace lo mismo pero evitará el uso de punteros.

    – Natalia Adams

    23 de abril de 2013 a las 2:24

¿Ha sido útil esta solución?