Timothy Maloney
Timothy Maloney

Reputation: 11

How can I send command line arguments to a malloc array, and then send those arguments from a parent process to a child process

This is for a school assignment, and I know this is about a simple problem as there is, but for the life of me I can't figure out what I am doing wrong.

In the parent process, I need to convert cmdline arguments to integers, then store the arguments in a malloc array. I then need to send each integer to the child process one at a time. The child process will then sum all of the integers passed from the parent process. Once the summation is complete, it will return the sum to the parent process. The parent process then prints out the sum.

There are 3 things I do not understand about this code.

  1. Taking command line arguments, converting them into integers, and storing them using a pointer to a malloc array. I do not understand why I can't just write this in my parent process:
  int* numArray = (int*) malloc (argc * sizeof(int));
  for(int i = 0; i < argc; ++i){
     numArray[i] = atoi(argv[i+1]);
  }
  1. How can I send individual values to child process for summation? I can read them one at a time, and then increment sum by the value in sumBuf. Then sumBuf gets overwritten with the next value, and increments sum by sumBuf again. How can I do this?

  2. How can I access the child's return value in the parent process?

Storing the integers in the malloc array yields a segmentation fault, and I do not understand how to correct this. also, since fork returns the child's PID, if the child returns a sum, shouldn't the sum be the child's PID?

  1. For the malloc array I have tried de-referencing numArray inside the for loop like:
   *numArray[i] = atoi(argv[i+1]) 
  1. I have tried writing individual values to the pipe within a for loop

  2. I know that fork returns the child PID value, so if child returns sum, shouldn't sum = p, store sum into the parent's sum value?

    int main(int argc, char **argv){
      int *numArray = (int*) malloc (argc * sizeof(int));
      pid_t p;
      int fd[2];
      pipe(fd);
      p = fork()
      //error checks
    
      if(p == 0){//child process
           int sum = 0;
           int sumBuf = 0;
           close(fd[1]);//close write end
           for(int i = 0; i < argc; ++i){
               read(fd[0], sumBuf, sizeof(int));
               sum += sumBuf;
           }
           close(fd[0]);//close read end
           return sum;//return sum from child process
       }
       else{//parent process
           int sum = 0;
           close(fd[0]);//close read end
           for(int i = 0; i < argc; ++i){
               numArray[i] = atoi(argv[i+1]);
               write(fd[1], numArray[i], sizeof(int));
           }
           close(fd[1]);//close write end of pipe
           sum = p;
           printf("Sum = %d", sum);
           return 0;
       }
       free(numArray);
       return 0;
    }
    

I get a segmentation fault message when I try to run this program. Please don't call me stupid, I understand the idea of what to do, but I don't understand how to implement it..

Upvotes: 1

Views: 620

Answers (2)

adeishs
adeishs

Reputation: 79

Before getting to the main thing… I assume you have put #include <stdlib.h> (as well as <stdio.h> and <unistd.h>) there.

This:

int *numArray = (int*) malloc (argc * sizeof(int));

can be replaced with a better alternative:

int *numArray = malloc(argc * sizeof *numArray);

The cast is unnecessary. Also, using sizeof *pointer is better as if you need to change the data type pointed by the array, you won’t need to change the sizeof. Also, if you forget to #include <stdlib.h>, malloc() will return an int. Putting the cast basically tells the compiler to be quiet about it. If you don’t put the cast, you will get a diagnostic message.

As a matter of good habit, it’s also better to check the return value of the malloc(), e.g.

if (!numArray) {
    return EXIT_FAILURE;
}

Also, strtol() is better than atoi() as the former provides error checking.

Nitpick: You need to put ; after fork().

If you need to send back a value from the child to the parent, you can’t do what you did: sum = p;. Instead, you should create another pipe if the operating system doesn’t support bidirectional pipes (probably safer to assume this). I leave this as an exercise for you.

Now, write() and read() need their second argument a pointer. So, for example, the read() should be:

read(fd[0], &sumBuf, sizeof sumBuf);

Similarly for the write().

I don’t get what you mean by why you couldn’t just write the malloc() in the parent process. You certainly can, and it’s better as the child, as I understand, should have no access to the allocated memory.

Now, the most likely cause of the segfault is the undefined behaviour caused by reading past array bound. In this case, argv. This is probably easier to explain using an example:

If you run it this way:

./a.out 1 2 3

argc will be 4, meaning that you can only access argv[0] to argv[3]. Now, here’s a hint: look at the loops.

Upvotes: 2

Ajay Brahmakshatriya
Ajay Brahmakshatriya

Reputation: 9203

  1. I do not understand why I can't just write this in my parent process -- that is exactly what you have done and it should work. There is nothing wrong with it.

  2. The read and the write functions take the address of the buffer as the second argument. You have tried to pass the value of the variables. Change the following lines as -

read(fd[0], sumBuf, sizeof(int));

to

read(fd[0], &sumBuf, sizeof(int));

and

write(fd[1], numArray[i], sizeof(int));

to

write(fd[1], &(numArray[i]), sizeof(int));

This should solve the problem for you. Also, your compiler must have warned you about these. Please treat all warnings as errors.

  1. You can access the child's process id in the parent by looking at the return value of fork. In your case, the variable p.

You also seem to be having a confusion between PID and the value the process returns. PID is a process identifier. It is unique to a process. The return value is what the main function of that process returns. This can be integer (two processes can also return the same value). The parent can access the value it's child returns using the wait function.

Upvotes: 0

Related Questions