Pointer..
-
Hallo,
nach fast einem Jahr arbeite ich fürs Studium wieder an einem C-Projekt.
Und wieder merke ich das ich Pointer noch nicht ganz verinnerlicht habe.int * insertw_1_svc(char **argp, struct svc_req *rqstp) { static int result; //printf("%s\n", *argp); int i; for (i=0; i<nwords; i++) if (strcmp (*argp, dict[i]) == 0) return 0; strcpy (dict[nwords], *argp); nwords++; result = nwords; return &result; }
Ich habe den Parameter char **argp und kann den Wert von ihm mit printf("%s\n", *argp); ausgeben. Funktioniert wunderbar. Nur leider nicht das was ich brauche.
Wie man sieht soll dieser Wert in ein paar Funktionen als Paramenter übergeben werden. Daran hapert es.
- Frage: Wie muss ich in meinem Fall das eintippen, damit es funktioniert?
- Frage: Hat jemand einen Workaround wie man mit Pointer umgehen muss? Speziell dann **argp (also Pointer auf Pointer) und im Zusammenhang mit Funktionen (als Parameter und Rückgabewert) auf einen zukommt. Am Besten alles wie man sich Pointer gut vorstellen/verinnerlichen kann.
mfg werdas34
-
Nur leider nicht das was ich brauche.
Ja, was brauchst du denn stattdessen?
-
Das z.B. strcmp (*argp, dict[i]) keinen Speicherzugriffsfehler wirft und den Wert auf den **argp zeigt als Parameter hinzufügt.
-
- globale Variable nwords -> Schrott
- globale Variable dict -> Schrott
static
int result -> Schrott
du zählst argp gar nicht weiter, was soll dann die Übergabe als ** Parameter?
Dass strcmp abstürzt liegt am undefinierten Speicher von argp oder dict oder beiden.
Da du den Aufrufkontext verheimlichst, kann dir keiner helfen - was soll die Funktion überhaupt machen?
-
@Wutz
Schrott int * als Rückgabwert
-
@pmqtt
Depp. Du hast nicht verstanden was ich damit zum Thema "Missdesign" sagen will.
-
globale Variable nwords -> Schrott
globale Variable dict -> Schrott
static int result -> Schrottdu zählst argp gar nicht weiter, was soll dann die Übergabe als ** Parameter?
Dass strcmp abstürzt liegt am undefinierten Speicher von argp oder dict oder beiden.
Da du den Aufrufkontext verheimlichst, kann dir keiner helfen - was soll die Funktion überhaupt machen?Die ersten beiden Stichpunkte sind in der Vorlage vom Prof vorgegeben. Der letzte Stichpunkt wurde automatisiert von einem rpcgen Generator generiert.
argp ist zumindest nicht leer, da der auskommentierte printf funktioniert.
Die Funktion soll einen String in die DB schreiben. sofern er noch nicht enthalten ist.Erst mal zur Aufgabe. Vielleicht erklärt es auch warum manche Dinge so sind wie sie sind.
Das Thema ist RPC also Remote Zugriff auf verteilte Prodezuren.Es geht um eine Datenbank für Strings.
Clientseitig kann man die DB initialiseren, Srings einfügen, löschen updaten etc. Serverseitig wird das alles gespeichert. Es wird nirgendwo zwischengespeichert, d.h bei Neustart muss man alles neu eintippen. (Ist auch nur eine Übungsaufgabe im Studium, also man machts einmal und dass wars)Ich poste hiermal die gesamte Datei die mit rcpgen die neuen
Dateien generiert. MIt diesem Befehl werden ie erzeugt.rpcgen -a -C rdbase.x
/* rdbase.x */ /* RPC declarations for database program */ const DBASESIZE= 100; const MAXWORD = 50; const MAXRESULT = 10; const MAXSUCHERG = 100; struct upd { string upd_old <MAXWORD>; string upd_new <MAXWORD>; }; struct oneword { string word <MAXWORD>; }; struct manywords { oneword words <DBASESIZE>; }; struct twoargs { string firstarg <MAXWORD>; string secondarg <MAXWORD>; }; program RDBASEPROG{ version RDBASEVERS { int INITW (void) = 1; int INSERTW (string) = 2; int DELETEW (string) = 3; int LOOKUPW (string) = 4; int UPDATEW (upd) = 5; int COUNTW (void) = 6; string SELECTW (void) = 7; manywords SELECTBETWEENW (twoargs) = 8; } = 1; } = 0x30090949;
Mein derzeitiger Server(ohne die noch nicht generierten Funktionen die nicht implementiert ist):
#include <stdio.h> #include "rdbase.h" char dict[DBASESIZE] [MAXWORD+1]; int nwords = 0; int * initw_1_svc(void *argp, struct svc_req *rqstp) { static int result; nwords = 0; result = 1; printf("Client called initw\n"); return &result; } int * insertw_1_svc(char **argp, struct svc_req *rqstp) { static int result; //printf("%s\n", *argp); int i; for (i=0; i<nwords; i++) if (strcmp (*argp, dict[i]) == 0) return 0; strcpy (dict[nwords], *argp); nwords++; result = nwords; for(int k = 0; i<nwords; k++){ for(int l = 0; i<MAXWORD; l++){ printf("%s\n", dict[k][l]); } } return &result; }
Derzeitiger Client (Funktionsaufruf in Zeile 36):
#include <stdio.h> #include "rdbase.h" #define MAXLINE 80 int nextin (char*, char*, char*); void rdbaseprog_1(char *host, char cmd, char *word1, char *word2) { CLIENT *clnt; int *result_1; char *initw_1_arg; int *result_2; char * insertw_1_arg; clnt = clnt_create (host, RDBASEPROG, RDBASEVERS, "udp"); if (clnt == NULL) { clnt_pcreateerror (host); exit (1); } switch (cmd) { case 'I': result_1 = initw_1((void*)&initw_1_arg, clnt); if (result_1 == (int *) NULL) { clnt_perror (clnt, "call failed"); }else{ printf ("Database initialized to empty.\n"); } clnt_destroy (clnt); break; case 'i': insertw_1_arg = word1; result_2 = insertw_1(&insertw_1_arg, clnt); if (result_2 == (int *) NULL) { clnt_perror (clnt, "call failed"); }else if(result_2 > 0){ printf ("Word inserted.\n"); }else{ printf ("Word could not be inserted.\n"); } clnt_destroy (clnt); break; } } int main (int argc, char *argv[]) { char *host; char word1 [MAXWORD + 1]; char word2 [MAXWORD + 1]; char cmd; int wrdlen; while(1){ printf("\nEnter your wishes\n"); wrdlen = nextin (&cmd, word1, word2); host = "localhost"; rdbaseprog_1 (host, cmd, word1, word2); } exit (0); } int nextin (cmd, word1, word2) char *cmd, *word1, *word2; { char command[MAXLINE]; char tmp[10]; //gets (command); // liest bis newline, also u.U. mehrere durch Leerzeichen getrennte Strings //fgets liest bis newline oder bis MAXLINE Bytes, also u.U. mehrere durch Leerzeichen getrennte Strings fgets (command, MAXLINE, stdin); sscanf (command, "%s %s %s", tmp, word1, word2); // liest aus commannd in tmp, word, word2 hinein *cmd = tmp[0]; return 0; }
-
@werdas_34 sagte in Pointer..:
insertw_1_arg
Zwar ist das alles ein wenig Konfus. Aber mal eine Frage kannst du ca. 100 Werte eintragen und dann knallt es?
Kann die Zeile 28 in der Function insertw_1_svc(char **argp, struct svc_req *rqstp) nicht auch das Problem sein. Du kopierst dort ohne genau zu wissen ob argp tatsächlich in dict passt.Anmerkungen mal nebenbei. Der pointer pointer macht keinen Sinn. Auch der Rückgabewert als int * macht wenig Sinn.
-
Zwar ist das alles ein wenig Konfus. Aber mal eine Frage kannst du ca. 100 Werte eintragen und dann knallt es?
Kann die Zeile 28 in der Function insertw_1_svc(char **argp, struct svc_req *rqstp) nicht auch das Problem sein. Du kopierst dort ohne genau zu wissen ob argp tatsächlich in dict passt.Ich initialisere die DB. Das funktioniert einwandfrei.
Dann möchte ich einen String inserten. Der String wird sofern nicht auskommentiert, richtig auf der serverseite ausgegeben.
Dann kommt der Fehler. Speicherzugriffsfehler. Und bisjetzt habe ich es nur mit drei Buchstaben wie "ash" getestet. Also zu lang kann es nicht sein.Anmerkungen mal nebenbei. Der pointer pointer macht keinen Sinn. Auch der Rückgabewert als int * macht wenig Sinn.
Dazu kann ich wenig sagen, weil es eben so generiert wird. Nur das eben in der Spezifkation festgelegt wurde das der Rückgabewert ein Integer sein soll.
Hier mal ein Blogbeitrag, an dem ich mich auch bisschen orientiere. http://tharikasblogs.blogspot.com/p/how-to-write-simple-rpc-programme.html
-
int nextin (cmd, word1, word2) char *cmd, *word1, *word2;
K&R C? Was soll das?
*cmd = tmp[0];
Was macht das?
-
War ein Codeschnipsel vom Prof.
Wenn man in der Konsole eingibt: "i test"
Dann wird i in cmd gespeichert für den switch case um die richtige Funktion auszuwählen. test wird in word1 geschrieben, damit man weiß welches Wort inserted werden soll. Und word2 würde dann gefüllt werden, wenn ein drittes Wort in der Konsole eingeben wird. Also z.B. "i test hallo", dann hallo in word2.
-
@werdas_34 sagte in Pointer..:
Nur das eben in der Spezifkation festgelegt wurde das der Rückgabewert ein Integer sein soll.
Und warum gibst du dann einen Zeiger zurück?
-
Und warum gibst du dann einen Zeiger zurück?
Nicht ich, es wurde so generiert. Gut wenn es an dem liegt, dann lösche ich den Pointer.
-
Dann wird i in cmd gespeichert für den switch case
Dann sollte tmp auch nur ein char sein.
War ein Codeschnipsel vom Prof.
YAIT (yet another incompetent teacher)
-
@manni66 sagte in Pointer..:
Dann sollte tmp auch nur ein char sein.
Habe nun in der Funktion alles auf char angepasst.
Genauso habe ich mal den Pointer vom int Rückgabewert gelöscht. Habe immer noch den Rückgabefehler.
Edit:
Gibts hier eigentlich die Möglichkeit die Dateien hochzuladen?
Denn es sind mehrere Dateien, die generiert werden, die man aber nicht bearbeiten soll.
Vielleicht wird es dann dadurch klarer? Oder jemand möchte bisschen herum testen?
-
@werdas_34 sagte in Pointer..:
Nicht ich, es wurde so generiert.
Wow. Da wird was generiert. Das erklärt auch den unsinnigen Code.
Und du erwartest jetzt, dass wir rätseln, was der Generator generiert?!Wie testet man nochmal RPC in einem Programm?
-
Wow. Da wird was generiert. Das erklärt auch den unsinnigen Code.
Und du erwartest jetzt, dass wir rätseln, was der Generator generiert?!Naja, den Thread habe ich mit dem Inhalt geöffnet, wie man sich Pointer am Besten verinnerlichen kann.
Dann kam von dir "ohne Kontext keine sinnvolle Hilfe", was ich verstehen kann.
Dann poste ich den Code und erklär was Sache ist. Jede weitere Antwort fand irgendwas schlect am generierten Code.Wenn jemand mir sagen kann wie ich im ersten Beitrag die Funktion zum laufen kriege ohne einen Speicherzugriffsfehler zu erhalten. Und da ich mit Ponter immer noch nicht ganz warm bin, dachte ich frage Experten.
Edit:
Ich habe mal ein Beispiel gemacht um das alles etwas zu verstehen (auch mit erzeugten Code). Und das funktioniert tatdellos. Auch die erste Funktion(initw) in meinem Skript funktioniert tadellos. Also am Generator liegts nicht. Er kann ineffizient sein, aber das ist mir ziemlich egal, da ich die Aufgabe löse(hoffen wirs mal), dem Prof die schicke und dann in nem halben Jahr ohne weitere Nutzung lösche. Also der Code vom Generator funktioniert.
-
@werdas_34 sagte in Pointer..:
Und das funktioniert tatdellos.
Das kannst du als Anfänger nicht beurteilen - glaube mir, den Satz habe ich hier schon hundertmal gesagt, und er ist unbestritten, denn nur weil du keinen Fehler erhältst und das Programm mit deinen Spieldaten die von dir erwarteten Ergebnisse bringt, ist das Programm noch lange nicht korrekt.
Deinen Fehler kann man nicht nachvollziehen, solange man den Aufrufkontext deine dynamischen Funktionsargumente nicht kennt, dazu gibt es u.a. Debugger.
Du greifst auf undefinierten Speicher zu, also entweder ist dein definierter (unsinnig als globales Array definiert) Speicher zu klein oder dein Index zu groß.
-
Ich starte Server und Client.
Client fragt mich nach einer Eingabe:
I
Client gibt aus Database initialized to empty.
Serverseitig wird ausgegeben: Client called initw
Ich gebe beim Client ein: i ash
Server gibt ash aus wenn printf auskommentiert ist und dann Speicherzugriffsfehler.Es kann icht daran liegen das das Wort zu groß ist oder ähnliches.
Hier mal die rdbase.h, wo weitere Sachen definiert sind:
#ifndef _RDBASE_H_RPCGEN #define _RDBASE_H_RPCGEN #include <rpc/rpc.h> #ifdef __cplusplus extern "C" { #endif #define DBASESIZE 100 #define MAXWORD 50 #define MAXRESULT 10 #define MAXSUCHERG 100 struct upd { char *upd_old; char *upd_new; }; typedef struct upd upd; struct oneword { char *word; }; typedef struct oneword oneword; struct manywords { struct { u_int words_len; oneword *words_val; } words; }; typedef struct manywords manywords; struct twoargs { char *firstarg; char *secondarg; }; typedef struct twoargs twoargs; #define RDBASEPROG 0x30090949 #define RDBASEVERS 1 #if defined(__STDC__) || defined(__cplusplus) #define INITW 1 extern int * initw_1(void *, CLIENT *); extern int * initw_1_svc(void *, struct svc_req *); #define INSERTW 2 extern int * insertw_1(char **, CLIENT *); extern int * insertw_1_svc(char **, struct svc_req *); #define DELETEW 3 extern int * deletew_1(char **, CLIENT *); extern int * deletew_1_svc(char **, struct svc_req *); #define LOOKUPW 4 extern int * lookupw_1(char **, CLIENT *); extern int * lookupw_1_svc(char **, struct svc_req *); #define UPDATEW 5 extern int * updatew_1(upd *, CLIENT *); extern int * updatew_1_svc(upd *, struct svc_req *); #define COUNTW 6 extern int * countw_1(void *, CLIENT *); extern int * countw_1_svc(void *, struct svc_req *); #define SELECTW 7 extern char ** selectw_1(void *, CLIENT *); extern char ** selectw_1_svc(void *, struct svc_req *); #define SELECTBETWEENW 8 extern manywords * selectbetweenw_1(twoargs *, CLIENT *); extern manywords * selectbetweenw_1_svc(twoargs *, struct svc_req *); extern int rdbaseprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); #else /* K&R C */ #define INITW 1 extern int * initw_1(); extern int * initw_1_svc(); #define INSERTW 2 extern int * insertw_1(); extern int * insertw_1_svc(); #define DELETEW 3 extern int * deletew_1(); extern int * deletew_1_svc(); #define LOOKUPW 4 extern int * lookupw_1(); extern int * lookupw_1_svc(); #define UPDATEW 5 extern int * updatew_1(); extern int * updatew_1_svc(); #define COUNTW 6 extern int * countw_1(); extern int * countw_1_svc(); #define SELECTW 7 extern char ** selectw_1(); extern char ** selectw_1_svc(); #define SELECTBETWEENW 8 extern manywords * selectbetweenw_1(); extern manywords * selectbetweenw_1_svc(); extern int rdbaseprog_1_freeresult (); #endif /* K&R C */ /* the xdr functions */ #if defined(__STDC__) || defined(__cplusplus) extern bool_t xdr_upd (XDR *, upd*); extern bool_t xdr_oneword (XDR *, oneword*); extern bool_t xdr_manywords (XDR *, manywords*); extern bool_t xdr_twoargs (XDR *, twoargs*); #else /* K&R C */ extern bool_t xdr_upd (); extern bool_t xdr_oneword (); extern bool_t xdr_manywords (); extern bool_t xdr_twoargs (); #endif /* K&R C */ #ifdef __cplusplus } #endif #endif /* !_RDBASE_H_RPCGEN */
dict wird mit [100] [51] initialisiert.
In der Funktion wird dict[0] mit argp überschrieben, da nwords anfangs 0 ist. Da durch den printf bekannt ist das argp den richtigen Wert hat und dict[0] ist ja definiert.Ich sehe jetzt nicht wo der Speicher zu klein bzw der Index zu groß sind. Kannst du das erläutern?
-
Deine Ausgabe ist fehlerhaft:
for(int k = 0; i<nwords; k++){ for(int l = 0; i<MAXWORD; l++){ printf("%s\n", dict[k][l]); } }
Du gibst einzelne Zeichen als String aus (denn
dict
ist wohl alschar
-Array deklariert und nicht alschar*
-Array, denn sonst würde der Code darüber [strcmp, strcpy
] keinen Sinn machen).
Ändere es also zufor(int k = 0; i<nwords; k++){ printf("%s\n", dict[k]); }