[C] multidimensional array naar functie

Pagina: 1
Acties:

Onderwerpen


  • Mr_gadget
  • Registratie: Juni 2004
  • Laatst online: 06:29

Mr_gadget

C8H10N4O2 powered

Topicstarter
Het is mij niet hellemaal duidelijk hoe ik het volgende in C kan bereiken:

Ik heb een een 2D array grid[15][15], deze wil ik initialiseren door alle waarden 0 te maken en dit wil ik met een functie doen.

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void fill_array(int *grid[15][15])
{
    int x,y;
    
    for (y=1; y<=15; ++y)
    {
        for (x=1; x<=15; ++x)
        {
            grid[x][y]=0;
              printf(" in grid heeft %d %d de waarde %d\n", x,y, grid[x][y]);   
            
        }
    }
}

Deze werkt alleen nog binnen de functie. Maar hoe ik dit met een 2D pointer zodat het ook buiten de functie veranderd? Iets van *(*grid+i) vernoemd ik maar hoe acces ik [x][y] met een pointer? Voor 1D is het gewoon *(x+i) maar hoe in 2d?

En is het verstandig deze pointers van te voren te allocaten met alloc? Of hoeft dat niet per se aangezien het dynamisch is?

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

je hebt een 2D array van pointers naar integers.
je printf is dan ook niet goed (je stuurt een int * naar een %d)

daarnaast, in C kan je geen arrays als argumenten geven, dat worden impliciet pointers.
maar als de size al bekend is in de functie (15x15 zo te zien), kan je die gewoon gebruiken voor indexing:

C:
1
2
3
4
5
void set_to_0(int *array)
{
  int i;
  for(i = 0; i < 15 * 15; i++) array[i] = 0;
}

-niks-


  • Mr_gadget
  • Registratie: Juni 2004
  • Laatst online: 06:29

Mr_gadget

C8H10N4O2 powered

Topicstarter
Bedankt :) Dus als ik het goed begrijp wordt de array
1 2 3
4 5 6
7 8 9

opgeslagen in het geheugen als 1 2 3 4 5 6 7 8 9?
Dus je berekent met " i < 15 * 15;" gewoon de laatste waarde?

  • Soultaker
  • Registratie: September 2000
  • Nu online
Dat klopt precies.

edit:
Trouwens, je kunt weliswaar geen arrays doorgeven, maar wel pointers naar arrays. Dit kan bijvoorbeeld wel:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void fill_array(int (*a)[15][15])
{
    int r, c;

    for (r = 0; r < 15; ++r)
        for (c = 0; c < 15; ++c)
            (*a)[r][c] = 100*r + c;  /* of whatever */
}

void f()
{
    int a[15][15];
    fill_array(&a);
}


Of zo:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void fill_array(int (*a)[15])
{
    int r, c;

    for (r = 0; r < 15; ++r)
        for (c = 0; c < 15; ++c)
            a[r][c] = 100*r + c;  /* of whatever */
}

void f()
{
    int a[15][15];
    fill_array(a);
}



Denk er bovendien aan dat in C array's geïndexeert worden vanaf 0. Een indices van array met lengte 15 lopen van 0 tot en met 14, niet van 1 tot en met 15 (zoals je in de topic start wel lijkt te denken).

edit2:
Trouwens, dit mag ook gewoon:
C:
1
2
void fill_array(int a[15][15])
  // etc

Maar dit is een puur syntactische variatie op het tweede voorbeeld dat ik gaf (met int (*a)[15] als argument).

[ Voor 126% gewijzigd door Soultaker op 27-09-2009 00:12 ]


  • DataGhost
  • Registratie: Augustus 2003
  • Nu online

DataGhost

iPL dev

Mr_gadget schreef op zaterdag 26 september 2009 @ 22:50:
Bedankt :) Dus als ik het goed begrijp wordt de array
1 2 3
4 5 6
7 8 9

opgeslagen in het geheugen als 1 2 3 4 5 6 7 8 9?
Dus je berekent met " i < 15 * 15;" gewoon de laatste waarde?
Tenzij de array gedefinieerd is als pointer...

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int i;
int *temp;

#ifdef GRID_IS_POINTER
int **grid;
grid = malloc(15 * sizeof(int *));
#else
int *grid[15];
#endif

for(i=0;i<15;i++) {
    grid[i] = malloc(15 * sizeof(int));
    if(i == 0) {
        temp = malloc(15 * sizeof(int));
    }
}

free(temp);
set_to_0(grid); // <-- Gaat mis (code uit MLM's post, for(i = 0; i < 15 * 15; i++) array[i] = 0;)

//.......


Dat maakt voor de functieaanroep geen zak uit maar in uiteindelijke werking wel degelijk een hele hoop!

[ Voor 46% gewijzigd door DataGhost op 26-09-2009 23:25 ]


  • Soultaker
  • Registratie: September 2000
  • Nu online
Je geeft dan ook een argument van een compleet verkeerd type door. Daar zal je compiler dan ook voor waarschuwen. MLM's code is prima, maar uiteraard alleen als je een array van ints als argument meegeeft. Wat was nu precies je punt?

  • DataGhost
  • Registratie: Augustus 2003
  • Nu online

DataGhost

iPL dev

Nee, de declaratie in MLM's code is fout. Een int **x, int *x[15] en int x[15][15] zijn voor de compiler equivalent, laatste keer dat ik keek in ieder geval. Er wordt direct een (m.i. nutteloze) micro-optimalisatie aangedragen waarmee je de boel stevig om zeep kan helpen en er is geen compiler die je daarvoor gaat waarschuwen.

Mijn punt is dat je niet zomaar allerlei aannames kan doen over hoe een bepaald datatype in het geheugen is opgeslagen en dat je een beginner daar al helemaal niet mee moet opschepen. Het is leuk dat je in bepaalde gevallen een 2d-array als 1d-array kan adresseren maar dan moet je de basics al wel in de vingers hebben. Straks zit zijn code vol met die dingen en wil hij opeens dynamische grids gaan gebruiken, enig idee wat een takkezooi dat dan gaat worden?

  • Soultaker
  • Registratie: September 2000
  • Nu online
DataGhost schreef op zaterdag 26 september 2009 @ 23:39:
Nee, de declaratie in MLM's code is fout. Een int **x, int *x\[15] en int x\[15]\[15] zijn voor de compiler equivalent, laatste keer dat ik keek in ieder geval.
Hierin vergis je je. De drie types zijn volstrekt verschillend. Het zijn respectievelijk:
  • een pointer (naar pointer naar int, om precies te zijn)
  • een 1-dimensionale array (bestaande uit 15 elementen, elk een pointer naar integer)
  • een 2-dimensionale array (bestaande uit 15x15 elementen, elk een integer)
Van de drie typen die je noemt kan de tweede stilzwijgend naar de eerste geconverteerd worden, maar dat is alles. Je kunt een functie die een int** verwacht wel een int-array passen, maar dat komt omdat conversie tussen incompatible pointers niet verboden is in C. Daar waarschuwt de compiler wel voor (en een cast is dan ook op z'n plaats, als je dat echt van plan was).
Het is leuk dat je in bepaalde gevallen een 2d-array als 1d-array kan adresseren maar dan moet je de basics al wel in de vingers hebben.
De conversie van een array-van-x naar een pointer-naar-x kan ik álle gevallen. Je converteert ook niet een 2d-array naar een 1d-array, maar een 2d-array naar een pointer. Dat is juist een basic feature van C en dus een van de dingen die je als beginnende programmeur moet leren. ;)

[ Voor 24% gewijzigd door Soultaker op 26-09-2009 23:59 ]


Acties:
  • 0 Henk 'm!

  • DataGhost
  • Registratie: Augustus 2003
  • Nu online

DataGhost

iPL dev

Mmmkay, ik werk zelf niet heel vaak met statische arrays in functiecalls maar de compiler geeft inderdaad een waarschuwing als je een int[15][15] aan set_to_0(int **array) voert of een int** aan set_to_0(int (*array)[15]). Ik had het idee dat dit niet gebeurde, vandaar. Aangezien ik persoonlijk een int** en int[15][15] conceptueel gezien beide een 2D-array vind, leek het me verstandig te melden dat je zeker moet weten dat je structuur een ononderbroken blok is voordat je hem op een dergelijke manier gaat adresseren.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op zaterdag 26 september 2009 @ 23:56:
Je kunt een functie die een int** verwacht wel een int-array passen, maar dat komt omdat conversie tussen incompatible pointers niet verboden is in C.
Incorrect. void* kun je overal naartoe converteren, maar willekeurige pointers niet.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Gek, volgens mij wordt hier vraag 6.18 gesteld, maar rolt er (eerst) een ander antwoord uit.. ;)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Nog even voor de duidelijkheid, C geeft niet om dimensies van arrays als je ze doorgeeft aan een functie, alle items liggen in memory naast elkaar, dus als je een array doorgeeft als pointer, is het altijd een T*, niet een T** voor een 2D array of een T*** voor een 3D array.

In mijn eerste reply heb ik inderdaad een 2D array [15][15] "omgezet" naar een 1D array [15*15], omdat die functioneel hetzelfde zijn. Daardoor kan ik met 1 loopje erdoorheen lopen zonder probleem :) Dat had ik wellicht wat kunnen toelichten.

Daarnaast zie ik ook een ander soort 2D array, een 1D array van 1D arrays langskomen in DataGhost's eerste post. Dat is inderdaad een heel ander beestje (die kan ook niet-vierkant zijn zeg maar, elke row kan een ander aantal elementen bevatten). Dat soort arrays kan natuurlijk niet door mijn loopje verwerkt worden, omdat de elementen niet in het geheugen na elkaar hoeven te liggen (kan wel natuurlijk).

-niks-


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

MLM schreef op zondag 27 september 2009 @ 00:46:
Nog even voor de duidelijkheid, C geeft niet om dimensies van arrays als je ze doorgeeft aan een functie,
Jawel. Je kunt een int[15][15] niet doorgeven aan een functie die een int* verwacht. De impliciete cast is naar int(*)[15], niet naar int*. Hij is natuurlijk wel layout-compatible met een 1D array, maar een expliciete cast in jouw voorbeeld blijft wel nodig. In het voorbeeld van Soultaker niet.
Daarnaast zie ik ook een ander soort 2D array, een 1D array van 1D arrays langskomen in DataGhost's eerste post. Dat is inderdaad een heel ander beestje (die kan ook niet-vierkant zijn zeg maar, elke row kan een ander aantal elementen bevatten).
Niet-rechthoekig bedoel je ;), en de term daarvoor is jagged array.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

.oisyn schreef op zondag 27 september 2009 @ 12:04:

[...]

Niet-rechthoekig bedoel je ;), en de term daarvoor is jagged array.
Als ie niet rechthoekig is, dan is ie ook niet vierkant :P (tuurlijk kunnen ze ook rechthoekig zijn, maar we hebben het al de hele tijd over 15x15)
Je hebt gelijk, ik wist die term ooit, maar die was me even compleet ontschoten (en het is wel duidelijk genoeg)

[ Voor 10% gewijzigd door MLM op 27-09-2009 12:46 ]

-niks-

Pagina: 1