Toon posts:

[C] probleem met functie en pointer

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb een probleem met een stukje C code. Ik ben niet zo heel erg goed met C, al lijkt me niet zo'n moeilijk probleem.

De code is alsvolgt:
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
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

char *get_setting(char *setting) {
        FILE *fp;
        char line[255];
        char command[255];

        sprintf (command, "settings -g %s", setting);
        fp = popen(command, "r");

        fgets (line, sizeof line, fp);

        if (line[strlen(line) - 1] == "\n")
                line[strlen(line) -1] = "\0";

        return line;
}

int main (int argc, char *argv[]) {
        char *username, *password;

        username = get_setting("username");
        password = get_setting("password");

        printf ("u = %s , p = %s \n", username, password);

        return 0;
}

het programma 'settings' is een apparte applicatie. Bovenstaande applicatie moet twee keer dat programma 'settings' uitvoeren. Door 'settings -g username' uit te voeren, krijg je als result een opgeslagen username terug.

Maar het werkt dus niet. De output is twee keer de waarde van password in plaats van de waarde van username en password. Gcc geeft als compilatie waarschuwing:
code:
1
2
3
4
test.c: In function &#8216;get_setting&#8217;:
test.c:17: warning: comparison between pointer and integer
test.c:18: warning: assignment makes integer from pointer without a cast
test.c:20: warning: function returns address of local variable

Het lijkt me dat het komt omdat die functie een pointer returned. Maar hoe los ik dit dan op dat het wel werkt? En wat is de precieze oorzaak?

[ Voor 0% gewijzigd door moto-moi op 28-09-2006 13:05 ]


  • DroogKloot
  • Registratie: Februari 2001
  • Niet online

DroogKloot

depenisvanjezus

Ten eerste is 'line' een array dat op de stack wordt gealloceerd waardoor na de return van get_setting() het ding niet meer bestaat en de pointer ongeldig is, ten tweede vergelijk je op regel 16 een karakter uit line met een string ("\n" moet '\n' zijn).

[ Voor 6% gewijzigd door DroogKloot op 28-09-2006 13:06 ]


Verwijderd

Topicstarter
DroogKloot schreef op donderdag 28 september 2006 @ 13:04:
Ten eerste is 'line' een array dat op de stack wordt gealloceerd waardoor na de return van get_setting() het ding niet meer bestaat en de pointer ongeldig is, ten tweede vergelijk je op regel 16 een karakter uit line met een string ("\n" moet '\n' zijn).
Als ik "\n" vervang met '\n' dan werkt die if statement inderdaad en zijn er weer twee warnings weg. Maar hoe zorg ik ervoor dat die line bewaard blijft?

  • zeroxcool
  • Registratie: Januari 2001
  • Laatst online: 11:55
Verwijderd schreef op donderdag 28 september 2006 @ 13:08:
[...]

Als ik "\n" vervang met '\n' dan werkt die if statement inderdaad en zijn er weer twee warnings weg. Maar hoe zorg ik ervoor dat die line bewaard blijft?
Door line dynamisch te alloceren (met malloc()). Dan blijft dat stuk geheugen niet op de stack staan maar op 'extern' geheugen. Zoals de error van GCC duidelijk aangeeft:
code:
1
test.c:20: warning: function returns address of local variable

Return je dus een adres van een lokale variabele.

zeroxcool.net - curity.eu


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13-02 18:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

mallocen is idd een optie, betekent wel dat de ontvanger van de returnvalues de buffer wel weer moet vrijgeven met een free(). Een andere optie is om de gebruiker van de functie zelf een buffer mee te laten geven zodat je die kunt vullen met de informatie. Niet vergeten ook een lengte mee te laten geven om buffer overruns te voorkomen.

Of je gebruikt gewoon C++ en returnt een std::string. Makkelijker, veiliger.

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.


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 13-02 18:14

MBV

vergeet alleen niet om het buffer ook weer vrij te geven :)

edit:
wat .iosyn zegt dus

[ Voor 21% gewijzigd door MBV op 28-09-2006 13:29 ]


  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

en als je om een of andere rede geen c++ kan gebruiken kun je het ook zo oplossen:
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
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void get_setting(char *setting, char **line) {
        FILE *fp;
        char command[255];

        sprintf (command, "settings -g %s", setting);
        fp = popen(command, "r");

        fgets(*line, sizeof *line, fp);

        if (line[strlen(line) - 1] == "\n")
                line[strlen(line) -1] = "\0";
}

int main (int argc, char *argv[]) {
        char *username[255];
        char *password[255];

        get_setting("username", username);
        get_setting("password", password);

        printf ("u = %s , p = %s \n", username, password);

        return 0;
}

(niet getest)

oprecht vertrouwen wordt nooit geschaad


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 13-02 18:14

MBV

char *line als parameter zou ook moeten werken: een c-string is altijd een pointer naar zijn eerste element :). Verder heb je een probleem zodra char *username langer wordt dan command, en zou het me verbazen als char "*username[255]" gaat werken (zou toch "char username[255]" moeten zijn?).

* MBV moet minder vaak PHP proggen :P

  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

MBV schreef op donderdag 28 september 2006 @ 14:36:
char *line als parameter zou ook moeten werken: een c-string is altijd een pointer naar zijn eerste element :). Verder heb je een probleem zodra char *username langer wordt dan command, en zou het me verbazen als char "*username[255]" gaat werken (zou toch "char username[255]" moeten zijn?).

* MBV moet minder vaak PHP proggen :P
je hebt gelijk dat char* ook zou mogen, is misschien nog wel beter omdat je dan ook de pointer naar de c-string niet hoeft te deleten :)
wordt het zoiets:

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
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void get_setting(char *setting, char *line) {
        FILE *fp;
        char command[255];

        sprintf (command, "settings -g %s", setting);
        fp = popen(command, "r");

        fgets(line, sizeof line, fp);

        if (line[strlen(line) - 1] == "\n")
                line[strlen(line) -1] = "\0";
}

int main (int argc, char *argv[]) {
        char username[255];
        char password[255];

        get_setting("username", username);
        get_setting("password", password);

        printf ("u = %s , p = %s \n", username, password);

        return 0;
}

oprecht vertrouwen wordt nooit geschaad


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13-02 18:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je code klopt voor geen meter, je definieert 2 arrays van 255 pointers naar char, die niet geinitialiseerd zijn. get_setting gaat vervolgens checken of deze entries naar dezelfde string pointen als "\n" (zal nooit gebeuren), en zo ja dan assignt ie de string "\0" aan die entries.

Het zou wel kloppen als je de compile-error van de topicstarter wegwerkt, en username en password gewoon char[255] te laten zijn, en die line parameter van get_line een char* maakt.

.edit: zo ja, nou nog die compile error fix. Een lengte meegeven zou ook netter zijn, zoals ik eerder al zei :)

[ Voor 11% gewijzigd door .oisyn op 28-09-2006 14:46 ]

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.


  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

MBV schreef op donderdag 28 september 2006 @ 14:36:
char *line als parameter zou ook moeten werken: een c-string is altijd een pointer naar zijn eerste element :). Verder heb je een probleem zodra char *username langer wordt dan command, en zou het me verbazen als char "*username[255]" gaat werken (zou toch "char username[255]" moeten zijn?).

* MBV moet minder vaak PHP proggen :P
char *username[255] mag op zich wel maar dan heb je wel een array van pointers naar char, wat dus niet is wat je wilt in dit geval.

All my posts are provided as-is. They come with NO WARRANTY at all.

Pagina: 1