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.

    1. Frage: Wie muss ich in meinem Fall das eintippen, damit es funktioniert?
    2. 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.



  • @Wutz sagte in Pointer..:

    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?

    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.



  • @pmqtt sagte in Pointer..:

    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.

    @pmqtt sagte in Pointer..:

    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



  • @werdas_34

    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?



  • @Th69 sagte in Pointer..:

    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.



  • @werdas_34

    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?



  • @Wutz sagte in Pointer..:

    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 dictist wohl als char-Array deklariert und nicht als char*-Array, denn sonst würde der Code darüber [strcmp, strcpy] keinen Sinn machen).
    Ändere es also zu

    for(int k = 0; i<nwords; k++){
    	printf("%s\n", dict[k]);
    }
    

Log in to reply