Reputation: 11
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.
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]);
}
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?
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?
malloc
array I have tried de-referencing numArray
inside the for loop like: *numArray[i] = atoi(argv[i+1])
I have tried writing individual values to the pipe within a for loop
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
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
Reputation: 9203
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.
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.
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