Rückgabewert



  • Hallo,

    ich habe zwei Fragen(beide Fragen beziehen sich auf die Aufgabe von diesen Beitrag:
    Kurz nochmal zur Aufgabe: Soll ein RPC Programm sein, welches eine einfache Datenbank simuliert.

    Nun habe ich die Aufgabe als Client zwei Argumente als String entgegenzunehmen. Diese Argumente sollen enen Art Filter darstellen und die Funktion soll die Werte zurückliefern die zwischen den beiden Argumenten liegen:
    z.B. arg1 = abc, arg2 = test-> Zurückliefern: hallo, abcd, josef, -> Nicht Zurückgelierfert: zzz, wolfgang, aaa,
    Exakte Aufgabenstellung: "Ausgabe der Menge aller in der Datenbank enthaltenen Wörter, die alphabetisch zwi-
    schen zwei einzugebenden Worten liegen. Geben Sie die Wörter in einer geeigneten Datenstruktur zurück, die alle gefundenen Wörter enthält. Dieses Select ist dann die
    Vorstufe zu einem Select, in dem die Tupel einer Tabelle einer relationalen Datenbank zurückgegeben werden können."

    Ansich keine schwere Aufgabe mit strcmp.
    Nur der vorgegebene Rückgabewert irrtiert mich. Meine Intuition war es eine verkette Liste zu basteln.
    Aber vielleicht könnt ihr mir da helfen:
    Der Rückgabewert ist manywords und er ist so aufgebaut:

    struct oneword {
    	char *word;
    };
    typedef struct oneword oneword;
    
    struct manywords {
    	struct {
    		u_int words_len;
    		oneword *words_val;
    	} words;
    };
    typedef struct manywords manywords;
    

    Ich werde nicht schlau, inwiefern words_len mir was helfen soll. Und ich kann höchstens (aus meiner Sicht) einen konkatinierten String zurückliefern?


    Eine andere Funktion soll den gesamten Inhalt der DB als konkatinierten String zurückliefern. Soweit kein Problem nur irgendwie kann ich den String nicht sinnvoll zurücksenden.

    char **
    selectw_1_svc(void *argp, struct svc_req *rqstp)
    {
    	static char * result;
    	char buf[80];
    	buf[0] = '\0';
    
    	printf("Called selectw.\n");
    
    	for(int i = 0; i < nwords; i++){
    		strcat(buf, dict[i]);
    		strcat (buf," ");
    	}
    	printf("%s\n", buf);  //gewünschte Ausgabe
    	//strcpy(result, buf);
    	//result = "test";  
    	return &result;
    }
    

    result = "test", dann liefert die Funktion test zurück. Wenn ich versuche buf zurückzuliefern, dann kommt Speicherzugriffsfehler. Ich verstehs halt nicht. Was ist jetzt der große Unterschied zwischen dem char Array buf und dem String "test" ???
    Wäre super wenn da jemand für Aufklärung sorgt.

    mfg werdas34



  • manywords result;
    result.words.worlds_len = 42;
    result.words.words_val = malloc(42 * sizeof oneword);
    for (size_t i = 0; i < 42; ++i) {
        result.words.words_val[i].word = malloc(wielangeauchimmerderstringist + 1);
        strcpy(result.words.words_val[i].word, woauchimmerderstringherkommt);
    }
    


  • Danke für deine Antwort.
    Ist ja vereinfacht gesagt auch nur ein katonierter String, jedelich das jeder String maximal lang ist, oder?



  • Nein!
    In Swordfishs Beispiel ist words_val ein Zeiger auf einen Bereich von 42 onewords.
    Das einzige, was an einem Stück im Speicher liegt, sind also diese onewords - die aber wiederum jeweils nur aus einem Zeiger auf char bestehen.
    Für jeden dieser 42 Zeiger wird eigener Speicher angefordert (Zeile 5), und zwar genau so viel, wie benötigt wird, um einen String der Länge wielangeauchimmerderstringist darin unterzubringen.
    In der nächsten Zeile wird dieser String dann dorthin kopiert.
    Die 42 Strings liegen am Ende verstreut im Speicher herum, lediglich die Zeiger darauf hängen zusammen.
    In words_len steht halt, wieviele es sind.



  • @werdas_34: Zur Erklärung von "Zeiger-Arrays" habe ich dir mal diesen Link rausgesucht (mit Bildchen): Zeiger (Pointer) (s. "6.5 Zeiger-Array").



  • @Belli und @Th69

    Danke für die Erklärungen.

    Zu meiner zweiten Rückgabewertfrage keine Anregungen?



  • Wenn nur ein String zurückgegeben werden soll, warum hat die Funktion denn dann einen Doppelzeiger als Rückgabewert?

    Außerdem macht ein statisches Array dort keinen Sinn, am besten wäre dort dann Speicher per malloc (bzw. je nach Implementierung realloc) zu besorgen (dann müßte aber eine andere Funktion diesen Speicher wieder per free freigeben).



  • @werdas_34 sagte in Rückgabewert:

    Wenn ich versuche buf zurückzuliefern, dann kommt Speicherzugriffsfehler. Ich verstehs halt nicht. Was ist jetzt der große Unterschied zwischen dem char Array buf und dem String "test" ???

    buf ist eine lokale Variable auf dem Stack, und der Stack wird beim Verlassen der Funktion wieder aufgeräumt, d.h. Zugriff auf buf außerhalb der Funktion ist UB. Du solltest Dir dringend den Unterschied zwischen static storage, Heap und Stack erarbeiten. Schon in der andere Frage hast Du solange herumgewürgt bis, der Compiler es irgend wie gefressen hat. Ein brauchbares Programm kam dabei nicht heraus.

    Eine mögliche Lösung sähe ungefähr so aus.

    char** selectw_1_svc(const char* const argp, const struct svc_req* const rqstp)  {
       char** result = NULL;
       size_t num_results = 0; // Du musst die Zahl der Ergebnisse irgend wie ermitteln
    
       result = malloc((num_results + 1) * sizeof(char*));
       result[num_results] = NULL;
    
       for (size_t i = 0; i != num_results; ++i) {
           size_t string_length = 0; // ähnliche Aufgabe die Länge der Strings muss bestimmt werden.
    
           result[i] = malloc(string_length+1);
           strcpy (result[i], source_string); // Woher kommen die Infos bei Dir?
           char* const p = result[i];
           p[string_length] = 0;
       }
    
       return result;
    }
    
    void free_result (char** p) {
       for (size_t i = 0; p[i] != NULL; ++i) {
           free(p[i]);
       }
       free(p);
    }
    

    Diese Funktion liefert eine NULL-terminiertes Array von Zeiger auf char zurück. Außerhalb der Funktion ist man verantwortlich die innerhalb der Funktion allozierten Felder mittels free()wieder freizugeben. Dafür gibt es dann free_result.

    Da Du leider keine übersetzbaren Codeteile postest ist das ganze ungetestet.



  • Die beiden Aufgaben funktionieren teilweise.
    Deswegen folgt unten alles an Code was ich habe und was man braucht usw.
    Zu Datenbankinhalt als einen String ausgeben:
    Eingabe:
    I
    i eins
    i zwei
    i drei
    m
    Ausgabe:
    eins
    Erwartete Ausgabe: eins zwei drei

    Abfrage mit zwei Argumenten:
    Eingabe:
    I
    i eins
    i zwei
    i drei
    i vier
    b a vier
    Ausgabe:
    eins
    ';Y[U
    drei
    Erwartete Ausgabe:
    eins
    drei
    vier

    Auch ich lese mich in Literatur ein um Pointer, Stack etc wieder aufzufrischen.

    Ab hier folgt der gesamte Quellcode:
    rdbase_client.c (Ab Z. 98 ff)

    #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;
    	int  *result_3;
    	char * deletew_1_arg;
    	int  *result_4;
    	char * lookupw_1_arg;
    	int  *result_5;
    	upd  updatew_1_arg;
    	int  *result_6;
    	char *countw_1_arg;
    	char * *result_7;
    	char *selectw_1_arg;
    	manywords  *result_8;
    	twoargs  selectbetweenw_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");
    			}
    			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: %s\n", word1);
    			}else{
    				printf ("Word could not be inserted: %s\n", word1);
    			}
    			break;
    		case 'd':
    			deletew_1_arg = word1;
    			result_3 = deletew_1(&deletew_1_arg, clnt);
    			if (result_3 == (int *) NULL) {
    				clnt_perror (clnt, "call failed");
    			}else if(*result_3 > 0){
    				printf ("Word deleted: %s\n", word1);
    			}else{
    				printf ("Word could not be deleted: %s\n", word1);
    			}
    			break;
    		case 'l':
    			lookupw_1_arg = word1;
    			result_4 = lookupw_1(&lookupw_1_arg, clnt);
    			if (result_4 == (int *) NULL) {
    				clnt_perror (clnt, "call failed");
    			}else if(*result_4 > 0){
    				printf ("Word found: %s\n", word1);
    			}else{
    				printf ("Word could not be found: %s\n", word1);
    			}
    			break;
    		case 'u':
    			updatew_1_arg.upd_old = word1;
    			updatew_1_arg.upd_new = word2;
    			result_5 = updatew_1(&updatew_1_arg, clnt);
    			if (result_5 == (int *) NULL) {
    				clnt_perror (clnt, "call failed");
    			}else if(*result_5 > 0){
    				printf ("Word updated: %s -> %s\n", word1, word2);
    			}else{
    				printf ("Word could not updated: %s -> %s\n", word1, word2);
    			}
    			break;
    		case 'c':
    			result_6 = countw_1((void*)&countw_1_arg, clnt);
    			if (result_6 == (int *) NULL) {
    				clnt_perror (clnt, "call failed");
    			}else{
    				printf("Counted words in database: %d\n", *result_6);
    			}
    			break;
    		case 'm':
    			result_7 = selectw_1((void*)&selectw_1_arg, clnt);
    			if (result_7 == (char **) NULL) {
    				clnt_perror (clnt, "call failed");
    			}else{
    				printf("Content of database: %s\n", *result_7);
    			}
    			break;
    		case 'b':
    			selectbetweenw_1_arg.firstarg = word1;
    			selectbetweenw_1_arg.secondarg = word2;
    			result_8 = selectbetweenw_1(&selectbetweenw_1_arg, clnt);
    			if (result_8 == (manywords *) NULL) {
    				clnt_perror (clnt, "call failed");
    			} else{
    				for(u_int i = 0; i < result_8->words.words_len; i++){
    					printf("%s\n", result_8->words.words_val[i]);
    				}
    			}
    		
    	}
    	clnt_destroy (clnt);
    
    }
    
    
    int
    main (int argc, char *argv[])
    {
    	char *host; 
    	char word1 [MAXWORD + 1];
        char word2 [MAXWORD + 1];
        char cmd;
        int wrdlen;
    	
    	while(1){
    		printf ("\nEnter Command out of    I i d l u c m b  \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;
       //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, "%c %s %s", cmd, word1, word2); // liest aus commannd in tmp, word, word2 hinein
    //   *cmd = tmp;
       return 0;
    }
    
    

    rdbase_server.c Ab Zeile 98

    #include <stdio.h>
    #include <string.h>
    
    #include "rdbase.h"
    
    char dict[DBASESIZE] [MAXWORD+1];
    int  nwords = 0;
    
    void printDB();
    
    int *
    initw_1_svc(void *argp, struct svc_req *rqstp)
    {
    	static int  result;
        nwords = 0;	
    	result = 1;
    	printf("Called initw.\n");
    	return &result;
    }
    
    int *
    insertw_1_svc(char **argp, struct svc_req *rqstp)
    {
    	static int  result;
    	printf("Insert %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;
    	
    	//printDB();
    	
    	return &result;
    }
    
    int *
    deletew_1_svc(char **argp, struct svc_req *rqstp)
    {
    	static int  result;
    	printf("Delete %s.\n", *argp);
       int i;
       for (i=0; i<nwords; i++)
    		if (strcmp (*argp, dict[i]) == 0) {
    			nwords--;
    			strcpy (dict[i], dict[nwords]);
    			result = 1;
    			return &result;
    		}
    	result = 0;
    	return &result;
    }
    
    int *
    lookupw_1_svc(char **argp, struct svc_req *rqstp)
    {
    	static int  result;
    	printf("Lookup %s.\n", *argp);
       int i;
       for (i=0; i<nwords; i++)
          if (strcmp (*argp, dict[i]) == 0){
    			result = 1;
    			return &result;
    	  }
    	result = 0;
    	return &result;
    }
    
    int *
    updatew_1_svc(upd *argp, struct svc_req *rqstp)
    {
    	static int  result;
    	printf("Update %s -> %s.\n", argp->upd_old, argp->upd_new);
       int i;
       for (i=0; i<nwords; i++)
          if (strcmp (argp->upd_old, dict[i]) == 0) {
             strcpy (dict[i], argp->upd_new);
    		 result = 1;
            return &result;
          }
       result = 0;
    	return &result;
    }
    
    int *
    countw_1_svc(void *argp, struct svc_req *rqstp)
    {
    	static int  result;
    	printf("Called countw.\n");
    	result = nwords;
    
    	return &result;
    }
    
    char **
    selectw_1_svc(void *argp, struct svc_req *rqstp)
    {
       char** result = NULL;
       printf("Called selectw.\n");
       size_t num_results = nwords;
    
       result = malloc((num_results + 1) * sizeof(char*));
       result[num_results] = NULL;
    
       for (size_t i = 0; i != num_results; ++i) {
           size_t string_length = strlen(dict[i]);
           result[i] = malloc(string_length+1);
           strcpy (result[i], dict[i]); // Woher kommen die Infos bei Dir?
           char* const p = result[i];
           p[string_length] = 0;
       }
    
       return result;
    }
    
    
    manywords *
    selectbetweenw_1_svc(twoargs *argp, struct svc_req *rqstp)
    {
    	static manywords  result;
    	printf("Between: %s and %s\n", argp->firstarg, argp->secondarg);
    	int number = 0;
    	for(int k = 0; k < nwords; k++){
    		if((strcmp(argp->firstarg, dict[k]) <= 0) && (strcmp(argp->secondarg, dict[k]) >= 0)){
    			number++;
    		}
    	}
    
    	result.words.words_len = number;
    	result.words.words_val = malloc(number * sizeof(oneword));
    	for (size_t i = 0; i < nwords; ++i) {
    		if((strcmp(argp->firstarg, dict[i]) <= 0) && (strcmp(argp->secondarg, dict[i]) >= 0)){
    			result.words.words_val[i].word = malloc(strlen(dict[i]) + 1);
    			strcpy(result.words.words_val[i].word, dict[i]);
    		}
    	}
    
    	return &result;
    }
    
    void printDB(){
    	for(int i = 0; i < nwords; i++){
    		printf("%s\n", dict[i]);
    	}
    }
    
    

    Folgende Dateien sind unverändert und sollen unverändert bleiben:
    rdbase.h

    /*
     * Please do not edit this file.
     * It was generated using rpcgen.
     */
    
    #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 */
    
    

    rdbase_cInt.c

    /*
     * Please do not edit this file.
     * It was generated using rpcgen.
     */
    
    #include <memory.h> /* for memset */
    #include "rdbase.h"
    
    /* Default timeout can be changed using clnt_control() */
    static struct timeval TIMEOUT = { 25, 0 };
    
    int *
    initw_1(void *argp, CLIENT *clnt)
    {
    	static int clnt_res;
    
    	memset((char *)&clnt_res, 0, sizeof(clnt_res));
    	if (clnt_call (clnt, INITW,
    		(xdrproc_t) xdr_void, (caddr_t) argp,
    		(xdrproc_t) xdr_int, (caddr_t) &clnt_res,
    		TIMEOUT) != RPC_SUCCESS) {
    		return (NULL);
    	}
    	return (&clnt_res);
    }
    
    int *
    insertw_1(char **argp, CLIENT *clnt)
    {
    	static int clnt_res;
    
    	memset((char *)&clnt_res, 0, sizeof(clnt_res));
    	if (clnt_call (clnt, INSERTW,
    		(xdrproc_t) xdr_wrapstring, (caddr_t) argp,
    		(xdrproc_t) xdr_int, (caddr_t) &clnt_res,
    		TIMEOUT) != RPC_SUCCESS) {
    		return (NULL);
    	}
    	return (&clnt_res);
    }
    
    int *
    deletew_1(char **argp, CLIENT *clnt)
    {
    	static int clnt_res;
    
    	memset((char *)&clnt_res, 0, sizeof(clnt_res));
    	if (clnt_call (clnt, DELETEW,
    		(xdrproc_t) xdr_wrapstring, (caddr_t) argp,
    		(xdrproc_t) xdr_int, (caddr_t) &clnt_res,
    		TIMEOUT) != RPC_SUCCESS) {
    		return (NULL);
    	}
    	return (&clnt_res);
    }
    
    int *
    lookupw_1(char **argp, CLIENT *clnt)
    {
    	static int clnt_res;
    
    	memset((char *)&clnt_res, 0, sizeof(clnt_res));
    	if (clnt_call (clnt, LOOKUPW,
    		(xdrproc_t) xdr_wrapstring, (caddr_t) argp,
    		(xdrproc_t) xdr_int, (caddr_t) &clnt_res,
    		TIMEOUT) != RPC_SUCCESS) {
    		return (NULL);
    	}
    	return (&clnt_res);
    }
    
    int *
    updatew_1(upd *argp, CLIENT *clnt)
    {
    	static int clnt_res;
    
    	memset((char *)&clnt_res, 0, sizeof(clnt_res));
    	if (clnt_call (clnt, UPDATEW,
    		(xdrproc_t) xdr_upd, (caddr_t) argp,
    		(xdrproc_t) xdr_int, (caddr_t) &clnt_res,
    		TIMEOUT) != RPC_SUCCESS) {
    		return (NULL);
    	}
    	return (&clnt_res);
    }
    
    int *
    countw_1(void *argp, CLIENT *clnt)
    {
    	static int clnt_res;
    
    	memset((char *)&clnt_res, 0, sizeof(clnt_res));
    	if (clnt_call (clnt, COUNTW,
    		(xdrproc_t) xdr_void, (caddr_t) argp,
    		(xdrproc_t) xdr_int, (caddr_t) &clnt_res,
    		TIMEOUT) != RPC_SUCCESS) {
    		return (NULL);
    	}
    	return (&clnt_res);
    }
    
    char **
    selectw_1(void *argp, CLIENT *clnt)
    {
    	static char *clnt_res;
    
    	memset((char *)&clnt_res, 0, sizeof(clnt_res));
    	if (clnt_call (clnt, SELECTW,
    		(xdrproc_t) xdr_void, (caddr_t) argp,
    		(xdrproc_t) xdr_wrapstring, (caddr_t) &clnt_res,
    		TIMEOUT) != RPC_SUCCESS) {
    		return (NULL);
    	}
    	return (&clnt_res);
    }
    
    manywords *
    selectbetweenw_1(twoargs *argp, CLIENT *clnt)
    {
    	static manywords clnt_res;
    
    	memset((char *)&clnt_res, 0, sizeof(clnt_res));
    	if (clnt_call (clnt, SELECTBETWEENW,
    		(xdrproc_t) xdr_twoargs, (caddr_t) argp,
    		(xdrproc_t) xdr_manywords, (caddr_t) &clnt_res,
    		TIMEOUT) != RPC_SUCCESS) {
    		return (NULL);
    	}
    	return (&clnt_res);
    }
    
    

    rdbase_svc.c

    /*
     * Please do not edit this file.
     * It was generated using rpcgen.
     */
    
    #include "rdbase.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <rpc/pmap_clnt.h>
    #include <string.h>
    #include <memory.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    #ifndef SIG_PF
    #define SIG_PF void(*)(int)
    #endif
    
    static void
    rdbaseprog_1(struct svc_req *rqstp, register SVCXPRT *transp)
    {
    	union {
    		char *insertw_1_arg;
    		char *deletew_1_arg;
    		char *lookupw_1_arg;
    		upd updatew_1_arg;
    		twoargs selectbetweenw_1_arg;
    	} argument;
    	char *result;
    	xdrproc_t _xdr_argument, _xdr_result;
    	char *(*local)(char *, struct svc_req *);
    
    	switch (rqstp->rq_proc) {
    	case NULLPROC:
    		(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
    		return;
    
    	case INITW:
    		_xdr_argument = (xdrproc_t) xdr_void;
    		_xdr_result = (xdrproc_t) xdr_int;
    		local = (char *(*)(char *, struct svc_req *)) initw_1_svc;
    		break;
    
    	case INSERTW:
    		_xdr_argument = (xdrproc_t) xdr_wrapstring;
    		_xdr_result = (xdrproc_t) xdr_int;
    		local = (char *(*)(char *, struct svc_req *)) insertw_1_svc;
    		break;
    
    	case DELETEW:
    		_xdr_argument = (xdrproc_t) xdr_wrapstring;
    		_xdr_result = (xdrproc_t) xdr_int;
    		local = (char *(*)(char *, struct svc_req *)) deletew_1_svc;
    		break;
    
    	case LOOKUPW:
    		_xdr_argument = (xdrproc_t) xdr_wrapstring;
    		_xdr_result = (xdrproc_t) xdr_int;
    		local = (char *(*)(char *, struct svc_req *)) lookupw_1_svc;
    		break;
    
    	case UPDATEW:
    		_xdr_argument = (xdrproc_t) xdr_upd;
    		_xdr_result = (xdrproc_t) xdr_int;
    		local = (char *(*)(char *, struct svc_req *)) updatew_1_svc;
    		break;
    
    	case COUNTW:
    		_xdr_argument = (xdrproc_t) xdr_void;
    		_xdr_result = (xdrproc_t) xdr_int;
    		local = (char *(*)(char *, struct svc_req *)) countw_1_svc;
    		break;
    
    	case SELECTW:
    		_xdr_argument = (xdrproc_t) xdr_void;
    		_xdr_result = (xdrproc_t) xdr_wrapstring;
    		local = (char *(*)(char *, struct svc_req *)) selectw_1_svc;
    		break;
    
    	case SELECTBETWEENW:
    		_xdr_argument = (xdrproc_t) xdr_twoargs;
    		_xdr_result = (xdrproc_t) xdr_manywords;
    		local = (char *(*)(char *, struct svc_req *)) selectbetweenw_1_svc;
    		break;
    
    	default:
    		svcerr_noproc (transp);
    		return;
    	}
    	memset ((char *)&argument, 0, sizeof (argument));
    	if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
    		svcerr_decode (transp);
    		return;
    	}
    	result = (*local)((char *)&argument, rqstp);
    	if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
    		svcerr_systemerr (transp);
    	}
    	if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
    		fprintf (stderr, "%s", "unable to free arguments");
    		exit (1);
    	}
    	return;
    }
    
    int
    main (int argc, char **argv)
    {
    	register SVCXPRT *transp;
    
    	pmap_unset (RDBASEPROG, RDBASEVERS);
    
    	transp = svcudp_create(RPC_ANYSOCK);
    	if (transp == NULL) {
    		fprintf (stderr, "%s", "cannot create udp service.");
    		exit(1);
    	}
    	if (!svc_register(transp, RDBASEPROG, RDBASEVERS, rdbaseprog_1, IPPROTO_UDP)) {
    		fprintf (stderr, "%s", "unable to register (RDBASEPROG, RDBASEVERS, udp).");
    		exit(1);
    	}
    
    	transp = svctcp_create(RPC_ANYSOCK, 0, 0);
    	if (transp == NULL) {
    		fprintf (stderr, "%s", "cannot create tcp service.");
    		exit(1);
    	}
    	if (!svc_register(transp, RDBASEPROG, RDBASEVERS, rdbaseprog_1, IPPROTO_TCP)) {
    		fprintf (stderr, "%s", "unable to register (RDBASEPROG, RDBASEVERS, tcp).");
    		exit(1);
    	}
    
    	svc_run ();
    	fprintf (stderr, "%s", "svc_run returned");
    	exit (1);
    	/* NOTREACHED */
    }
    
    

    rdbase_xdr.c

    /*
     * Please do not edit this file.
     * It was generated using rpcgen.
     */
    
    #include "rdbase.h"
    
    bool_t
    xdr_upd (XDR *xdrs, upd *objp)
    {
    	register int32_t *buf;
    
    	 if (!xdr_string (xdrs, &objp->upd_old, MAXWORD))
    		 return FALSE;
    	 if (!xdr_string (xdrs, &objp->upd_new, MAXWORD))
    		 return FALSE;
    	return TRUE;
    }
    
    bool_t
    xdr_oneword (XDR *xdrs, oneword *objp)
    {
    	register int32_t *buf;
    
    	 if (!xdr_string (xdrs, &objp->word, MAXWORD))
    		 return FALSE;
    	return TRUE;
    }
    
    bool_t
    xdr_manywords (XDR *xdrs, manywords *objp)
    {
    	register int32_t *buf;
    
    	 if (!xdr_array (xdrs, (char **)&objp->words.words_val, (u_int *) &objp->words.words_len, DBASESIZE,
    		sizeof (oneword), (xdrproc_t) xdr_oneword))
    		 return FALSE;
    	return TRUE;
    }
    
    bool_t
    xdr_twoargs (XDR *xdrs, twoargs *objp)
    {
    	register int32_t *buf;
    
    	 if (!xdr_string (xdrs, &objp->firstarg, MAXWORD))
    		 return FALSE;
    	 if (!xdr_string (xdrs, &objp->secondarg, MAXWORD))
    		 return FALSE;
    	return TRUE;
    }
    
    

    Makefile.rdbase

    # This is a template Makefile generated by rpcgen
    
    # Parameters
    
    CLIENT = rdbase_client
    SERVER = rdbase_server
    
    SOURCES_CLNT.c = 
    SOURCES_CLNT.h = 
    SOURCES_SVC.c = 
    SOURCES_SVC.h = 
    SOURCES.x = rdbase.x
    
    TARGETS_SVC.c = rdbase_svc.c rdbase_server.c rdbase_xdr.c 
    TARGETS_CLNT.c = rdbase_clnt.c rdbase_client.c rdbase_xdr.c 
    TARGETS = rdbase.h rdbase_xdr.c rdbase_clnt.c rdbase_svc.c rdbase_client.c rdbase_server.c
    
    OBJECTS_CLNT = $(SOURCES_CLNT.c:%.c=%.o) $(TARGETS_CLNT.c:%.c=%.o)
    OBJECTS_SVC = $(SOURCES_SVC.c:%.c=%.o) $(TARGETS_SVC.c:%.c=%.o)
    # Compiler flags 
    
    CFLAGS += -g 
    LDLIBS += -lnsl
    RPCGENFLAGS = 
    
    # Targets 
    
    all : $(CLIENT) $(SERVER)
    
    $(TARGETS) : $(SOURCES.x) 
    	rpcgen $(RPCGENFLAGS) $(SOURCES.x)
    
    $(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) $(TARGETS_CLNT.c) 
    
    $(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) $(TARGETS_SVC.c) 
    
    $(CLIENT) : $(OBJECTS_CLNT) 
    	$(LINK.c) -o $(CLIENT) $(OBJECTS_CLNT) $(LDLIBS) 
    
    $(SERVER) : $(OBJECTS_SVC) 
    	$(LINK.c) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)
    
     clean:
    	 $(RM) core $(TARGETS) $(OBJECTS_CLNT) $(OBJECTS_SVC) $(CLIENT) $(SERVER)
    
    
    

    Start des Programmes:

    make -f Makefile.rdbase
    sudo ./rdbasae_server
    sudo ./rdbase_client
    

    Hoffe das passt alles.



  • Gucken wir uns mal den delete-Teil an:

    @werdas_34 sagte in Rückgabewert:

       for (i=0; i<nwords; i++)
    		if (strcmp (*argp, dict[i]) == 0) {
    			nwords--;
    			strcpy (dict[i], dict[nwords]);
    			result = 1;
    			return &result;
    		}
    
    1. behält die Reihenfolge nicht bei.
    2. Schau dir den Spezialfall an, dass du das letzte Element löscht! Dann machst du trotzdem ein strcpy - und zwar von dem letzten auf das letzte Element. Siehe https://en.cppreference.com/w/c/string/byte/strcpy: "The behavior is undefined if the strings overlap." - das tun sie, sie sind sogar identisch. Sieh auch mal nach, was restrict bedeutet.


  • @werdas_34 sagte in Rückgabewert:

    • Please do not edit this file.

    Super Voraussetzung, um eigene Ideen auszuprobieren.



  • @wob sagte in Rückgabewert:

    Gucken wir uns mal den delete-Teil an:

    Klar kann man versuchen eine Übungsaufgabe aus dem Studium, um Inhalte aus der Vorlesungen besser zu verstehen, es übertreiben. Ich könnte noch ne GUI hinzufügen und ne SQL Datenbank anschließen.
    Selbst permamente Überprüfung, ob Parameter nicht NULL bzw sinnvolle Werte haben, wäre sinnvoll, wird dann weggelassen, weil die Aufgabe einmal vorgeführt und dann gelöscht wird.

    Lange Rede kurzer Sinn:
    Unser Prof sieht einige Sachen nicht so streng und manche Teile kommen gar von ihm selbst unter anderem die delete Funktion. Einfach das wir den Fokus auf den Kern der Aufgabe (letzten beiden Funktionen) legen.

    Ich bin mir sicher du wolltest mir damit nur zeigen, dass der Teil nicht ideal umgesetzt ist und bei professioneller Software vermieden werden sollte.

    Dennoch bitte ich den Fokus auf die letzten beiden Funktionen zu werfen.

    Vielen Dank.



  • @werdas_34 sagte in Rückgabewert:

    [ganz viel bla bla bla]

    Ich bin mir sicher du wolltest mir damit nur zeigen, dass der Teil nicht ideal umgesetzt ist und bei professioneller Software vermieden werden sollte.

    Nein. Ich habe dir gesagt, dass der gezeigte Code undefiniertes Verhalten hat.



  • @wob sagte in Rückgabewert:

    Nein. Ich habe dir gesagt, dass der gezeigte Code undefiniertes Verhalten hat.

    Dann hat der Prof offenbar nichts dagegen.

    Oder meinst du, davon kommt die fehlerhafte Ausgabe aus der letzten Aufgabe?
    Komisch nur das die delete Funktion nicht aufgerufen wird...



  • Das Prof hat keine Ahnung, was UB ist und bedeutet. Deswegen hat er nichts dagegen.
    Dein Prof ist zu faul, sich selbst sinnvolle Aufgaben für euch auszudenken und bemüht stattdessen einen Uralt-C89 Generator um Code zu produzieren, an dem ihr dann rumfrickeln sollt.
    Lernen tut ihr bei diesem Studium dieses Codes natürlich nichts.



  • @Wutz sagte in Rückgabewert:

    Das Prof hat keine Ahnung, was UB ist und bedeutet. Deswegen hat er nichts dagegen.

    Das kann gut sein, aber ...

    Dein Prof ist zu faul, sich selbst sinnvolle Aufgaben für euch auszudenken und bemüht stattdessen einen Uralt-C89 Generator um Code zu produzieren, an dem ihr dann rumfrickeln sollt.

    Das dürfte eine Vorlesung sein, in der RPC eine Rolle spielt. Vielleicht geht es um verteilte Systeme. Es ist mit ziemlicher Sicherheit keine Vorlesung, in der C-Programmierung im Mittelpunkt steht, sondern C ist das Handwerkszeug (das sich die Studierenden bitteschön selbst beizubringen haben), um höhere Konzepte zu erlernen.



  • @Wutz sagte in Rückgabewert:

    Das Prof hat keine Ahnung, was UB ist und bedeutet. Deswegen hat er nichts dagegen.
    Dein Prof ist zu faul, sich selbst sinnvolle Aufgaben für euch auszudenken und bemüht stattdessen einen Uralt-C89 Generator um Code zu produzieren, an dem ihr dann rumfrickeln sollt.

    Ich weiß nicht, wo ich anfangen soll. Deswegen lass ich es gleich komplett.

    @Wutz sagte in Rückgabewert:

    Lernen tut ihr bei diesem Studium dieses Codes natürlich nichts.

    Es geht ja nur darum das Prinzip Remote Procedure Call in C zu verstehen und einmal angewandt zu haben. Der Rest dient nur dazu, das ganze halbwegs funktional zu halten. Schließlich keine vollwertige Software..
    Dazu ist mein letztes C Projekt drei Jahre her und ich fange was Pointer und Speicher etc. wieder von vorne an.



  • @Wutz sagte in Rückgabewert:

    Dein Prof ist zu faul, sich selbst sinnvolle Aufgaben für euch auszudenken und bemüht stattdessen einen Uralt-C89 Generator um Code zu produzieren, an dem ihr dann rumfrickeln sollt.

    RPC ist noch immer Basis von NFS und diverser anderer IX Dienste, insofern ist das nichts veraltet. Im Gegensatz zu dem ganzen neuen Gedöns ist RPC schnell.



  • @john-0
    Und?



  • @werdas_34 Das ist recht viel Code um alles zu überblicken, inklusive globaler Variablen, die sich überall ändern können.
    Das Zauberwort heißt hier minimales compilierbares Beispiel, dass das Problem reproduziert. Damit lenkst du auch den Fokus der Community auf das Problem, dass du gelöst haben möchtest.
    Außerdem würde ich dir empfehlen, mal ein Debugger zu benutzen und zu gucken, was an welcher Stelle genau passiert.


Anmelden zum Antworten