[Ansi C] pointers doorgeven aan een functie

Pagina: 1
Acties:

  • Ti_Uhl
  • Registratie: Mei 2003
  • Laatst online: 19-09-2012
Ik ben een programma aan het schrijven om het verbeteren van dactylo oefeningen gemakkelijker te maken maar ik ben ergens in de mist gegaan met het doorgeven van waardes aan functies.

Het programma werkt als volgt :
Eerst word het orginele bestand ingelezen in een array van woorden.
Dan word het te verbeteren bestand gefiltert om het te veel aan spaties te verwisselen door _. Dit omdat ook spaties een fout moet zijn.
Dan word de te verbeteren tekst ook in een array van woorden gezet
vervolgens ga ik alle woorden controleren en indien nodig fouten bijhouden.

Nu het probleem zit hem volgens mij in het feit dat die array's, die overigens dynamisch worden gemaakt, by value worden doorgegeven ipv by reference want in de functie fillarray worden ze gevult maar ik kan in mijn main geen waarde meer uit die array krijgen. Dit geldt ook voor checkArray en compareWord. Volgens mij word er iedere keer een copie van mijn array's gemaakt ipv mijn orginele te gebruiken die in main zijn aangemaakt.

Ik weet dat dit waarschijnlijk een slecht geprogrammeerd en waarschijnlijk buggy programma is maar dit is de eerste keer dat ik in C iets maak en ken er dus ook niet al te veel van.

Hieronder de code van het programma :

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/* Created by Anjuta version 1.2.2 */
/*  This file will not be overwritten */

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

// misch is dit niet zo'n schone oplossing maar het vergemakkelijkt de oplossing
// wel. Nu moet ik geen dynamische 2 dimensionale array gaan maken om die 
// woorden op te slaan :)
typedef struct woord {
    char woord[50];
} woord;

FILE *fjuist;           // het bestand met de juiste versie
FILE *fteverbeteren;    // het bestand dat moet verbeterd worden
FILE *fout;
FILE *fres;
// hier worden de resultaten naartoe geschreven

char foutFileName[20] = "teverbeteren.txt";
char juistFileName[20] = "origineel.txt"; 
char outputFileName[20] = "out.txt";
char outputResFileName[20] = "resultaten.txt";
char spatie = '_';

// prototypes van de functies :)
void filterSpaces(FILE *file, FILE *outfile, char spaceVar);
short fillArray(FILE *file, woord *array);
void checkArray(woord *arrayFout,short narrayFout, woord *arrayOrgineel, short narrayOrgineel, FILE *output);
short compareWord(char orgineel[50],char fout[50]);

int main(void) {
    
    // geheugen vrijmaken voor het eerste element van de array 
    woord *foutarray = (woord *) malloc(sizeof(woord));
    short nfoutarray = 1;
    
    woord *juistarray = (woord *) malloc(sizeof(woord));
    short njuistarray = 1;
    
    // het orgineel in een array steken
    if ( (fjuist = fopen(juistFileName,"r")) != NULL ) {
        njuistarray = fillArray(fjuist,juistarray);
        fclose(fjuist);
    }
    
    // te verbeteren openen
    if ( (fteverbeteren = fopen(foutFileName,"r") ) != NULL && (fout = fopen(outputFileName,"w+")) != NULL && (fres = fopen(outputResFileName,"w+")) != NULL) {
        filterSpaces(fteverbeteren,fout,spatie);
        rewind(fout);
        nfoutarray = fillArray(fout,foutarray);
        printf("aantal woorden :) %d\n",nfoutarray);
        checkArray(foutarray,nfoutarray,juistarray,njuistarray,fres);
        
    }       
    return (0);
}


/*
Naam functie : filterSpaces
Auteur : Ti_Uhl
Argumenten : 
    *file : het bestand dat moet gefilterd worden
    *outfile : bestand naarwaar de gefilterde tekst moet geschreven worden
    spaceVar : karakter dat de spaces moet verangen
Doel : 
Vervangt de spaties die te veel zijn in $file met spaceRep en schrijft het
bestand weg naar *outfile
*/

void filterSpaces(FILE *file, FILE *outfile, char spaceVar) {
    
    // local vars 
    long currentPointer;
    
    char currentChar;
    char nextChar;
    
    while ( !feof(file) ) {
        currentChar = fgetc(file);
        if ( currentChar == ' ' ) {
            // we onthouden de filepointer en kijken eerst ff na of de volgende
            // ook een spatie is :)
            currentPointer = ftell(file);
            nextChar = fgetc(file);
            if (nextChar == ' ') {
                // we gaan de vorige op _ zetten :)
                currentChar = spaceVar;
            }
            // we gaan terug op de juiste pos staan :)
            fseek(file,currentPointer,SEEK_SET);
        } 
        fputc((int)currentChar,outfile);
    }
}


/*
Naam functie : fillArray
Auteur : Ti_Uhl
Argumenten : 
    *file : het bestand dat in de array moet geplaatst worden
    *array : de array waarin het bestand moet gestoken worden
Doel : 
    Deze functie leest het bestand in en plaatst alle woorden in een array.
TODO :
    Deze functie moet nog aangepast worden zodat de woorden niet meer in een 
    char[50] worden gestoken want dit kan wel eens veel te veel geheugen gaan 
    vreten dan nodig :)
*/
short fillArray(FILE *file, woord *array) {
    
    short i=0;
    short n = 1;
    
    // voor een of andere reden moet ik die while zo schrijven anders probeert
    // nog verder te lezen dan de tekst lang is :)  
    while ( ( (fscanf(file,"%s",array[i].woord)) != 0 ) && !feof(file) ) {
        
        //fscanf(file,"%s",array[i].woord);
        printf("%s\n",array[i].woord);
        array = ( woord *) realloc(array,(++i +1) * sizeof(woord)); 
        n++;
    }
    return(n);
}


/*
Naam functie : checkArray
Auteur : Ti_Uhl
Argumenten : 
    *arrayfout : de array met de te verbeteren woorden
    *narrayfout : element count van arrayfout
    *arrayorgineel : de array met de orginele woorden
    *narrayorgineel : element count van arrayorgineel
    *output : het bestand naarwaar de resultaten moeten geschreven worden
Doel : 
    Controleert alle woorden op fouten en schrijft de resultaten weg naar
    output
*/
void checkArray(woord *arrayFout, short narrayFout, woord *arrayOrgineel, short narrayOrgineel, FILE *output) {
    
    short i=0;
    short totSpatieFout = 0;
    short totCharFout = 0;
    short foutcode = 0;
    short aangSpatieFout = 0;
    short aangCharFout = 0;
    short tempSpatieFout = 0;
    short tempCharFout = 0;
    
    for (i=0;i<narrayFout;i++) {
        foutcode = compareWord(arrayFout[i].woord,arrayOrgineel[i].woord);
        tempSpatieFout = foutcode / 10;
        tempCharFout = foutcode % 10;
        printf("%d : %s : %s\n",i,arrayOrgineel[i].woord,arrayFout[i].woord);
        printf("Spatiefout : %d ",tempSpatieFout);
        printf("Charfout : %d\n",tempCharFout);
        if (tempSpatieFout != 0) {
            aangSpatieFout++;
        }
        if (tempCharFout != 0) {
            aangCharFout++;
        }
        totSpatieFout += tempSpatieFout;
        totCharFout += totCharFout;     
    }
    // ff alles naar res bestand schrijve ;)
    fprintf(output,"----------------------------------------------\n");
    fprintf(output,"Bestandsnaam : %s\n",outputResFileName);
    fprintf(output,"tijdstip creatie : %s\n",outputResFileName);
    fprintf(output,"tijdstip correctie : %s\n",outputResFileName);
    fprintf(output,"Filesize : %s\n",outputResFileName);
    fprintf(output,"Aantal karakters : %s\n",outputResFileName);
    fprintf(output,"Aantal effectieve fouten.\n");
    fprintf(output,"---------------------------\n");
    fprintf(output,"spatiefouten : %d\n",totSpatieFout);
    fprintf(output,"karakter fouten : %d\n",totCharFout);
    fprintf(output,"Aantal aangerekende fouten.\n");
    fprintf(output,"---------------------------\n");
    fprintf(output,"spatiefouten : %d\n",aangSpatieFout);
    fprintf(output,"karakter fouten : %d\n",aangCharFout);
}

/*
Naam functie : compareWord
Auteur : Ti_Uhl
Argumenten : 
    orgineel : het orginele woord
    fout : het foute woord
Doel : 
    Deze functie controleert of 2 woorden juist zijn.
Return value :
    0 : de woorden zijn identiek en juist
    1 : en zijn karakters verkeerd in het woord
    2 : er is een spatie fout. Let er op dat 2 spaties na een . juist zijn
        volgens de criteria van de opgave !! :)
*/
short compareWord(char orgineel[50],char fout[50]) {
    
    int i = 0;
    int retVal =0;
    int loops = 0;
    printf("cmpw : %s : %s\n",orgineel,fout);
    // aantal loops bepalen :)
    if ( strlen(orgineel) > strlen(fout) ) {
        loops = strlen(orgineel);
    } else {
        loops = strlen(fout);
    }
    
    for (i=0;i<loops;i++) {
        if (fout[i] != orgineel[i]) {
            if (fout[i] == spatie && i != 0) {
                if ( fout[i-1] == '.' || fout[i-2] == '.' ) {
                    retVal = 0;
                } else {
                    retVal +=10 ;
                }
            } else {
                retVal += 1;
            }
        }
    }
    return(retVal);
            
}


Hier vind je de bestanden van het programma even allemaal.

Verwijderd

Ti_Uhl schreef op donderdag 17 maart 2005 @ 20:34:
Nu het probleem zit hem volgens mij in het feit dat die array's, die overigens dynamisch worden gemaakt, by value worden doorgegeven ipv by reference want in de functie fillarray worden ze gevult maar ik kan in mijn main geen waarde meer uit die array krijgen. Dit geldt ook voor checkArray en compareWord. Volgens mij word er iedere keer een copie van mijn array's gemaakt ipv mijn orginele te gebruiken die in main zijn aangemaakt.
Jups, dat klopt. In je functie fillArray ga je aan 'array' een nieuwe waarde toekennen, namelijk in de regel "array = ( woord *) realloc(array,(++i +1) * sizeof(woord));" maar array is een pointer die wordt doorgegeven 'by value' zoals men zegt. Wanneer fillArray dus afgelopen is zal je main functie inderdaad de oude waarde blijven zien.

De eenvoudigste oplossing is dan ook om dat niet by value te gaan doorgeven, en fillArray bvb aan te passen als volgt:
C:
1
short fillArray(FILE *file, woord**array);

en dan natuurlijk idem met je implementatie. In je main kun je die dan oproepen als volgt:
C:
1
njuistarray = fillArray(fjuist, &juistarray);


En ja, er wordt hoogst waarschijnlijk ook vaak een kopie gemaakt. Je reserveert in je eerste malloc in je main funcite slechts plaats voor één woord, het eerste element in je array zoals je zelf al in commentaar aangeeft. Een realloc zorgt er dan gewoon voor (of probeert dat althans) om (in jouw geval) extra plaats te voorzien. Maar het hoeft niet zo te zijn dat die extra plaats vlak achter jouw array ligt natuurlijk. Realloc kan een totaal nieuw blok geheugen voorzien dat groot genoeg is, maar zorgt er dan wel voor dat het stuk wat je al had netjes gekopieerd wordt naar de nieuwe blok, zodat het wat betreft de inhoud lijkt alsof je er gewoon achteraan een stuk hebt bijgekregen. Maar dat kopieren kost natuurlijk wel tijd... ;)

Ik heb je code verder niet echt zitten doorspitten, maar een paar kleine opmerkingen ivm dingetjes die ik meteen opmerkte wil ik nog wel kwijt:
- malloc en realloc kunnen falen, dus ik zou het resultaat daarvan toch eens checken, al was het maar met een assert :)
- met code zoals "fscanf(file,"%s",array[i].woord)" zou ik voorzichtig zijn; in jouw geval is het waarschijnlijk wel ok maar het hebt het vlaggen als er in je file een woord staat dat groter is dan 50 karakters natuurlijk, want array[i].woord heeft maar plaats voor 50 karakters en fscanf weet dat niet...

Er zijn nog wel een paar dingetjes waarover ik zou kunnen vitten, maar dat ga ik niet doen. Dat zou niet eerlijk zijn voor een eerste C programma.
Ik wens je dan ook nog veel succes en vooral heel veel programmeerplezier. En ik kan je enkel de raad geven om gewoon te programmeren en te proberen, en af en toe een boek te lezen. De expertise komt dan vanzelf ;)

  • bigbeng
  • Registratie: Augustus 2000
  • Laatst online: 26-11-2021
Weet je zeker dat het adres van array in de functie fillArray() wel hetzelfde blijft na die realloc? Volgens mij en deze website niet:
http://www.elook.org/programming/c/realloc.html

edit:

spuit -11 :)

[ Voor 9% gewijzigd door bigbeng op 17-03-2005 21:14 ]


  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
1 ding wat sowiezo fout gaat is de realloc hierzo:
C:
1
2
3
4
5
6
7
8
9
10
    // voor een of andere reden moet ik die while zo schrijven anders probeert
    // nog verder te lezen dan de tekst lang is :)  
    while ( ( (fscanf(file,"%s",array[i].woord)) != 0 ) && !feof(file) ) {
        
        //fscanf(file,"%s",array[i].woord);
        printf("%s\n",array[i].woord);
        array = ( woord *) realloc(array,(++i +1) * sizeof(woord)); 
        n++;
    }
    return(n);

'array' is gedeclareerd als een pointer naar 'woord'en, en die kun je idd gebruiken als een array van ongespecificeerde lengte, mits je genoeg geheugen alloceert daarvoor. Dat doe je volgens mij ook door middel van de realloc(), maar hier zit 'm het probleem:

Door het realloceren van geheugen kan het zijn dat je nieuwe, vergrootte blok geheugen ergens anders in het geheugen komt te staan. Met andere woorden, het adres waarnaar 'array' verwijst kan veranderen binnen deze functie. Nu zul je daar binnen deze functie niks van merken omdat je de waarde van array updated na elke realloc().

Maar op het moment dat fillArray() klaar is, en de functie terugkeert naar de aanroeper (main() in dit geval), weet deze aanroeper niks van dat 'array' tegenwoordig ergens anders in het geheugen staat! De aanroeper werkt dus met het verkeerde geheugenblok.

Een quick-and-dirty oplossing hiervoor is om niet "een pointer naar het begin van de array van woorden" mee te geven (zoals je nu doet: woord *array), maar "een pointer naar een pointer naar het begin van de array van woorden" (woord **array).
Je aanroep vanuit main wordt dan "njuistarray = fillArray(fjuist, &juistarray);", en elementen uit je array worden dan niet langer als "array[i]" aangesproken, maar (*array)[i].
Zodoende kun je na elke realloc de waarde van array bijwerken door *array = realloc(...) te doen, zodat na terugkeer uit fillArray() main werkt met de juiste array.

--edit--
Klere, ik moet sneller leren typen. Nu staan er 3 mensen hetzelfde te vertellen... 8)7

[ Voor 7% gewijzigd door MrBucket op 17-03-2005 21:16 ]


Verwijderd

bigbeng schreef op donderdag 17 maart 2005 @ 21:13:
Weet je zeker dat het adres van array in de functie fillArray() wel hetzelfde blijft na die realloc? Volgens mij en deze website niet:
http://www.elook.org/programming/c/realloc.html
Klopt, array kan veranderen in die functie. Ik weet het wel zeker :)
Maar op zich is dat niet zo erg, afgezien van het feit dat realloc dan wat gaat zitten kopieren en dat dus wat tijd kost. Het grote probleem hier is dat de veranderde waarde niet zichtbaar wordt voor z'n main functie na afloop van die fillArray functie :)

[edit]
Ik vermoed dat de topicstarter ondertussen wel te horen heeft gekregen wat er fout is :P :+

[ Voor 9% gewijzigd door Verwijderd op 17-03-2005 21:17 ]


  • bigbeng
  • Registratie: Augustus 2000
  • Laatst online: 26-11-2021
Verwijderd schreef op donderdag 17 maart 2005 @ 21:16:
[...]

Klopt, array kan veranderen in die functie. Ik weet het wel zeker :)
Maar op zich is dat niet zo erg, afgezien van het feit dat realloc dan wat gaat zitten kopieren en dat dus wat tijd kost. Het grote probleem hier is dat de veranderde waarde niet zichtbaar wordt voor z'n main functie na afloop van die fillArray functie :)
Dat bedoelde ik ook hoor :) Mijn C is wat roestig, maar pointers heb ik door :D
Nu de topicstarter nog ;)

Verwijderd

Hehe. Komt wel goed denk ik :)
Ik moet de eerste programmeur die echt meteen pointers goed doorhad nog altijd tegenkomen denk ik :P
/me herinnert zich nog vaag zijn eerste C brouwsels vele jaren geleden... *rillingen krijgt*

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 10-05 12:29

Creepy

Tactical Espionage Splatterer

bigbeng schreef op donderdag 17 maart 2005 @ 21:18:
[...]

Dat bedoelde ik ook hoor :) Mijn C is wat roestig, maar pointers heb ik door :D
Nu de topicstarter nog ;)
En naast dat mag de topicstartenz'n post aanpassen met alleen de relevante code. De code die er nu staat is echt veel te veel. Dat gaat (bijna) niemand voor je debuggen.

Lees aub P&W FAQ - De "quickstart" eens door en post alleen het stuk relevante code. Probeer zo'n klein mogelijk test geval te maken dat je probleem demonstreert zodat het een stuk makkelijker is voor ons om je te helpen.

[ Voor 3% gewijzigd door Creepy op 17-03-2005 21:24 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • Ti_Uhl
  • Registratie: Mei 2003
  • Laatst online: 19-09-2012
aan iedereen :
Thx ik denk dat ik nu weet wat me te wachten staat :) gewoon een pointer naar een pointer naar woord erin te steken :)
Ik kan het op dit moment niet meer testen maar zodra ik het heb gedaan post ik het effect ervan hier wel even :)

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Ts, ik denk dat je nu inmiddels zelf ook wel hebt gemerkt dat het werken met pointers om lijsten van woorden te bewerken snel erg onoverzichtelijk wordt, zeker als je nog een beetje moeite hebt met pointers.

Als je in c++ had geprogrammeerd had ik je geadviseerd om een std::vector te gebruiken in plaats van een platte array (een vector is een array die automatisch groeit als je er elementen aan toevoegt). In ansi c bestaat deze niet, maar je kunt wel iets soortgelijks in elkaar knutselen. Het grootste voordeel is dat je het geklooi met geheugen heralloceren en niet-geupdate pointers scheidt van de rest van je code.

Om een voorzetje te geven:
C:
1
2
3
4
5
6
7
8
9
10
11
struct woordenlijst{
  woord *pData;  //Pointer naar je dynamisch gealloceerde array
  int iWoorden; //Grootte van je array, in woorden
};

//Voegt het gegeven woord toe aan de gegeven woordenlijst
void woordenlijst_voegtoe(woordenlijst *pLijst, woord w){
  (*pLijst).pData = realloc(...);
  (*pLijst).pData[(*pLijst).iWoorden] = w;
  (*pLijst).iWoorden++;
}


In de rest van je code kan je dan werken met het type "woordenlijst", en de functie woordenlijst_voegtoe(), waardoor je al een heel stuk van je pointer-naar-pointer-naar...-ellende kwijt bent.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 10-05 10:05
Misschien is het ook een idee om niet iedere keer een extra positie te reserveren maar zoiets als std::vector doet, met een factor 1.nogwat vergroten.
Scheelt je een hoop reallocs, ten koste van wat meer administratie.

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.


  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
farlane schreef op donderdag 17 maart 2005 @ 22:43:
Misschien is het ook een idee om niet iedere keer een extra positie te reserveren maar zoiets als std::vector doet, met een factor 1.nogwat vergroten.
Scheelt je een hoop reallocs, ten koste van wat meer administratie.
Tuurlijk, dat was ook mijn eerste idee, maar wel met het gevaar dat TS het idee krijgt dat hij zich nog meer ellende op de hals haalt in plaats van dat het de zaken vereenvoudigd. Dus dat heb ik bij nader inzien maar weggelaten :)

  • Ti_Uhl
  • Registratie: Mei 2003
  • Laatst online: 19-09-2012
Heb mijn programma aangepast en alles werkt nu zoals het moet. Ik denk echter wel dat ik mijn programmatje een beetje ga aanpassen want vind het allemaal niet zo proper meer en een beetje onduidelijk :)
Thx iig
Pagina: 1