Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

586
Views
¿Cómo determina este fragmento de código el tamaño del arreglo sin usar sizeof()?

Al revisar algunas preguntas de la entrevista de C, encontré una pregunta que decía "¿Cómo encontrar el tamaño de una matriz en C sin usar el operador sizeof?", Con la siguiente solución. Funciona, pero no puedo entender por qué.

 #include <stdio.h> int main() { int a[] = {100, 200, 300, 400, 500}; int size = 0; size = *(&a + 1) - a; printf("%d\n", size); return 0; }

Como era de esperar, devuelve 5.

editar: la gente señalóesta respuesta, pero la sintaxis difiere un poco, es decir, el método de indexación

 size = (&arr)[1] - arr;

así que creo que ambas preguntas son válidas y tienen un enfoque ligeramente diferente del problema. ¡Gracias a todos por la inmensa ayuda y la explicación detallada!

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Esta línea es de suma importancia:

 size = *(&a + 1) - a;

Como puede ver, primero toma la dirección de a y le agrega una. Luego, elimina la referencia de ese puntero y le resta el valor original de a .

La aritmética de punteros en C hace que esto devuelva el número de elementos en la matriz, o 5 . Agregar uno y &a es un puntero a la siguiente matriz de 5 int s después a . Después de eso, este código elimina la referencia del puntero resultante y resta a (un tipo de matriz que se ha convertido en un puntero) de eso, dando el número de elementos en la matriz.

Detalles sobre cómo funciona la aritmética de punteros:

Digamos que tiene un puntero xyz que apunta a un tipo int y contiene el valor (int *)160 . Cuando resta cualquier número de xyz , C especifica que la cantidad real restada de xyz es ese número multiplicado por el tamaño del tipo al que apunta. Por ejemplo, si restaste 5 de xyz , el valor de xyz resultante sería xyz - (sizeof(*xyz) * 5) si no se aplicara la aritmética de punteros.

Como a es una matriz de 5 tipos int , el valor resultante será 5. Sin embargo, esto no funcionará con un puntero, solo con una matriz. Si intenta esto con un puntero, el resultado siempre será 1 .

Aquí hay un pequeño ejemplo que muestra las direcciones y cómo esto no está definido. El lado izquierdo muestra las direcciones:

 a + 0 | [a[0]] | &a points to this a + 1 | [a[1]] a + 2 | [a[2]] a + 3 | [a[3]] a + 4 | [a[4]] | end of array a + 5 | [a[5]] | &a+1 points to this; accessing past array when dereferenced

Esto significa que el código resta a de &a[5] (o a+5 ), dando 5 .

Tenga en cuenta que este es un comportamiento indefinido y no debe usarse bajo ninguna circunstancia. No espere que el comportamiento de esto sea consistente en todas las plataformas y no lo use en programas de producción.

over 4 years ago · Santiago Trujillo Report

0

Hmm, sospecho que esto es algo que no habría funcionado en los primeros días de C. Sin embargo, es inteligente.

Dando los pasos uno a la vez:

  • &a obtiene un puntero a un objeto de tipo int[5]
  • +1 obtiene el siguiente objeto de este tipo suponiendo que hay una matriz de esos
  • * convierte efectivamente esa dirección en puntero de tipo a int
  • -a resta los dos punteros int y devuelve el recuento de instancias int entre ellos.

No estoy seguro de que sea completamente legal (con esto me refiero a la legalidad de un abogado de lenguaje, no funcionará en la práctica), dado el tipo de operaciones que se están llevando a cabo. Por ejemplo, solo está "permitido" restar dos punteros cuando apuntan a elementos en la misma matriz. *(&a+1) se sintetizó accediendo a otra matriz, aunque sea una matriz principal, por lo que en realidad no es un puntero a la misma a que . Además, si bien puede sintetizar un puntero más allá del último elemento de una matriz, y puede tratar cualquier objeto como una matriz de 1 elemento, la operación de desreferenciación ( * ) no está "permitida" en este puntero sintetizado, aunque no tiene comportamiento en este caso!

Sospecho que en los primeros días de C (sintaxis K&R, ¿alguien?), una matriz se convertía en un puntero mucho más rápido, por lo que *(&a+1) solo podría devolver la dirección del siguiente puntero de tipo int**. Las definiciones más rigurosas del C++ moderno definitivamente permiten que exista el puntero al tipo de matriz y conozcan el tamaño de la matriz, y probablemente los estándares de C hayan seguido su ejemplo. Todo el código de función de C solo toma punteros como argumentos, por lo que la diferencia técnica visible es mínima. Pero solo estoy adivinando aquí.

Este tipo de pregunta de legalidad detallada generalmente se aplica a un intérprete de C, o una herramienta de tipo pelusa, en lugar del código compilado. Un intérprete podría implementar una matriz 2D como una matriz de punteros a matrices, porque hay una función de tiempo de ejecución menos que implementar, en cuyo caso la desreferenciación del +1 sería fatal, e incluso si funcionara daría la respuesta incorrecta.

Otra posible debilidad puede ser que el compilador de C pueda alinear la matriz externa. Imagínese si se tratara de una matriz de 5 caracteres ( char arr[5] ), cuando el programa realiza &a+1 invoca el comportamiento de "matriz de matriz". El compilador podría decidir que una matriz de matriz de 5 caracteres ( char arr[][5] ) en realidad se genera como una matriz de matriz de 8 caracteres ( char arr[][8] ), de modo que la matriz externa se alinee bien. El código que estamos discutiendo ahora reportaría el tamaño de la matriz como 8, no como 5. No estoy diciendo que un compilador en particular definitivamente haría esto, pero podría hacerlo.

over 4 years ago · Santiago Trujillo Report

0

Cuando agrega 1 a un puntero, el resultado es la ubicación del siguiente objeto en una secuencia de objetos del tipo apuntado (es decir, una matriz). Si p apunta a un objeto int , entonces p + 1 apuntará al siguiente int en una secuencia. Si p apunta a una matriz de 5 elementos de int (en este caso, la expresión &a ), entonces p + 1 apuntará a la siguiente matriz de 5 elementos de int en una secuencia.

Restar dos punteros (siempre que ambos apunten al mismo objeto de matriz, o uno esté apuntando uno más allá del último elemento de la matriz) produce la cantidad de objetos (elementos de matriz) entre esos dos punteros.

La expresión &a produce la dirección de a y tiene el tipo int (*)[5] (puntero a una matriz de 5 elementos de int ). La expresión &a + 1 produce la dirección de la siguiente matriz de 5 elementos de int que sigue a , y también tiene el tipo int (*)[5] . La expresión *(&a + 1) desreferencia el resultado de &a + 1 , de modo que produce la dirección del primer int que sigue al último elemento de a , y tiene el tipo int [5] , que en este contexto "decae" a un expresión de tipo int * .

De manera similar, la expresión a "decae" en un puntero al primer elemento de la matriz y tiene tipo int * .

Una imagen puede ayudar:

 int [5] int (*)[5] int int * +---+ +---+ | | <- &a | | <- a | - | +---+ | | | | <- a + 1 | - | +---+ | | | | | - | +---+ | | | | | - | +---+ | | | | +---+ +---+ | | <- &a + 1 | | <- *(&a + 1) | - | +---+ | | | | | - | +---+ | | | | | - | +---+ | | | | | - | +---+ | | | | +---+ +---+

Estas son dos vistas del mismo almacenamiento: a la izquierda, lo vemos como una secuencia de matrices de 5 elementos de int , mientras que a la derecha, lo vemos como una secuencia de int . También muestro las diversas expresiones y sus tipos.

Tenga en cuenta que la expresión *(&a + 1) da como resultado un comportamiento indefinido :

...
Si el resultado apunta a uno más allá del último elemento del objeto de matriz, no se utilizará como operando de un operador * unario que se evalúa.

Borrador en línea C 2011 , 6.5.6/9

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!