C, array van pointers naar struct

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Swedgin
  • Registratie: Februari 2016
  • Laatst online: 12-01-2022
Hallo,

Ik ben bezig met een programmatje te schrijven in C, maar ik heb een probleem om een array van pointers naar struct te initializeren.

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
typedef uint8_t size_m;
typedef float T;

typedef struct {

    size_m n_rows;
    size_m n_cols;
    T* mat;

} matrix;

typedef matrix* ptr_mat;

void mat_free(ptr_mat x) {

    free(x->mat);

}

void ptr_mat_free(ptr_mat x) {

    free(x->mat);
    free(x);

}

void calc_means(ptr_mat means, ptr_mat* means_sens);

int main(void) {
    uint8_t sen = 0, sensor_count = 4;
    uint8_t feature_count = 6, class_count = 10;
    uint8_t total_feature_count = feature_count*sensor_count;

    ptr_mat means = malloc(sizeof(*means));
    means->n_rows = class_count;
    means->n_cols = total_feature_count;
    means->mat = calloc(means->n_rows * means->n_cols, sizeof(*means->mat));

    ptr_mat means_sens[sensor_count];
    for (; sen < sensor_count; ++sen) {
        means_sens[sen] = malloc(sizeof(*means_sens[sen]));       //pointers alloceren
        means_sens[sen]->n_rows = class_count;                          
        means_sens[sen]->n_cols = feature_count;
        means_sens[sen]->mat = calloc(means_sens[sen]->n_rows * means_sens[sen]->n_cols, sizeof(*means_sens[sen]->mat));
    }

    calc_means(means, means_sens);                        //<-- foutmelding
    mat_print(means)
    for (sen = 0; sen < sensor_count; ++sen)
        mat_print(means_sens[sen]);
    
    ptr_mat_free(means);
    for (sen = 0; sen < sensor_count; ++sen)
         mat_free(means_sens[sen]);
    
    return 0;
}



In clion geeft de regel met de pijl mij een runtime error:
Signal: SIGSEGV (Segmentation fault)

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)


Dus volgens mij is de array niet juist aangemaakt. Hoe doe ik dit het best? Maak ik ook het geheugen correct weer vrij?


EDIT:
C:
1
2
3
4
5
6
7
    ptr_mat means_sens[sensor_count];
    for (; sen < sensor_count; ++sen) {
        means_sens[sen] = malloc(sizeof(*means_sens[sen]));
        means_sens[sen]->n_rows = class_count;                        
        means_sens[sen]->n_cols = feature_count;
        means_sens[sen]->mat = calloc(means_sens[sen]->n_rows * means_sens[sen]->n_cols, sizeof(*means_sens[sen]->mat));
    }


Ik moet de pointer ook alloceren. Maar nu geeft ie dezelfde foutmelding op de functie calc_means(ptr_mat, ptr_mat*)

[ Voor 16% gewijzigd door Swedgin op 02-08-2017 23:31 . Reden: typo ]

Alle reacties


Acties:
  • 0 Henk 'm!

  • mandroid
  • Registratie: Juli 2002
  • Laatst online: 08-10 19:59
Je defineert een array van pointers, maar je initialiseert de pointers in de array niet. Je maakt maw een array van random data die later wordt geinterpreteerd als een pointer naar een ongeldig object.

Als je echt een array van pointers nodig hebt, moet je zowel de array definieren, en elke object in de array initializeren (maw opvullen met ponters naar geldige objecten).

Acties:
  • 0 Henk 'm!

  • Swedgin
  • Registratie: Februari 2016
  • Laatst online: 12-01-2022
mandroid schreef op woensdag 2 augustus 2017 @ 21:02:
Je defineert een array van pointers, maar je initialiseert de pointers in de array niet. Je maakt maw een array van random data die later wordt geinterpreteerd als een pointer naar een ongeldig object.

Als je echt een array van pointers nodig hebt, moet je zowel de array definieren, en elke object in de array initializeren (maw opvullen met ponters naar geldige objecten).
Thanks voor je antwoord. Ik had het net zelf ook gevonden. Ik heb mijn OP ge-edit, want mijn foutmelding verplaatst hem naar waar de functie calc_means wordt opgeroepen. (In debug stopt ie op de functie lijn void calc_mean() {)

Acties:
  • 0 Henk 'm!

  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 08:44

BoAC

Memento mori

Swedgin schreef op woensdag 2 augustus 2017 @ 21:06:
[...]


Thanks voor je antwoord. Ik had het net zelf ook gevonden. Ik heb mijn OP ge-edit, want mijn foutmelding verplaatst hem naar waar de functie calc_means wordt opgeroepen. (In debug stopt ie op de functie lijn void calc_mean() {)
Ik vind de implementatie van de functie calc_mean() niet..

Acties:
  • 0 Henk 'm!

  • Swedgin
  • Registratie: Februari 2016
  • Laatst online: 12-01-2022
BoAC schreef op woensdag 2 augustus 2017 @ 21:18:
[...]

Ik vind de implementatie van de functie calc_mean() niet..
Doet dat er toe? calc_means() vraagt een ptr_mat en een pointer naar ptr_mat (de eerste matrix van de 4 in de rij). In de functie vult hij deze matrices in aan de hand van data in een csv file.
De reden waarom 1 matrix en een array van 4 matrices is omdat ik data op 2 manieren wil bekijken. Eenmaal alle features tesamen en eenmaal per sensor apart. Het laatste vergt namelijk minder instructies in de latere berekeningen.
Ik zit momenteel terug op windows. Ik zal ze morgen posten indien nodig.

Acties:
  • 0 Henk 'm!

  • Gropah
  • Registratie: December 2007
  • Niet online

Gropah

Admin Softe Goederen

Oompa-Loompa 💩

De vraag is of de error wel daadwerkelijk komt bij het aanroepen van de functie of dat het gebeurd door een operatie in die functie. Ik ben namelijk nog nooit een situatie tegengekomen waarbij de pure functie aanroep een segvault gaf.

Overigens zou ik je ook aanraden om te compileren met de -g flag van GCC en eventueel het programma te runnen via valgrind (als je op unix werkt) omdat je dan net iets beter kunt zien wat er allemaal fout gaat en waar.

Acties:
  • 0 Henk 'm!

  • DroogKloot
  • Registratie: Februari 2001
  • Niet online

DroogKloot

depenisvanjezus

Terzijde, ik zie geen bijzondere reden om de means_sens array en means niet gewoon op de stack te alloceren, i.e.

C:
1
2
3
4
5
6
matrix means;
matrix means_sens[sensor_count];
...
means.mat = calloc(means.n_rows * means.n_cols, sizeof(T));
...
calc_means(&means, &means_sens[0]);


aangezien sensor_count toch een constante is, en anders bestaat er (in gcc) nog alloca. Dat bespaart *en* een hoop overbodige indirectie *en* verkleint de kans op bugs zoals deze. Je kunt dit eventueel ook doortrekken naar de T* mat's.

[ Voor 7% gewijzigd door DroogKloot op 03-08-2017 00:01 ]


Acties:
  • 0 Henk 'm!

  • Swedgin
  • Registratie: Februari 2016
  • Laatst online: 12-01-2022
Gropah schreef op woensdag 2 augustus 2017 @ 23:40:
De vraag is of de error wel daadwerkelijk komt bij het aanroepen van de functie of dat het gebeurd door een operatie in die functie. Ik ben namelijk nog nooit een situatie tegengekomen waarbij de pure functie aanroep een segvault gaf.

Overigens zou ik je ook aanraden om te compileren met de -g flag van GCC en eventueel het programma te runnen via valgrind (als je op unix werkt) omdat je dan net iets beter kunt zien wat er allemaal fout gaat en waar.
http://imgur.com/a/uHE79

Ok, volgens mij gebeurt het door een operatie in de functie zelf. Ik moet arrays inlezen van 800 samples en die sample per sample bekijken.

char buf[x] is de boosdoener.

Als ik in calc_means() de matrices gewoon opvul door erdoor te itereren, werkt de functie en zijn er geen foutmeldingen.

C:
1
2
3
4
5
6
7
8
9
10
11
12
void calculate_means(ptr_mat means, ptr_mat* means_sens) {

    uint8_t i = 0, sen = 0;
    for (; i < means->n_rows * means->n_cols; ++i)
        means->mat[i] = i;

    for (; sen < 4; ++sen) {
        for (i = 0; i < means_sens[sen]->n_rows*means_sens[sen]->n_cols; ++i)
            means_sens[sen]->mat[i] = i;
    }

}



Ik zal eerlijk zijn, van debuggen heb ik nog weinig kaas gegeven. Meestal vind ik handmatig de fout naar lang zoeken maar zou dit toch willen verbeteren.
Volgens mij compileert clion momenteel met cmake en niet met GCC. Ik zou moeten kijken hoe ik dit moet veranderen.
Valgrind heb ik vroegen nog eens gebruikt, maar nooit goed valgrind leren gebruiken waardoor dit nog steeds abstract is en mij niet echt veel vooruit helpt.


@DroogKloot Bedankt voor de tip om geen ptr_mats aan te maken maar gewoon mat's. Wat bedoel je met doortrekken naar de T* mats? Die ook aanmaken volgens means.mat[.n_rows*.n_cols]? Gaat toch niet werken?

In de finale versie ga ik de struct matrix eruit halen en enkel met arrays werken. Ik weet op voorhand hoe groot de arrays/matrices zijn dus kan ik dat semi hard coderen. Voorlopig is het zo gemakkelijker om te testen en maak ik zo mijn eigen matrix library aan.
Het is de bedoeling om deze code op een arduino uno te laten draaien.

Acties:
  • 0 Henk 'm!

  • mandroid
  • Registratie: Juli 2002
  • Laatst online: 08-10 19:59
Je maakt een array van maar liefst 10 gigabyte, dat wil al wel eens fout lopen :).

code:
1
char buf[10000000000];

Acties:
  • 0 Henk 'm!

  • Swedgin
  • Registratie: Februari 2016
  • Laatst online: 12-01-2022
Haha lol, misschien paar nullekes teveel gezet. Ik wou er allesinds genoeg hebben voor de hele rij. :)
Dus, 800 floats -> 800*4 bytes -> 3200 + 100 reserve zou dus eigenlijk voldoende moeten zijn.

char buf[3300]; (te weinig, => segfault) -> char buf[11000]; OK

11000 gevonden door trial and error met de natte vinger

Ie geeft verder in de functie weer segfault. Zal nog wat verder zoeken. Terwijl ook eens die ptr_mats veranderen door matrix's

EDIT:
Is er een verschil in:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
void calc_means(ptr_mat means, ptr_mat means_sens);

matrix means;
matrix means_sens[sensor_count];
/*
init n_rows, n_cols and allocate needed space
*/

//method 1:
calc_means(&means, means_sens)

//method 2:
calc_means(&means, &means_sens[0])

[ Voor 40% gewijzigd door Swedgin op 03-08-2017 15:44 ]


Acties:
  • 0 Henk 'm!

  • DroogKloot
  • Registratie: Februari 2001
  • Niet online

DroogKloot

depenisvanjezus

Swedgin schreef op donderdag 3 augustus 2017 @ 14:20:
[...]


@DroogKloot Bedankt voor de tip om geen ptr_mats aan te maken maar gewoon mat's. Wat bedoel je met doortrekken naar de T* mats? Die ook aanmaken volgens means.mat[.n_rows*.n_cols]? Gaat toch niet werken?
Aangezien (of beter gezegd als) de dimensies van je matrices van te voren vaststaan, kun je struct matrix ook zo opschrijven:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <assert.h>
#include <stdint.h>
#include <string.h>

#define SENSOR_COUNT 4
#define FEATURE_COUNT 6
#define CLASS_COUNT 10
#define TOTAL_FEATURE_COUNT (FEATURE_COUNT * SENSOR_COUNT)

typedef uint8_t size_m;
typedef float T;

typedef struct {
    size_m n_rows;
    size_m n_cols;
    T mat[CLASS_COUNT * FEATURE_COUNT];
} sens_matrix;

typedef struct {
    size_m n_rows;
    size_m n_cols;
    T mat[CLASS_COUNT * TOTAL_FEATURE_COUNT];
} mean_matrix;


void init_matrices(mean_matrix* means, sens_matrix* means_sens) {
    means->n_rows = CLASS_COUNT;
    means->n_cols = TOTAL_FEATURE_COUNT;

    assert(sizeof(means->mat) == (means->n_rows * means->n_cols * sizeof(T)));
    memset(&means->mat[0], 0, sizeof(means->mat));

    for (size_m sen = 0; sen < SENSOR_COUNT; ++sen) {
        means_sens[sen].n_rows = CLASS_COUNT;
        means_sens[sen].n_cols = FEATURE_COUNT;

        assert(sizeof(means_sens[sen].mat) == (means_sens[sen].n_rows * means_sens[sen].n_cols * sizeof(T)));
        memset(&means_sens[sen].mat[0], 0, sizeof(means_sens[sen].mat));
    }
}

int main(void) {
    mean_matrix means;
    sens_matrix means_sens[SENSOR_COUNT];

    init_matrices(&means, &means_sens[0]);
    // ...
    return 0;
}


Nu hoef je geen enkele dynamische allocatie meer te doen (dat is op embedded systemen vaak niet eens mogelijk), en zelfs de n_rows en n_cols die nu geinitialiseerd worden in init_matrices zijn feitelijk overbodig want je weet per type matrix (mean_matrix of sens_matrix) al het aantal rijen en kolommen.
Swedgin schreef op donderdag 3 augustus 2017 @ 14:39:
EDIT:
Is er een verschil in:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
void calc_means(ptr_mat means, ptr_mat means_sens);

matrix means;
matrix means_sens[sensor_count];
/*
init n_rows, n_cols and allocate needed space
*/

//method 1:
calc_means(&means, means_sens)

//method 2:
calc_means(&means, &means_sens[0])
Nee; vanwege array decay zijn die twee methodes equivalent en welke je kiest is persoonlijke stijl.

Acties:
  • 0 Henk 'm!

  • Swedgin
  • Registratie: Februari 2016
  • Laatst online: 12-01-2022
Achzo, nu ben ik mee met wat je bedoelt. Maar ik ga niet voor de 4 type matrices een eigen struct schrijven, want dat betekent dat ik dan ook elke matrix functie 4 maal moet schrijven.

Voorlopig werk ik nog met malloc omdat ik op mijn computer zelf nog aan het testen ben, -assert en memset ken ik niet.
Ik heb een matrix.h file met daarin zelfgemaakte matrix/array functies. De matrix functies vragen minstens een pointer naar een matrix en geven eventueel een ptr_mat (gealloceerd in de functie) terug. De array functies vragen minstens een pointer naar T en een size_m lengte.
Uiteindelijk moet de fixed point versie op de arduino komen met enkel 1D arrays.


Ik denk van mezelf dat ik de basis van C ken, maar ik heb moeite om er mee te spelen en of ik wel de "juiste regels" volg. Het meeste heb ik mezelf aangeleerd via al doende dingen op te zoeken en te schrijven.

Acties:
  • 0 Henk 'm!

  • epic007
  • Registratie: Februari 2004
  • Laatst online: 07-10 10:46
Je hebt een mooie functie om een ptr_mat te free-en

C:
1
2
3
4
void ptr_mat_free(ptr_mat x) {
    free(x->mat);
    free(x);
}


Waarom geen functie om er een te alloceren?

C:
1
2
3
4
5
6
7
ptr_mat ptr_mat_malloc(size_m rows, size_m cols) {
  ptr_mat result =  malloc(sizeof(matrix);
  result->n_rows = rows;
  result->n_cols = cols;
  result->mat = calloc(rows*cols,sizeof(T))
  return result;
}

Acties:
  • 0 Henk 'm!

  • Swedgin
  • Registratie: Februari 2016
  • Laatst online: 12-01-2022
Ha, geen idee waarom ik dit niet in een functie gestoken had. Maakte de ptr_mats telkens handmatig aan.

Ik heb calculate_means() werkend gekregen. Nu bezig met de fixed point implementatie maar krijg soms rare uitkomsten. Ik mag weer paar uurkes debuggen :p

Acties:
  • 0 Henk 'm!

  • Twieka
  • Registratie: Oktober 2010
  • Laatst online: 01-03 17:06
Leuk hoor, al dat gerommel met pointers. Is c++ niet een mogelijkheid?
Kan je je dataset bv. als een std::vector van std::valarray beschouwen.

Acties:
  • 0 Henk 'm!

  • Swedgin
  • Registratie: Februari 2016
  • Laatst online: 12-01-2022
Ik ben in C begonnen en wil dit nu ook afwerken in C.
In principe heb ik de feature vector niet meer nodig nadat ik bepaald heb tot welke klasse hij behoort. Het lijkt mij gemakkelijker en minder intensief om gewoon een 1D array aan te maken met dan een pointer die erdoor loopt om de features in te vullen.

aka zoiets:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int feat[24];
int* it_f = feat;
int sample[3]
for (s = 0; s < sensors; ++s) {
it_f = feat + s*feature_count;
while (window not full) {
sample[2] = new_sample;
update_gemiddelde(it_f, sample+2);
update_rms(it_f+1, sample+2);
update_zero_cross(it_f+2, sample+2);
//...
update_slope_change(it_f+5, sample+2);
sample[0] = sample[1];
sample[1] = sample[2];
}
}
// predict the class of the vector
// using mahalanobis-distance/multivariate gaussian distribution



Dit is voor op een arduino. Ik sample aan 1-2 kHz, en zou na elke sample de features updaten. Om dan daarna de klasse te bepalen.
C:
1
2
3
4
5
6
7
8
9
10
while (true) {
for (w < window_length; ++w) {
    t0: ADC_0: done -> feature_vector[0:6] updaten
    t1: ADC_1: done -> feature_vector[6:12] updaten
    t2: ADC_2: done -> feature_vector[12:18] updaten
    t3: ADC_3: done -> feature_vector[18:24] updaten
}
final_update of feature_vector
predict_class(feature_vector);
}


En dit alles zou 400 ms in beslag mogen nemen per window (150-200 ms)

[ Voor 24% gewijzigd door Swedgin op 07-08-2017 22:13 . Reden: typo ]


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 27-09 13:03
Als je C99 kunt gebruiken zou je er voor kunnen kiezen om een flexible array member te gebruiken (of als je GNU extensies mag gebruiken een zero sized array ), vind ik bij dit soort use-cases wat cleaner:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
typedef struct {
    int n_rows;
    int n_cols;
    float mat[];
} sens_matrix;

sens_matrix* alloc_matrix( int rows, int cols )
{
    sens_matrix* r = (sens_matrix*) malloc( sizeof(sens_matrix) + ( sizeof( float ) * rows * cols ) );
    if( r ) {
        r->n_rows = rows;
        r->n_cols = cols;

        for( int i = 0; i < rows * cols; ++i )
            r->mat[ i ] = 0.f;
    }

    return r;
}

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1