una resueltos que pass pasar funcion ejercicios como cadenas bidimensional arreglo array c++ c arrays multidimensional-array

resueltos - que es un array en c++



Cómo pasar una matriz multidimensional a una función en C y C++ (12)

Además de utilizar matrices de longitud variable en C99, no se puede escribir de manera portátil una función para aceptar una matriz multidimensional si no se conocen los tamaños de las matrices en tiempo de compilación, consulte la Pregunta 6.19 de C-FAQ . La mejor forma de manejar esto es simular matrices multidimensionales utilizando memoria asignada dinámicamente. La pregunta 6.16 hace un muy buen trabajo explicando los detalles de hacer esto.

#include<stdio.h> void print(int *arr[], int s1, int s2) { int i, j; for(i = 0; i<s1; i++) for(j = 0; j<s2; j++) printf("%d, ", *((arr+i)+j)); } int main() { int a[4][4] = {{0}}; print(a,4,4); }

Esto funciona en C, pero no en C ++.

error:

cannot convert `int (*)[4]'' to `int**'' for argument `1'' to `void print(int**, int, int)''

¿Por qué no funciona en C ++? ¿Qué cambio se necesita hacer?


Aquí hay una versión que funciona, pero teóricamente no válida (ver abajo) C90 y C ++ 98:

#include <stdio.h> static void print(int *arr, size_t s1, size_t s2) { size_t i, j; printf("/n"); for(i = 0; i < s1; i++) { for(j = 0; j < s2; j++) { printf("%d, ", arr[i * s2 + j]); } } printf("/n"); } int main(void) { int a[4][4] = {{0}}; print(a[0], 4, 4); return 0; }

Una versión de C ++ que utiliza plantillas (adaptadas de la respuesta de Notinlist ) podría verse así:

#include <iostream> #include <cstring> using namespace std; template <size_t N, size_t M> struct IntMatrix { int data[N][M]; IntMatrix() { memset(data, 0, sizeof data); } }; template <size_t N, size_t M> ostream& operator<<(ostream& out, const IntMatrix<N,M>& m) { out << "/n"; for(size_t i = 0; i < N; i++) { for(size_t j = 0; j < M; j++) { out << m.data[i][j] << ", "; } } out << "/n"; return out; } int main() { IntMatrix<4,4> a; cout << a; return 0; }

Alternativamente, podría usar contenedores STL anidados, es decir, vector< vector<int> > , en lugar de una matriz simple.

Con C99, podrías hacer

static void print(size_t s1, size_t s2, int arr[s1][s2]) { printf("/n"); for(size_t i = 0; i < s1; i++) { for(size_t j = 0; j < s2; j++) { printf("%d, ", arr[i][j]); } } printf("/n"); }

y llámalo como

print(4, 4, a);

Como Robert señaló en los comentarios, el primer fragmento involucra un comportamiento indefinido. Sin embargo, suponiendo que la aritmética del puntero siempre resultará en un puntero incluso cuando se trate de un comportamiento indefinido (y no explote su computadora), solo hay un único resultado posible debido a otras restricciones dentro del estándar, es decir, este es un caso donde el estándar deja algo innecesariamente indefinido.

Por lo que puedo decir, sustituyendo

print(a[0], 4, 4);

con

union m2f { int multi[4][4]; int flat[16]; } *foo = (union m2f *)&a; print(foo->flat, 4, 4);

lo hará legal C.


El problema es ese

int a[4][4];

en realidad se almacenará en una memoria física continua. Por lo tanto, para acceder a una parte arbitraria de su matriz 4x4, la función "imprimir" necesita conocer las dimensiones de la matriz. Por ejemplo, la siguiente pequeña porción de código, accederá a la misma parte de la memoria de dos maneras diferentes.

#include <iostream> void print(int a[][4]){ for (int i = 0; i <4; i++){ for (int j = 0; j < 4; j++){ //accessing as 4x4 array std::cout << a[i][j] <<std::endl; //accessing corresponding to the physical layout in memory std::cout << *(*(a)+ i*4 + j) << std::endl; } } } int main(){ int a[4][4]; //populating the array with the corresponding indices from 0 to 15 int m = 0; for (int i = 0; i<4; i++){ for (int j= 0; j < 4; j++){ a[i][j] = m; m++; } } print(a); }

Entonces, el diseño de la memoria no cambia, pero la forma de acceder sí lo hace. Se puede visualizar como un tablero de ajedrez.

0 1 2 3 ---------- 0| 1 2 3 4 1| 5 6 7 8 2| 9 10 11 12 3|13 14 15 16

Pero la memoria física real se ve así.

0*4+0 0*4+1 0*4+2 0*4+3 1*4+0 1*4+1 1*4+2 1*4+3 2*4+1 etc. ----------------------------------------------------- 1 2 3 4 5 6 7 8 9 etc.

En c ++ los datos de una matriz se almacenan fila por fila y la longitud de una fila (en este caso 4) siempre es necesaria para llegar a la compensación de memoria adecuada para la siguiente fila. El primer subíndice, por lo tanto, solo indica la cantidad de almacenamiento que se necesita cuando se declara el conjunto, pero ya no es necesario calcular el desplazamiento después.


Este código no funcionará en C o C ++. Una matriz de tipo int[4][4] no es convertible a un puntero de tipo int ** (que es lo que int *arr[] representa en la declaración de parámetro). Si logró compilarlo en C, es simplemente porque probablemente ignoró una advertencia del compilador C básicamente del mismo formato que el mensaje de error que obtuvo del compilador C ++. (A veces los compiladores C emiten advertencias para lo que es esencialmente un error ).

Entonces, nuevamente, no hagas afirmaciones que no sean verdaderas. Este código no funciona en C. Para convertir una matriz 2D incorporada en un puntero int ** puedes usar una técnica como esta

Conversión de matrices multidimensionales a punteros en c ++

(Consulte la respuesta aceptada. El problema es exactamente el mismo).

EDIT: el código parece funcionar en C porque otro error en el código de impresión está enmascarando los efectos del error en el paso de la matriz. Para acceder correctamente a un elemento de una pseudo-matriz int ** , debe usar la expresión *(*(arr + i) + j) , o mejor una arr[i][j] simple arr[i][j] (que es lo mismo ) Te perdiste el extra * que lo hizo imprimir algo que no tiene absolutamente nada que ver con el contenido de tu matriz. Nuevamente, inicialice su matriz en main a otra cosa para ver que los resultados que está imprimiendo en C no tienen absolutamente nada que ver con el contenido previsto de la matriz.

Si cambia la declaración de printf como se muestra arriba, es muy probable que su código falle debido al error de paso de matriz que describí inicialmente.

Una vez más: no se puede pasar una matriz int[4][4] como una pseudo-matriz int ** . Esto es lo que el C ++ le dice en el mensaje de error. Y, estoy seguro, esto es lo que tu compilador de C te dijo, pero probablemente lo ignoraste, ya que era "solo una advertencia".


Las matrices multidimensionales son bloques continuos de memoria. Entonces puedes hacerlo de esta manera:

#include <stdio.h> void pa(const int *a, int y, int x) { int i, j; for (i=0;i<y;i++) { for (j=0;j<x;j++) printf("%i", *(a+j+i*x)); printf("/n"); } } int main() { int a[4][3] = { {1,2,3}, {4,5,6}, {4,5,6}, {7,8,9} }; pa(a[0], 4, 3); return 0; }

También funciona en C ++;


Lo primero que debe hacer es obtener los tipos correctos. Si las reglas de C ++ son las mismas que las de C con respecto a los tipos de arreglo (estoy bastante seguro de que lo son), entonces, dada la declaración

int a[4][4];

la expresión a tiene tipo int [4][4] , que se convierte implícitamente ("decae") a un tipo de puntero de int (*)[4] (puntero a matriz de 4 elementos de int) cuando se pasa a print , por lo necesitas cambiar la print a

void print(int (*arr)[4], int s1, int s2) { int i, j; for(i = 0; i<s1; i++) for(j = 0; j<s2; j++) printf("%d, ", arr[i][j]); }

La expresión arr[i] elimina las referencias de forma implícita, por lo que no necesita meterse con una desreferencia explícita.

El inconveniente es que la print solo puede manejar matrices Nx4 de int; si desea manejar otros tamaños de matriz, deberá adoptar un enfoque diferente.

Una cosa que puede hacer es en lugar de pasar la matriz, pasar la dirección del primer elemento y hacer que la print calcule manualmente los desplazamientos, de la siguiente manera:

int main() { int a[4][4] = {{0}}; print(&a[0][0],4,4); // note how a is being passed } void print(int *arr, int s1, int s2) // note that arr is a simple int * { int i, j; for (i = 0; i < s1; i++) for (j = 0; j < s2; j++) printf("%d, ", arr[i * s2 + j]); }


Puede usar int** lugar. Es mucho más flexible:

#include <stdio.h> #include <stdlib.h> void print(int **a, int numRows, int numCols ) { int row, col ; for( int row = 0; row < numRows; row++ ) { for( int col = 0; col < numCols ; col++ ) { printf("%5d, ", a[row][col]); } puts(""); } } int main() { int numRows = 16 ; int numCols = 5 ; int **a ; // a will be a 2d array with numRows rows and numCols cols // allocate an "array of arrays" of int a = (int**)malloc( numRows* sizeof(int*) ) ; // each entry in the array of arrays of int // isn''t allocated yet, so allocate it for( int row = 0 ; row < numRows ; row++ ) { // Allocate an array of int''s, at each // entry in the "array of arrays" a[row] = (int*)malloc( numCols*sizeof(int) ) ; } int count = 1 ; for( int row = 0 ; row < numRows ; row++ ) { for( int col = 0 ; col < numCols ; col++ ) { a[row][col] = count++ ; } } print( a, numRows, numCols ); }

Otra cosa que puede interesarle es una estructura como D3DMATRIX :

typedef struct _D3DMATRIX { union { struct { float _11, _12, _13, _14; float _21, _22, _23, _24; float _31, _32, _33, _34; float _41, _42, _43, _44; }; float m[4][4]; }; } D3DMATRIX; D3DMATRIX myMatrix ;

Lo bueno de este pequeño tidbit es que puedes usar myMatrix.m[0][0] (para acceder al primer elemento), o puedes usar myMatrix._11 para acceder también al mismo elemento. La union es el secreto.


Respuesta corta, puede cambiar el programa de la siguiente manera

void print(int arr[], int s1, int s2) { ... printf("%d,", *(a+i + s2*j)); ... print((int*)a,4,4);

Esto necesitaría una mejor respuesta para explicar las diferencias entre la aritmética y las matrices de puntero y puntero en C y C ++. No me lanzaré a eso ahora. ¿Tal vez alguien más?

Obviamente, no estoy sorprendido por el mismo punto que otros carteles en su código. Lo que más me molesta en el encabezado de la función de impresión es que utiliza una indirección doble para una matriz en la que no tiene la intención de cambiar el puntero inicial (de hecho, no se puede hacer ya que es una constante). @ | V | lad answer corrige esto estableciendo una o dos dimensiones en una constante fija, pero luego pasar s1 y s2 se vuelve inútil.

Todo depende de lo que realmente quieras hacer. ¿Imprimir es una función de impresión de matriz de propósito general o una especializada para algunos tipos de matriz?


Solo quiero mostrar la versión en C ++ de la respuesta de bobobobo.

int numRows = 16 ; int numCols = 5 ; int **a ; a = new int*[ numRows* sizeof(int*) ]; for( int row = 0 ; row < numRows ; row++ ) { a[row] = new int[ numCols*sizeof(int) ]; }

El resto del código es lo mismo con bobobobo''s.


#include<cstdio> template <size_t N, size_t M> struct DataHolder { int data[N][M]; DataHolder() { for(int i=0; i<N; ++i) for(int j=0; j<M; ++j) data[i][j] = 0; } }; template <size_t N, size_t M> void print(const DataHolder<N,M>& dataHolder) { printf("/n"); for(int i = 0; i<N; i++) { for(int j = 0; j<M; j++) { printf("%d, ", dataHolder.data[i][j]); } } printf("/n"); } int main() { DataHolder<4,4> a; print(a); }


#include<stdio.h> void print(int (*arr)[4], int s1, int s2) { int i, j; for(i = 0; i<s1; i++) for(j = 0; j<s2; j++) printf("%d, ", arr[i][j]); } int main() { int a[4][4] = {{6}}; print(a,4,4); }

esto compilará editar: alguien ya publicó esta solución mi mala


#include<stdio.h> void print(int arr[][4], int s1, int s2) { int i, j; printf("/n"); for(i = 0; i<s1; i++) { for(j = 0; j<s2; j++) { printf("%d, ", *((arr+i)+j)); } } printf("/n"); } int main() { int a[4][4] = {{0}}; print(a,4,4); }

Esto funcionará, donde por trabajo me refiero a compilar. @AndreyT explicó por qué tu versión ya no funciona.

Así es como debes pasar una matriz 2d.

Para mayor claridad, también puede especificar ambos tamaños en la declaración de la función:

#include<stdio.h> void print(int arr[4][4], int s1, int s2) { int i, j; printf("/n"); for(i = 0; i<s1; i++) { for(j = 0; j<s2; j++) { printf("%d, ", *((arr+i)+j)); } } printf("/n"); } int main() { int a[4][4] = {{0}}; print(a,4,4); }

Ambos funcionarán.

También debe cambiar *((arr+i)+j) a a[i][j] (preferiblemente) o *(*(arr+i)+j) si su intención es acceder al elemento j th de la fila i .