recibe - Pasando una matriz por referencia en C?
pasar matriz por referencia c++ (7)
¿Cómo puedo pasar una matriz de estructuras por referencia en C?
Como ejemplo:
struct Coordinate {
int X;
int Y;
};
SomeMethod(Coordinate *Coordinates[]){
//Do Something with the array
}
int main(){
Coordinate Coordinates[10];
SomeMethod(&Coordinates);
}
El lenguaje C no admite el paso por referencia de ningún tipo. El equivalente más cercano es pasar un puntero al tipo.
Aquí hay un ejemplo inventado en ambos idiomas
API de estilo C ++
void UpdateValue(int& i) {
i = 42;
}
El equivalente C más cercano
void UpdateValue(int *i) {
*i = 42;
}
En C simple, puedes usar una combinación de puntero / tamaño en tu API.
void doSomething(MyStruct* mystruct, size_t numElements)
{
for (size_t i = 0; i < numElements; ++i)
{
MyStruct current = mystruct[i];
handleElement(current);
}
}
El uso de punteros es lo más cercano a llamadas por referencia disponibles en C.
En C, las matrices se pasan como un puntero al primer elemento. Son el único elemento que realmente no pasa por el valor (el puntero se pasa por valor, pero la matriz no se copia). Eso permite que la función llamada modifique los contenidos.
void reset( int *array, int size) {
memset(array,0,size * sizeof(*array));
}
int main()
{
int array[10];
reset( array, 10 ); // sets all elements to 0
}
Ahora, si lo que quiere es cambiar la matriz en sí (número de elementos ...) no puede hacerlo con la pila o las matrices globales, solo con la memoria asignada dinámicamente en el montón. En ese caso, si quiere cambiar el puntero, debe pasarle un puntero:
void resize( int **p, int size ) {
free( *p );
*p = malloc( size * sizeof(int) );
}
int main() {
int *p = malloc( 10 * sizeof(int) );
resize( &p, 20 );
}
En la edición de pregunta, usted pregunta específicamente acerca de cómo pasar una serie de estructuras. Tienes dos soluciones allí: declara un typedef, o haz explícito que estás pasando una estructura:
struct Coordinate {
int x;
int y;
};
void f( struct Coordinate coordinates[], int size );
typedef struct Coordinate Coordinate; // generate a type alias ''Coordinate'' that is equivalent to struct Coordinate
void g( Coordinate coordinates[], int size ); // uses typedef''ed Coordinate
Puede tipear el tipo como lo declara (y es un idioma común en C):
typedef struct Coordinate {
int x;
int y;
} Coordinate;
Hola chicos aquí hay un programa de prueba simple que muestra cómo asignar y pasar una matriz usando new o malloc. Solo córtalo, péguelo y ejecútelo. ¡Que te diviertas!
struct Coordinate
{
int x,y;
};
void resize( int **p, int size )
{
free( *p );
*p = (int*) malloc( size * sizeof(int) );
}
void resizeCoord( struct Coordinate **p, int size )
{
free( *p );
*p = (Coordinate*) malloc( size * sizeof(Coordinate) );
}
void resizeCoordWithNew( struct Coordinate **p, int size )
{
delete [] *p;
*p = (struct Coordinate*) new struct Coordinate[size];
}
void SomeMethod(Coordinate Coordinates[])
{
Coordinates[0].x++;
Coordinates[0].y = 6;
}
void SomeOtherMethod(Coordinate Coordinates[], int size)
{
for (int i=0; i<size; i++)
{
Coordinates[i].x = i;
Coordinates[i].y = i*2;
}
}
int main()
{
//static array
Coordinate tenCoordinates[10];
tenCoordinates[0].x=0;
SomeMethod(tenCoordinates);
SomeMethod(&(tenCoordinates[0]));
if(tenCoordinates[0].x - 2 == 0)
{
printf("test1 coord change successful/n");
}
else
{
printf("test1 coord change unsuccessful/n");
}
//dynamic int
int *p = (int*) malloc( 10 * sizeof(int) );
resize( &p, 20 );
//dynamic struct with malloc
int myresize = 20;
int initSize = 10;
struct Coordinate *pcoord = (struct Coordinate*) malloc (initSize * sizeof(struct Coordinate));
resizeCoord(&pcoord, myresize);
SomeOtherMethod(pcoord, myresize);
bool pass = true;
for (int i=0; i<myresize; i++)
{
if (! ((pcoord[i].x == i) && (pcoord[i].y == i*2)))
{
printf("Error dynamic Coord struct [%d] failed with (%d,%d)/n",i,pcoord[i].x,pcoord[i].y);
pass = false;
}
}
if (pass)
{
printf("test2 coords for dynamic struct allocated with malloc worked correctly/n");
}
//dynamic struct with new
myresize = 20;
initSize = 10;
struct Coordinate *pcoord2 = (struct Coordinate*) new struct Coordinate[initSize];
resizeCoordWithNew(&pcoord2, myresize);
SomeOtherMethod(pcoord2, myresize);
pass = true;
for (int i=0; i<myresize; i++)
{
if (! ((pcoord2[i].x == i) && (pcoord2[i].y == i*2)))
{
printf("Error dynamic Coord struct [%d] failed with (%d,%d)/n",i,pcoord2[i].x,pcoord2[i].y);
pass = false;
}
}
if (pass)
{
printf("test3 coords for dynamic struct with new worked correctly/n");
}
return 0;
}
Las matrices se pasan efectivamente por referencia por defecto. En realidad, se pasa el valor del puntero al primer elemento. Por lo tanto, la función o método que recibe esto puede modificar los valores en la matriz.
void SomeMethod(Coordinate Coordinates[]){Coordinates[0].x++;};
int main(){
Coordinate tenCoordinates[10];
tenCoordinates[0].x=0;
SomeMethod(tenCoordinates[]);
SomeMethod(&tenCoordinates[0]);
if(0==tenCoordinates[0].x - 2;){
exit(0);
}
exit(-1);
}
Las dos llamadas son equivalentes, y el valor de salida debe ser 0;
Para ampliar un poco sobre algunas de las respuestas aquí ...
En C, cuando un identificador de matriz aparece en un contexto que no sea como un operando para & y sizeof, el tipo de identificador se convierte implícitamente de "N-elemento matriz de T" a "puntero a T", y su valor es configurado implícitamente a la dirección del primer elemento en la matriz (que es lo mismo que la dirección de la matriz en sí). Por eso, cuando pasa el identificador de matriz como argumento a una función, la función recibe un puntero al tipo de base, en lugar de a una matriz. Como no puede determinar qué tan grande es una matriz simplemente mirando el puntero al primer elemento, debe pasar el tamaño como un parámetro separado.
struct Coordinate { int x; int y; };
void SomeMethod(struct Coordinate *coordinates, size_t numCoordinates)
{
...
coordinates[i].x = ...;
coordinates[i].y = ...;
...
}
int main (void)
{
struct Coordinate coordinates[10];
...
SomeMethod (coordinates, sizeof coordinates / sizeof *coordinates);
...
}
Hay un par de formas alternativas de pasar matrices a las funciones.
Existe un puntero a una matriz de T, en oposición a un puntero a T. Usted declararía un puntero como
T (*p)[N];
En este caso, p es un puntero a un conjunto de N elementos de T (en oposición a T * p [N], donde p es un conjunto de elementos N de puntero a T). Por lo tanto, podría pasar un puntero a la matriz en lugar de un puntero al primer elemento:
struct Coordinate { int x; int y };
void SomeMethod(struct Coordinate (*coordinates)[10])
{
...
(*coordinates)[i].x = ...;
(*coordinates)[i].y = ...;
...
}
int main(void)
{
struct Coordinate coordinates[10];
...
SomeMethod(&coordinates);
...
}
La desventaja de este método es que el tamaño de la matriz es fijo, ya que un puntero a una matriz de 10 elementos de T es un tipo diferente de un puntero a una matriz de 20 elementos de T.
Un tercer método es envolver la matriz en una estructura:
struct Coordinate { int x; int y; };
struct CoordinateWrapper { struct Coordinate coordinates[10]; };
void SomeMethod(struct CoordinateWrapper wrapper)
{
...
wrapper.coordinates[i].x = ...;
wrapper.coordinates[i].y = ...;
...
}
int main(void)
{
struct CoordinateWrapper wrapper;
...
SomeMethod(wrapper);
...
}
La ventaja de este método es que no estás jugando con punteros. La desventaja es que el tamaño de la matriz es fijo (de nuevo, una matriz de 10 elementos de T es un tipo diferente de una matriz de 20 elementos de T).
También tenga en cuenta que si está creando una matriz dentro de un método, no puede devolverla. Si devuelve un puntero, se habría eliminado de la pila cuando la función vuelva. debe asignar memoria en el montón y devolver un puntero a eso. p.ej.
//this is bad
char* getname()
{
char name[100];
return name;
}
//this is better
char* getname()
{
char *name = malloc(100);
return name;
//remember to free(name)
}