[C] malloc 2D array

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

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

Mr_gadget

C8H10N4O2 powered

Topicstarter
Ik wil een lijst met namen maken met een variabele lengte. Daarom wil ik met malloc geheugen reserveren en dit later kunnen vergroten. Echter is het mij niet echt duidelijk hoe ik dit met een 2D array moet doen.

Ik wil dus bv een array namen[10][10] maken die later bv namen[100][10] kan worden gemaakt.
ik heb nu dit maar dit is dan maar voor een row..
C:
1
2
char *ptr; 
ptr = (char *)malloc(10*sizeof(char])); 

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

calloc. ;)

malloc kun je ook gebruiken, voor een 2D array van chars van 10x10 doe je dan gewoon een vermenigvuldiging:
C:
1
2
char **ptr;
ptr = (char**)malloc(10*10*sizeof(char]));


edit:
Van die laatste regel ben ik niet 100% zeker, mijn C-kennis is wat roestig. :)

[ Voor 108% gewijzigd door NMe op 06-10-2009 16:22 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

char**ptr is geen 2d array, maar een jagged array. Dan zul je dus eerst de buitenste array moeten mallocen, en dan elk element nog een keer specifiek.
C:
1
2
3
4
5
6
7
char ** ptr;
ptr = malloc(hoogte * sizeof(char*));

/* dit meteen doen, of uitstellen tot je 'm vult met strings
(dat laatste is handiger, omdat je dan weet hoe lang je strings gaan zijn) */
for (i = 0; i < 10; i++)
    ptr[i] = malloc(breedte * sizeof(char));

Overigens, sizeof(char) is per definitie 1

Mr_gagdet: als je genoegen wilt nemen met een vast aantal kolommen (zoals de 10 uit jouw voorbeeld), dan kun je dat zo doen:
C:
1
2
char (*ptr)[10];
ptr = malloc(sizeof(char[10][10]));


Het voordeel is hier dat je met 1 malloc klaar bent. Het nadeel is dat je de grootte niet af kunt laten hangen van ieder individueel element. Typisch gebruik je voor een array van strings wel gewoon char**, aangezien char* je string is. Maar dan moet je dus wel meerdere keren alloceren: eens voor je array, en eens per string in de array.

[ Voor 56% gewijzigd door .oisyn op 06-10-2009 16:40 ]

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

malloc reserveert geheugen op de heap
realloc verandert de grootte van geheugen op de heap
free geeft geheugen terug aan de heap

in jouw geval doe je dus waarschijnlijk eerst een malloc voor je eerste lijst, en naar mate je meer ruimte nodig hebt, gebruik je realloc om die ruimte te reserveren. als je je lijst niet meer nodig hebt, gebruik je free om het geheugen weer vrij te geven.

een 2D array met dimensies I, J kan je ook zien als een 1D array met dimensie I * J, dat kan je misschien helpen met je allocaties :)

de code van NMe hierboven lijkt me in elk geval niet helemaal wat je wilt hebben, een ptr[0][0] in dat geval verwijst naar de inhoud van het ongedefinieerde adres dat zich in de eerste 4 bytes van de allocatie bevind :)

je kan het wel iets anngepoast gebruiken:
C:
1
2
3
4
5
6
int *ptr; //1 indirectie
ptr = (int *)malloc(10 * 10 * sizeof(int)); //10 bij 10

//om een 2D index om te zetten naar 1D index
x = 0; y = 0; //x en y moeten wel in de 0-9 range range vallen in dit voorbeeld, omdat het een 10 bij 10 array is
waarde = ptr[x + y * breedte]; //breedte is 10 in dit geval, maar dat kan veranderen natuurlijk

[ Voor 4% gewijzigd door MLM op 06-10-2009 23:22 . Reden: char -> int voor duidelijkheid ]

-niks-


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Een array van strings benaderen als een linaire array van chars lijkt me wat onhandig, MLM...

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!

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

Mr_gadget

C8H10N4O2 powered

Topicstarter
Bedankt voor de antwoorden. Maar hoe zou ik het zo kunnen maken?
(ascii art gejat van: http://www.space.unibe.ch...l/C/CONCEPT/pointers.html)
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
     colours  *colours *(colours+2) **colours
          |         |       |           |
          |         |       |           |
          V         V       V           |     
         ---       -----------          |     
        |   |---->|   |   |   |         |     
         ---       -----------          |     
                    |   |   |           V     
                    |   |   |         -----------------------
                     --------------->| r | e | d |   |   |   |
                        |   |         -----------------------
                        |   |      
                        |   |          -----------------------
                         ---|-------->| g | r | e | e | n |   |
                            |          -----------------------
                            |
                            |          -----------------------
                             -------->| b | l | u | e |   |   |
                                       -----------------------
                                A           A
                                        |           |
                                        |           |
                                **(colours+2)   *(*(colours+2)+3)

Het aantal kleuren (namen in mijn geval) wil ik dus kunnen varieren. En dat ik dus per row een naam heb.
De lengte zou eigenlijk ook variabel moeten zijn, anders krijg ik troep ;)

[ Voor 3% gewijzigd door Mr_gadget op 06-10-2009 16:56 ]


Acties:
  • 0 Henk 'm!

  • writser
  • Registratie: Mei 2000
  • Laatst online: 16-09 10:48
Je wil een array gevuld met strings, right? Een string is weer een array van karakters, dus volgens mij kan je de oplossing van .oisyn gebruiken.

C:
1
2
3
4
5
6
7
8
9
10
char ** ptr;

// reserveer ruimte voor 'aantalKleuren' pointers naar een lijst van karakters
// (dus de strings waar je de kleuren in opslaat)
ptr = malloc(aantalKleuren * sizeof(char*));

for (i = 0; i < aantalKleuren; i++) {
    // hier elke kleur in de array gooien, weet niet waar je ze vandaan haalt.
    ptr[i] = ...;
}


Of je doet het in c++

C++:
1
2
3
  std:: vector <std::string> kleuren;
  kleuren.push_back("rood");
  kleuren.push_back("groen");

[ Voor 17% gewijzigd door writser op 06-10-2009 17:54 ]

Onvoorstelbaar!


Acties:
  • 0 Henk 'm!

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

MLM

aka Zolo

.oisyn schreef op dinsdag 06 oktober 2009 @ 16:37:
Een array van strings benaderen als een linaire array van chars lijkt me wat onhandig, MLM...
het was bedoeld als untyped voorbeeld, ik zal er ints van maken voor de duidelijkheid...

-niks-


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ja dat snap ik wel, maar ik bedoel dat de methode die je voorstelt, namelijk een daadwerkelijke 2D gemapt als linaire array, juist in het geval van de topicstarter minder handig is. Hij wil namelijk helemaal geen 2D array. Hij wil een array van strings.

[ Voor 23% gewijzigd door .oisyn op 07-10-2009 01:04 ]

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!

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

Mr_gadget

C8H10N4O2 powered

Topicstarter
Ik probeer nu de array te vullen en te resizen alleen werkt dat nog niet lekker. Namen lees ik uit een text file

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if(c!=EOF) {
c = fgetc(file);
            while(c!='"')
            {
                
                    printf("%c",c);
                    naam =realloc (naam, col+1);
                    naam[col]=c;
                    c = fgetc(file);
                    col =col +1;
                    
                    
                
                
            }
            printf("\n");
            printf("size is:%d ", (strlen(naam)));
            array =realloc (array, (strlen(naam)+sizeof(array)+19));
            strcpy((*(array+count)), naam);
            count=count+1;
            col =0;
            naam =0;


De size gaat niet goed :/ sizeof geeft een constante lengte bij de array naam.

[ Voor 4% gewijzigd door Mr_gadget op 07-10-2009 16:58 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Je gebruikt de sizeof-operator voor zover ik weet doorgaans ook voor types, niet voor variabelen.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • user109731
  • Registratie: Maart 2004
  • Niet online
C/C++ houdt nergens de lengte van 'array' bij, sizeof werkt in dit geval dus niet. Waarschijnlijk pak je nu de sizeof van de pointer, en dat zal idd 4 of 8 zijn... Je kunt een sentinel waarde aan het eind gebruiken (0 ofzo) of de lengte opslaan in een aparte variabele :)

@NMe: sizeof(variabele) kan ook, zelfs sizeof(expressie) :)

[ Voor 58% gewijzigd door user109731 op 07-10-2009 17:21 ]


Acties:
  • 0 Henk 'm!

  • unclero
  • Registratie: Juni 2001
  • Laatst online: 17-09 22:39

unclero

MB EQA ftw \o/

JanDM schreef op woensdag 07 oktober 2009 @ 17:15:
C/C++ houdt nergens de lengte van 'array' bij, sizeof werkt in dit geval dus niet. Waarschijnlijk pak je nu de sizeof van de pointer, en dat zal idd 4 of 8 zijn... Je kunt een sentinel waarde aan het eind gebruiken (0 ofzo) of de lengte opslaan in een aparte variabele :)

@NMe: sizeof(variabele) kan ook, zelfs sizeof(expressie) :)
Of als je helemaal bad-ass masochistisch bent, de eerste paar bytes in je array reserveren voor de size...


C:
1
2
3
#define ARRAY_START 2

unsigned short usArraySize = (cpBuffer[0] << 8) | cpBuffer[1];


;)

Quelle chimère est-ce donc que l'homme? Quelle nouveauté, quel monstre, quel chaos, quel sujet de contradiction, quel prodige!


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
unclero schreef op woensdag 07 oktober 2009 @ 18:06:
[...]


Of als je helemaal bad-ass masochistisch bent, de eerste paar bytes in je array reserveren voor de size...
Hoef je geen masochist voor te zijn, je moet 't alleen wat slimmer aanpakken.

code:
1
unsigned short usArraySize = (cpBuffer[-2] << 8) | cpBuffer[-1];


En dan na 't alloceren meteen de pointer met 2 bytes opschuiven.

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
PrisonerOfPain schreef op woensdag 07 oktober 2009 @ 18:35:
[...]


Hoef je geen masochist voor te zijn, je moet 't alleen wat slimmer aanpakken.

code:
1
unsigned short usArraySize = (cpBuffer[-2] << 8) | cpBuffer[-1];


En dan na 't alloceren meteen de pointer met 2 bytes opschuiven.
Alleen zegt de C standaard (C++ ook, als ik me goed herinner) dat gedrag bij negatieve array indices ongespecificeerd is...

[ Voor 4% gewijzigd door R4gnax op 07-10-2009 18:45 ]


Acties:
  • 0 Henk 'm!

  • bloody
  • Registratie: Juni 1999
  • Laatst online: 17-09 21:05

bloody

0.000 KB!!

PrisonerOfPain schreef op woensdag 07 oktober 2009 @ 18:35:
[...]


Hoef je geen masochist voor te zijn, je moet 't alleen wat slimmer aanpakken.

code:
1
unsigned short usArraySize = (cpBuffer[-2] << 8) | cpBuffer[-1];


En dan na 't alloceren meteen de pointer met 2 bytes opschuiven.
Ik heb het vage vermoeden dat TS hier niet in geinteresseerd is :P
@TS: is het niet handiger dat je dan die push_back manier gebruikt? Dus een vector?

nope


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
R4gnax schreef op woensdag 07 oktober 2009 @ 18:44:
[...]


Alleen zegt de C standaard (C++ ook, als ik me goed herinner) dat gedrag bij negatieve array indices ongespecificeerd is...
In C++ is dit sowieso geldig, zie paragraaf 5.7.5:
When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i–n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.
Dat in combinatie met 8.3.4
Except where it has been declared for a class (13.5.5), the subscript operator [] is interpreted in such a way that E1[E2] is identical to *((E1)+(E2)). Because of the conversion rules that apply to +, if E1 is an array and E2 an integer, then E1[E2] refers to the E2-th member of E1. Therefore, despite its asymmetric appearance, subscripting is a commutative operation.
In C zal ook zoiets gelden, anders zou pointer arithmetic geheid de helft van z'n nuttigheid verloren hebben.

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
PrisonerOfPain schreef op woensdag 07 oktober 2009 @ 18:56:
In C++ is dit sowieso geldig, zie paragraaf 5.7.5:
Klopt inderdaad. Ik had even gemist dat je de pointer naar cpBuffer meteen met 2 bytes op had geschoven. In dat geval werkt het inderdaad wel, want cpBuffer[-2] is dan idd. geldige pointer arithmetic (cpBuffer-2) naar het eerste element van het array zoals je dat gealloceerd had.

(Oeps!)

[ Voor 91% gewijzigd door R4gnax op 07-10-2009 19:29 ]


Acties:
  • 0 Henk 'm!

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

MLM

aka Zolo

PrisonerOfPain schreef op woensdag 07 oktober 2009 @ 18:35:
[...]


Hoef je geen masochist voor te zijn, je moet 't alleen wat slimmer aanpakken.

code:
1
unsigned short usArraySize = (cpBuffer[-2] << 8) | cpBuffer[-1];


En dan na 't alloceren meteen de pointer met 2 bytes opschuiven.
Of je bepaart jezelf een shift en een logical or, en je haalt je unsigned short in 1x eruit:
C:
1
unsigned short usArraySize = ((unsigned short *)cpBuffer)[-1];

Voordeel is dat dit ook werkt als je je buffer-type verandert, en makkelijker aan te passen als je je length-type verandert (2x replace vs een extra or en shift), en niet vereist dat een short 2x zo groot als een char is :) Op sommige architectures is sizeof(char) == sizeof(unsigned short) en dan gaat de eerste code leuk de mist in :P

-niks-


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

MLM schreef op donderdag 08 oktober 2009 @ 09:57:
[...]


Of je bepaart jezelf een shift en een logical or
da's een bitwise or ;)

Overigens zou ik het zo doen:
C:
1
2
3
4
5
6
7
8
9
10
11
12
struct CharArray
{
    size_t length;
    char data[1];
};

CharArray * CharArray_alloc(size_t length)
{
    CharArray * pArray = malloc(length + sizeof(size_t));
    pArray->length = length;
    return pArray;
}

[ Voor 42% gewijzigd door .oisyn op 08-10-2009 10:17 ]

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!

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

Mr_gadget

C8H10N4O2 powered

Topicstarter
Ik heb nu iets wat enigsinds lijkt te werken maar hoe krijg ik een pointer waarde zichtbaar in de main?

Ik heb de functie
C:
1
 int read_names(int *name_count); 

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
main()
{
 int *name_count=0;

 read_names(name_count); 
 printf("%d", *name_count);

}


int read_names(int *name_count)
{
*name_count=11;
}


In main veranderd hij niet...hoe zou ik name_count kunnen mallocen zodat hij wel zichtbaar is? Of moet ik de functie met & aanroepen?

[ Voor 0% gewijzigd door Mr_gadget op 16-10-2009 21:27 . Reden: fout ]


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Er klopt geen bal van je code. Je initialiseert een pointer met 0, wat niet mag in C. Regel 5 lijkt op een declaratie, maar die is ongeldig omdat je een variabele erin gebruikt. Je gaat me niet vertellen dat dit überhaupt compilet. Bottom line is dat je gewoon even een basis cursus C moet doen :).

.edit: blijkbaar heb ik zelf ook een cursus nodig, want 0 assignen aan een pointer mag dus wel :X. Ik zie dat je regel 5 ook gewijzigd hebt. Dit lijkt er idd meer op. Het probleem, zoals je hieronder ook kunt lezen, is dat de pointer nergens naar wijst. Je kunt een int alloceren, of gewoon op de stack definieren en het adres ervan nemen (waarvoor je dan idd de & nodig hebt)

[ Voor 76% gewijzigd door .oisyn op 16-10-2009 21:37 ]

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!

  • user109731
  • Registratie: Maart 2004
  • Niet online
'int read_names(name_count); ' in main is een typefout? En kreeg je geen 'segmentation faults' ofzo? Volgens mij schrijf je nu naar een null pointer.

Je 'alloceert' nu nergens een int. Wat ik zou doen:
C:
1
2
3
4
5
6
7
8
9
main()
{
  int count = 0;
  foo(&count);
}
void foo(int* count)
{
  *count = 10;
}

Ongetest, maar zo zou het moeten werken. In main heb je een int op de stack. Daarvan geef je het adres door aan foo(), die er vervolgens een waarde aan toekent :)

Acties:
  • 0 Henk 'm!

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

Mr_gadget

C8H10N4O2 powered

Topicstarter
oisyn: het stukje komt uit een groter geheel en is niet goed geknipt en geplakt. Maar ik ben idd bezig met een basiscursus C ;)

JanDM: hier kan ik wat mee!

Maar als ik een variabele heb op de heap hoe doe ik dit dan? Roep ik het zo correct aan?
(laat even voor eenvoud file en name_count weg)


C:
1
2
3
4
5
6
7
8
9
10
11
12
13
main()
{
 char ***names=0; 
 read_names(file_n, &names_, &name_count); 
printf("naam is: %s",*names);

}

read_names(FILE *file, char ***names, int *name_count)
{
*names=malloc((col)*sizeof(char));
 *(names+number)=naam;
}

Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Mr_gadget schreef op vrijdag 16 oktober 2009 @ 21:43:
oisyn: het stukje komt uit een groter geheel en is niet goed geknipt en geplakt.
Het maakt het voor ons een stuk makkelijker om je te helpen als je hier code neerzet die demonstreert wat je wilt doen en ook compileert. Dan hoeven we niet te raden naar wat er elders staat: of de geposte code klopt hangt vaak af van de overige code. Bovendien kan maar een beperkte groep ervaren gebruikers je helpen door code enkel te lezen: anderen, zoals ik, moeten het gedrag controleren door de code daadwerkelijk uit te voeren en aan te passen.

Wie trösten wir uns, die Mörder aller Mörder?


Acties:
  • 0 Henk 'm!

  • user109731
  • Registratie: Maart 2004
  • Niet online
Mr_gadget schreef op vrijdag 16 oktober 2009 @ 21:43:
Maar als ik een variabele heb op de heap hoe doe ik dit dan? Roep ik het zo correct aan?
(laat even voor eenvoud file en name_count weg)
Werkt dit zonder te crashen? names binnen main is een NULL-pointer, en die dereference je met *names.
Verder geeft de & operator je het adres van een variabele. Gebruik je echter memory op de heap dan is dat niet nodig, want malloc geeft je al een adres :)
Ik zou read_names de 'names' pointer laten returnen als het kan. Dat maakt het veel eenvoudiger.

Verder met Confusion en .oisyn, werkende code is handiger en dit is vrij basic C :)
Pagina: 1