0

I'm working on a slightly different take on linked lists than I've tried to tackle before, and it's leading to some issues. I'm familiar with handling a linked list using simple integer parameters, but I'm trying to handle a character array, and can't figure out exactly how to add to a list in this situation:

struct process{
    pid_t pid;
    char userArgument[1024];
    struct process* next;
};

class processList{
    private:
    process *head, *tail;
    public:
    processList(){
        head = NULL;
        tail = NULL;
    }

    void add(int pid, char argument[]){
        process *tmp = new process;
        tmp->pid = pid;
        tmp->userArgument = argument; //PROBLEM. I want this to take a character array passed to add() and use it as the userArgument for this new process
        tmp->next = NULL;

        if(head == NULL){
            head = tmp;
            tail = tmp;
        }
        else{
            tail->next = tmp;
            tail = tail->next;
        }

    }
};

The intended behaviour of the add function would be to create a new process with a pid of type int, and a new userArgument of type char[]. In the line I've marked as the problem, however, it throws up an error, and I've tried alternative versions without success (passing add() a string instead, using c_str(), etc). I'm stuck trying to get this to work, and would appreciate any help that can be offered.

MMMMMCK
  • 307
  • 3
  • 14
  • 3
    If you're using C++, is there some reason you're avoiding `std::string`? – scohe001 Jan 29 '18 at 22:26
  • std::string would likely have been a better decision and I realized that many hours after I started this project, but at this point the entire program is written around character arrays so I'm dedicated to that format. – MMMMMCK Jan 29 '18 at 22:29
  • 1
    @MMMMMCK - bad idea. When in hole - rule #1, stop digging. – pm100 Jan 29 '18 at 22:40
  • @MMMMMCK _"... but at this point the entire program is written around character arrays ..."_ `std::string` supports c-style character arrays using the `c_str()` function pretty well. Also you always can interact using the `data()` function, if you need write access. Any more substantial reasons not to use it (besides homework assignment restrictions)? –  Jan 29 '18 at 22:47
  • 1
    No, mostly general inexperience. This is good insight, I'll take a look at some of these functions and see if I can incorporate them into my work, thank you. – MMMMMCK Jan 29 '18 at 22:51
  • @MMMMMCK I wrote an answer which should give you the idea. Please get rid of that _old school_ c-style stuff of handling strings. –  Jan 29 '18 at 23:16
  • @MMMMMCK To add up upon my answer: The [`std::string_view`](http://en.cppreference.com/w/cpp/string/basic_string_view) feature is available with the very latest standard ([tag:c++17]), and would give you even better performance in regards to avoid copying strings around. –  Jan 29 '18 at 23:34

4 Answers4

2
   strcpy(tmp->userArgument, argument);

should do the trick.

Jim Lewis
  • 43,505
  • 7
  • 82
  • 96
  • Ah, perfect, I completely forgot about strcpy and it worked instantly! Thanks for the help, will accept when possible. – MMMMMCK Jan 29 '18 at 22:34
  • _@Jim_ Not to mention that is prone to buffer overflows. –  Jan 29 '18 at 23:20
1

Arrays are not assignable.

To copy an array, you must use a loop. Or use a function that does the loop. To figure out which function to use, you must first figure out what argument pointer is pointing at.

If argument points to a null terminated string that is guaranteed to be at most 1023 characters long, then you can use std::strcpy. If the length is not limited, then you need to figure out what to do in that case.

If argument points to an array of at least 1024 char, then you can use std::memcpy.

eerorika
  • 232,697
  • 12
  • 197
  • 326
1

This will do what you want:

void add(int pid, char argument[])
    {
        process *tmp = new process;
        tmp->pid = pid;
        //tmp->userArgument = argument; //PROBLEM. I want this to take a character array passed to add() and use it as the userArgument for this new process
        size_t count = sizeof(tmp->userArgument);
        memcpy(tmp->userArgument,argument,count);
        tmp->next = NULL;

        if(head == NULL)
    {
            head = tmp;
            tail = tmp;
        }
        else{
            tail->next = tmp;
            tail = tail->next;
        }
}
Mike Pettigrew
  • 156
  • 1
  • 8
  • `memcopy` is an even worse idea than `strncpy()`. Are all people going mad here? What does this has to do with c++ programming? –  Jan 29 '18 at 22:55
  • 1
    The requestor is presumably using a fixed data block "char [1024] to store various data fields of interest - other than strings. "memcpy" is the appropriate technique in that situation. – Mike Pettigrew Jan 29 '18 at 23:00
  • We can agree to disagree that `memcpy()` and using a _"fixed data block"_ is the appropriate technique in this case. –  Jan 29 '18 at 23:30
0

The correct way to do this in c++ would be to use std::string (which supports direct assignment, whereas char[] array doesn't):

struct process{
    pid_t pid;
    std::string userArgument;
 // ^^^^^^^^^^^
    struct process* next;
};

class processList{
    private:
    process *head, *tail;
    public:
    processList(){
        head = NULL;
        tail = NULL;
    }

    void add(int pid, const std::sting& argument) {
                   // ^^^^^^^^^^^^^^^^^
        process *tmp = new process;
        tmp->pid = pid;
        tmp->userArgument = argument; // Works just out of the box with std::string
        tmp->next = NULL;

        if(head == NULL){
            head = tmp;
            tail = tmp;
        }
        else{
            tail->next = tmp;
            tail = tail->next;
        }

    }
};

You might consider adding functions that allow to access the c-style string from your process struct:

struct process{
    pid_t pid;
    std::string userArgument;
    struct process* next;

    // Convenience getter/setter functions to interact with c-style character arrays
    const char* userArgumentCStyleString() const {
        return userArgument.c_str();
    }
    void userArgumentCStyleString(const char* args) {
        userArgument = std::string(args);
    }    
};

This way you also get rid of that ugly fixed sized char[1024] array.

  • Not a good idea to do the extra copy into the parameter, and then again into the member. Better to either pass by reference, or move into the member. Edit: I see that was fixed while I was typing. Speaking of *modern c++ standards*, `std::string_view` might be a good choice for the argument. – eerorika Jan 29 '18 at 23:19
  • @user2079303 Let's not _overstress_ the OP ;-). But yes, `std::string_view` would be the even better choice. –  Jan 29 '18 at 23:22
  • @user2079303 HTML tags like `` won't work with the restricted markdown in comments BTW. –  Jan 29 '18 at 23:28