Search code examples
cpointerssegmentation-faultrpc

How to iterate through a char ** variable


I'm running a small rpc program/ using an rpc framework that takes a char[] from the client file and sends it to the server that enumerates the integers in the string.

I have a file client.c that takes user input and passes it to an external function in a header file.

#include <rpc/rpc.h>
#include "getNumInt.h"

int main(int argc, char **argv){
    CLIENT *cli;
    char *server;
    server = argv[1];

    cli = clnt_create(server, GETNUMINT, GNUMINT, "tcp"); //creates a client handle
    /*does some check for whether the client connected*/
    char command[256];
    int *numInt;
    fgets(command, 256, stdin); 
    numInt = enumints_1(&command, cli); //segfaults here according to backtrace
    return(0);
}

The function enumints_1 is defined in my server stub server.c as:

int *enumints_1(msg, req)
    char **msg; struct svc_req *req;{
    printf(*msg);
    static int numDigits = 0;
    char msgcopy[256];
    strcpy(msgcopy, *msg);
    int i = 0;
    for(i; i<strlen(msgcopy); i++){
        if(msgcopy[i] >= '0' && msgcopy[i] <='9'){
            numDigits++;
        }
    }
    return(&numDigits);
}

My main issue is how I iterate through the char **msg as that is likely why my program is segfaulting. command is just a string taken from user input and then passed by reference to the enumints_1 function. Since it is a pointer to a point I assumed that I could just strcpy or memcpy to copy the string to a char array, but that doesn't work.

also my .x file:

struct intStringPair{
    int numInts;
    char msg[256];
};

program GETNUMINT{
    version GNUMINT{
        int ENUMINTS(string) = 1; //string considered char * the rpc generated file makes it so enumints_1 then has to take char **
        int WRITEMESSAGE(intStringPair) = 2;
    } = 1;
}= 0x20000001;

Solution

  • Like @user3386109 said:

    command is not a pointer. So &command is not a pointer-to-a-pointer

    so assigning &command to msg is not valid (and my compiler doesn't even compile it)

    When I compile this code:

    // my set up code
    
    #include <stdio.h>
    #include <string.h>
    struct svc_req {};
    typedef struct svc_req CLIENT;
    struct svc_req *clnt_create(const char *, int, int, const char*) {return 0;}
    int GETNUMINT=0, GNUMINT=0;
    
    // your code verbatim
    
    int *enumints_1(char **msg, struct svc_req *req){
        printf(*msg);
        static int numDigits = 0;
        char msgcopy[256];
        strcpy(msgcopy, *msg);
        int i = 0;
        for(i; i<strlen(msgcopy); i++){
            if(msgcopy[i] >= '0' && msgcopy[i] <='9'){
                numDigits++;
            }
        }
        return(&numDigits);
    }
    
    int main(int argc, char **argv){
        CLIENT *cli;
        char *server;
        server = argv[1];
    
        cli = clnt_create(server, GETNUMINT, GNUMINT, "tcp"); //creates a client handle
        /*does some check for whether the client connected*/
        char command[256];
        int *numInt;
        fgets(command, 256, stdin); 
        numInt = enumints_1(&command, cli); //segfaults here according to backtrace
        return(0);
    }
    

    The compiler says:

    <source>: In function 'int main(int, char**)':
    <source>:34:25: error: cannot convert 'char (*)[256]' to 'char**'
         numInt = enumints_1(&command, cli); //segfaults here according to backtrace
                             ^~~~~~~~
    <source>:10:24: note:   initializing argument 1 of 'int* enumints_1(char**, svc_req*)'
     int *enumints_1(char **msg, struct svc_req *req){
                     ~~~~~~~^~~
    Compiler returned: 1
    

    What you can do instead is make a pointer to the array and then pass the address of that:

    // my set up code
    #include <stdio.h>
    #include <string.h>
    struct svc_req {};
    typedef struct svc_req CLIENT;
    struct svc_req *clnt_create(const char *, int, int, const char*) {return 0;}
    int GETNUMINT=0, GNUMINT=0;
    
    // your code verbatim
    int *enumints_1(char **msg, struct svc_req *req){
        printf(*msg);
        static int numDigits = 0;
        char msgcopy[256];
        strcpy(msgcopy, *msg);
        int i = 0;
        for(i; i<strlen(msgcopy); i++){
            if(msgcopy[i] >= '0' && msgcopy[i] <='9'){
                numDigits++;
            }
        }
        return(&numDigits);
    }
    
    int main(int argc, char **argv){
        CLIENT *cli;
        char *server;
        server = argv[1];
    
        cli = clnt_create(server, GETNUMINT, GNUMINT, "tcp"); //creates a client handle
        /*does some check for whether the client connected*/
        char command[256], *command_pointer=command;
        int *numInt;
        fgets(command, 256, stdin); 
        numInt = enumints_1(&command_pointer, cli); //segfaults here according to backtrace
        return(0);
    }