matriz llenar inversa factorizacion descomposicion 3x3 c++ c arrays pointers

c++ - inversa - llenar matriz c#



¿Qué es la matriz en descomposición? (8)

¿Qué es la descomposición de una matriz? ¿Hay alguna relación con los punteros de matriz?


tl; dr: cuando usa una matriz que ha definido, en realidad usará un puntero a su primer elemento.

Así:

  • Cuando escribes arr[idx] realmente estás diciendo *(arr + idx) .
  • las funciones nunca toman realmente las matrices como parámetros, solo punteros, incluso cuando se especifica un parámetro de matriz.

Una especie de excepciones a esta regla:

  • Puede pasar matrices de longitud fija a funciones dentro de una struct .
  • sizeof() proporciona el tamaño que ocupa la matriz, no el tamaño de un puntero.

"Decadencia" se refiere a la conversión implícita de una expresión de un tipo de matriz a un tipo de puntero. En la mayoría de los contextos, cuando el compilador ve una expresión de matriz, convierte el tipo de expresión de "matriz de elemento N de T" a "puntero a T" y establece el valor de la expresión en la dirección del primer elemento de la matriz . Las excepciones a esta regla son cuando una matriz es un operando de sizeof o de operadores, o la matriz es un literal de cadena que se usa como inicializador en una declaración.

Asume el siguiente código:

char a[80]; strcpy(a, "This is a test");

La expresión a es de tipo "matriz de 80 elementos de char" y la expresión "Esto es una prueba" es de tipo "matriz de 16 elementos de char" (en C; en C ++, los literales de cadena son matrices de const char). Sin embargo, en la llamada a strcpy() , ninguna expresión es un operando de sizeof o & , por lo que sus tipos se convierten implícitamente a "puntero a char", y sus valores se establecen en la dirección del primer elemento en cada uno. Lo que recibe strcpy() no son matrices, sino punteros, como se ve en su prototipo:

char *strcpy(char *dest, const char *src);

Esto no es lo mismo que un puntero de matriz. Por ejemplo:

char a[80]; char *ptr_to_first_element = a; char (*ptr_to_array)[80] = &a;

Tanto ptr_to_first_element como ptr_to_array tienen el mismo valor ; la dirección base de a. Sin embargo, son tipos diferentes y se tratan de manera diferente, como se muestra a continuación:

a[i] == ptr_to_first_element[i] == (*ptr_to_array)[i] != *ptr_to_array[i] != ptr_to_array[i]

Recuerde que la expresión a[i] se interpreta como *(a+i) (que solo funciona si el tipo de matriz se convierte en un tipo de puntero), por lo que tanto a[i] como ptr_to_first_element[i] funcionan de la misma manera. La expresión (*ptr_to_array)[i] se interpreta como *(*a+i) . Las expresiones *ptr_to_array[i] y ptr_to_array[i] pueden llevar a advertencias o errores del compilador dependiendo del contexto; definitivamente harán lo incorrecto si esperas que se evalúen a[i] .

sizeof a == sizeof *ptr_to_array == 80

Nuevamente, cuando una matriz es un operando de sizeof , no se convierte a un tipo de puntero.

sizeof *ptr_to_first_element == sizeof (char) == 1 sizeof ptr_to_first_element == sizeof (char *) == whatever the pointer size is on your platform

ptr_to_first_element es un puntero simple a char.


Es cuando la matriz se descompone y se apunta a ;-)

En realidad, es solo que si quieres pasar una matriz en algún lugar, pero el puntero se pasa en su lugar (porque quién demonios pasaría la matriz completa por ti), la gente dice que la matriz pobre decae en el puntero.


Esto es lo que dice la norma (C99 6.3.2.1/3 - Otros operandos - Lvalores, matrices y designadores de funciones):

Excepto cuando es el operando del operador sizeof o el operador unario &, o si se utiliza un literal de cadena para inicializar una matriz, una expresión que tiene el tipo "matriz de tipo" se convierte en una expresión con el puntero de tipo a " escriba "" que apunta al elemento inicial del objeto de matriz y no es un valor l.

Esto significa que casi siempre que el nombre de la matriz se usa en una expresión, se convierte automáticamente en un puntero al primer elemento de la matriz.

Tenga en cuenta que los nombres de funciones actúan de manera similar, pero los punteros de función se usan mucho menos y de una manera mucho más especializada que no causa tanta confusión como la conversión automática de nombres de matriz a punteros.

El estándar de C ++ (4.2 conversión de matriz a puntero) afloja el requisito de conversión a (énfasis mío):

Un lvalue o rvalue de tipo "matriz de NT" o "matriz de límite desconocido de T" se puede convertir a un valor de tipo "puntero a T".

Por lo tanto, la conversión no tiene que suceder como ocurre casi siempre en C (esto permite que las funciones de sobrecarga o las plantillas coincidan con el tipo de matriz).

Esta es la razón por la que en C debería evitar el uso de parámetros de matriz en los prototipos / definiciones de funciones (en mi opinión, no estoy seguro de que exista un acuerdo general). Causan confusión y son una ficción de todos modos: use los parámetros del puntero y la confusión podría no desaparecer por completo, pero al menos la declaración del parámetro no miente.


La descomposición de la matriz significa que, cuando una matriz se pasa como un parámetro a una función, se trata de forma idéntica a ("decae") un puntero.

void do_something(int *array) { // We don''t know how big array is here, because it''s decayed to a pointer. printf("%i/n", sizeof(array)); // always prints 4 on a 32-bit machine } int main (int argc, char **argv) { int a[10]; int b[20]; int *c; printf("%zu/n", sizeof(a)); //prints 40 on a 32-bit machine printf("%zu/n", sizeof(b)); //prints 80 on a 32-bit machine printf("%zu/n", sizeof(c)); //prints 4 on a 32-bit machine do_something(a); do_something(b); do_something(c); }

Hay dos complicaciones o excepciones a las anteriores.

Primero, cuando se trata de matrices multidimensionales en C y C ++, solo se pierde la primera dimensión. Esto se debe a que los arreglos se distribuyen de forma contigua en la memoria, por lo que el compilador debe saber todo menos la primera dimensión para poder calcular las compensaciones en ese bloque de memoria.

void do_something(int array[][10]) { // We don''t know how big the first dimension is. } int main(int argc, char *argv[]) { int a[5][10]; int b[20][10]; do_something(a); do_something(b); return 0; }

Segundo, en C ++, puedes usar plantillas para deducir el tamaño de los arreglos. Microsoft usa esto para las versiones C ++ de las funciones Secure CRT como strcpy_s , y puede usar un truco similar para obtener de manera confiable la cantidad de elementos en una matriz .


Las matrices son básicamente lo mismo que los punteros en C / C ++, pero no del todo. Una vez que conviertas una matriz:

const int a[] = { 2, 3, 5, 7, 11 };

en un puntero (que funciona sin lanzar, y por lo tanto puede suceder inesperadamente en algunos casos):

const int* p = a;

se pierde la capacidad del operador sizeof para contar elementos en la matriz:

assert( sizeof(p) != sizeof(a) ); // sizes are not equal

Esta habilidad perdida se conoce como "decaimiento".

Para más detalles, echa un vistazo a este artículo sobre la desintegración de la matriz .


Se dice que las matrices "decaen" en punteros. Una matriz de C ++ declarada como int numbers [5] no se puede volver a apuntar, es decir, no puede decir numbers = 0x5a5aff23 . Más importante aún, el término decadencia significa pérdida de tipo y dimensión; numbers descomponen en int* al perder la información de dimensión (cuenta 5) y el tipo ya no es int [5] . Busque aquí los casos donde la decadencia no ocurre .

Si está pasando una matriz por valor, lo que realmente está haciendo es copiar un puntero: un puntero al primer elemento de la matriz se copia al parámetro (cuyo tipo también debe ser un puntero al tipo de elemento de la matriz). Esto funciona debido a la naturaleza decadente de la matriz; una vez decaído, sizeof ya no da el tamaño de la matriz completa, porque esencialmente se convierte en un puntero. Es por esto que se prefiere (entre otras razones) pasar por referencia o puntero.

Tres formas de pasar en una matriz 1 :

void by_value(const T* array) // const T array[] means the same void by_pointer(const T (*array)[U]) void by_reference(const T (&array)[U])

Los dos últimos proporcionarán el sizeof adecuado de la información, mientras que el primero no lo hará ya que el argumento de la matriz ha decaído para ser asignado al parámetro.

1 La constante U debe ser conocida en tiempo de compilación.


Las matrices, en C, no tienen valor.

Siempre que se espera el valor de un objeto, pero el objeto es una matriz, en su lugar se usa la dirección de su primer elemento, con pointer to (type of array elements) tipo pointer to (type of array elements) .

En una función, todos los parámetros se pasan por valor (las matrices no son una excepción). Cuando se pasa una matriz en una función, se "desintegra en un puntero" (sic); cuando se compara una matriz con otra cosa, nuevamente se "decae en un puntero" (sic); ...

void foo(int arr[]);

La función foo espera el valor de una matriz. Pero, en C, las matrices no tienen valor! Entonces foo obtiene la dirección del primer elemento de la matriz.

int arr[5]; int *ip = &(arr[1]); if (arr == ip) { /* something; */ }

En la comparación anterior, arr no tiene valor, por lo que se convierte en un puntero. Se convierte en un puntero a int. Ese puntero se puede comparar con la variable ip .

En la sintaxis de indexación de matriz que está acostumbrado a ver, de nuevo, el arr está ''descompuesto en un puntero''

arr[42]; /* same as *(arr + 42); */ /* same as *(&(arr[0]) + 42); */

Las únicas veces que una matriz no se desintegra en un puntero es cuando es el operando del operador sizeof, o el operador & (la dirección de ''operador''), o como un literal de cadena utilizado para inicializar una matriz de caracteres.