Hace mucho, mucho tiempo, jugué mucho con C pero me olvidé de todo. Ahora estoy tratando de resolver tareas fáciles y fallé.

Me gustaría escribir una función que tome 2dim array o char* e imprimirla. pero mi código tiene errores y no entiendo por qué. Según tengo entendido, products es un puntero a la matriz 2dim, así que al aumentarlo a i * sizeof(char**) obtengo un puntero a una submatriz, y al aumentar ese puntero de una submatriz, obtengo un puntero al bloque char. Pero parece que mi código busca un bloque de memoria diferente.

Acerca de la matriz products: sé que tiene N filas y 2 columnas.

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

void print(char*** products, size_t rows, size_t cols) {
    size_t i;

    for(i = 0; i < rows; i++) {
        printf("Col1: '%s. Col2: %s'\n",
            (products + i * sizeof(char**)),
            (products + i * sizeof(char**) + sizeof(char*))
        );
    }
}

int main(void) {
    const char* a[][3] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};
    print((char***)a, 3, 2);

    return 0;
}
0
Alex G.P. 27 ene. 2016 a las 12:14

4 respuestas

La mejor respuesta

Has mezclado lo que consideras columnas y filas. Arregle eso, luego deshágase de las tonterías de las tres estrellas, haga que la función acepte una cantidad variable de columnas y terminará con esto:

#include <stdio.h>

void print(size_t rows, size_t cols, const char* products[rows][cols]) 
{
  for(size_t r=0; r<rows; r++) 
  {
    for(size_t c=0; c<cols; c++)
    {
      printf("Col%zu: %s. ", c, products[r][c]);
    }
    printf("\n");
  }
}

int main (void) 
{
  const char* a[3][2] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};
  print(3, 2, a);

  return 0;
}

Y eso es todo, no hay necesidad de complicar más las cosas.

1
Lundin 27 ene. 2016 a las 10:11

Tal vez, esto es lo que querías, ¡que es más natural!

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

void print(void *_products, size_t rows, size_t cols) {
    const char* (*products)[cols] = _products;
    size_t i;

    for (i = 0; i < rows; i++) {
        printf("Col1: %s. Col2: %s\n", products[i][0], products[i][1]);
    }
}

int main(void) {
    const char* a[][2] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};
    print(a, 3, 2);

    return 0;
}
0
Simon Woo 24 nov. 2016 a las 20:50

const char* a[][3] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};

En este caso, podría escribir:

const char* a[][2] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};

Pero si realmente desea una matriz de 3 columnas, debe decirle a print que hay 3 columnas, no 2. Pero su impresión solo puede imprimir las dos primeras columnas, por supuesto ...

Entonces, cualquier arreglo de N dimensiones de T puede verse como un arreglo 1D simple de T. Solo tiene que hacer algunos cálculos de direcciones para acceder al elemento deseado. Esto es posible una vez que tenga un puntero al primer elemento de la matriz. Así que a continuación se muestra una versión funcional:

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

typedef const char * T;

void print(T *products, size_t rows, size_t cols) {
    size_t i;

    for (i = 0; i < rows; i++) {
        // Each row has cols items so here is the current row (i-th row):
        T *row = products + i * cols;
        printf("{%s, %s}\n", row[0], row[1]);
    }
}

int main(void) {
    T a[][3] = { { "abc", "1" }, { "def", "2" }, { "ghi", "3" } };

    // Tell print that there are 3 cols, not 2
    print(&a[0][0], 3, 3);

    return 0;
}
1
mikedu95 27 ene. 2016 a las 09:55

La matriz definida en esta declaración

const char* a[][3] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};

Tiene tipo const char *[3][3].

Tenga en cuenta que la matriz tiene tres "columnas"; hay 3 columnas especificadas explícitamente en la declaración de la matriz.

const char* a[][3] =....
               ^^^

Los elementos de la última columna se inicializan con NULL.

Cuando una matriz se utiliza en expresiones como, por ejemplo, un argumento, se convierte explícitamente en un puntero a su primer elemento.

Es decir, si usa la matriz que se muestra arriba como argumento, entonces se convierte a tipo

const char * ( * )[3]

No es del mismo tipo que char ***

Entonces la función debería haberse declarado como

void print( const char * ( *products )[3], size_t rows );

O como

void print( const char * products[][3], size_t rows );

Y la función debería llamarse como

print( a, 3 );

Puede especificar un parámetro más que establezca el número de columnas que desea, por ejemplo, generar

void print( const char * ( *products )[3], size_t rows, size_t cols );

En este caso, la función se puede llamar como

print( a, 3, 2 );

Sin embargo, la matriz en sí tiene 3 columnas. :)

O si el compilador admite matrices de longitud variable como

void print( size_t rows, size_t cols, const char * ( *products )[cols] );

O por legibilidad

void print( size_t rows, size_t cols, const char * products[rows][cols] );

Y se puede llamar como

print( 3, 3, a );

Aquí hay un programa demostrativo que muestra dos formas de declaración de función

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

#define N 3

void print1( const char *product[][N], size_t rows )
{

    for ( size_t i = 0; i < rows; i++ ) 
    {
        for ( const char **p = product[i]; *p; ++p )
        {
            printf( "%s ", *p );
        }
        printf( "\n" );
    }
}    

void print2( size_t rows, size_t cols, const char *product[rows][cols] )
{

    for ( size_t i = 0; i < rows; i++ ) 
    {
        for ( const char **p = product[i]; *p; ++p )
        {
            printf( "%s ", *p );
        }
        printf( "\n" );
    }
}    


int main( void )
{
    const char * a[][N] = 
    {
        { "abc", "1" }, 
        { "def", "2" }, 
        { "ghi", "3" }
    };

    print1( a, N );
    printf( "\n" );

    size_t n = N;

    const char * b[n][n];

    memcpy( b, a, sizeof( a ) );

    print2( n, n, b );
    printf( "\n" );
}    

Su salida es

abc 1 
def 2 
ghi 3 

abc 1 
def 2 
ghi 3 

Tenga en cuenta que las matrices de longitud variable, si son compatibles con el compilador, pueden no inicializarse y luego definirse.

3
Vlad from Moscow 27 ene. 2016 a las 10:00