So for school I got this exercise where I need to make a program that calculates if a number is a prime number or not. This program should make use of parent and child processes, and strtoul should be used to convert the argv to a unsigned long.
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
void checkprime(unsigned long num);
int main(int argc, char *argv, char *env)
{
strtoul(argv, NULL, 0);
pid_t pid = fork();
if(pid == 0)
{
unsigned long number;
printf("\nGive number to check: \n");
scanf("%lu",&number);
checkprime(number);
}
else if(pid < 0)
{
perror("Fork Failed!");
}
else
{
int status = -1, result;
waitpid(pid, &status, 0);
result = WEXITSTATUS(status);
if(result == 1)
{
printf("this is a prime number\n");
}
else if(status < 0)
{
perror("Something Failed");
}
else
{
printf("this is not a prime number\n");
}
}
return 0;
}
void checkprime(unsigned long num)
{
int i;
for(i = 2; i < num; i++)
{
if(num % i == 0)
{
exit(0);
}
}
exit(1);
}
So when I try to compile this it says: line 13: identifier not expected. Error code 1.
The code on line 13 says: pid_t pid = fork();
Now my question is: Why do i get that error?
Its fixed, thanks everyone for the help. I appreciate it.
Some old versions of compilers accept C89 (not C99 or C11) as the default C dialect. You want C99 (since you have a declaration after a statement) at least.
If you use some old version of GCC on some old Linux distribution, try compiling with gcc -std=gnu99 -Wall -Wextra -g where -std=gnu99 sets the C dialect (you could also use -std=c99 or better), -Wall -Wextra asks for warnings, -g wants debug information (in DWARF, for the gdb debugger). Better yet, upgrade your GCC to a recent version (like GCC 7 in November 2017) whose default is C11 with GNU extensions.
Or put the declaration
pid_t pid= 0;
(I prefer to systematically initialize variables in C)
before the statements
strtoul(argv, NULL, 0); //useless call, you need to store the result
pid= fork();
The compiler is telling you it didn't expect to encounter an identifier pid_t at that line since the previous line wasn't an identifier. You need to declare your variables at the top of the scope, and put other code below that. You could either do this
int main(int argc, char *argv, char *env)
{
long int val=strtoul(argv, NULL, 0);
pid_t pid = fork();
...
or
int main(int argc, char *argv, char *env)
{
pid_t pid = fork();
strtoul(argv, NULL, 0);
...
But you're missing the value returned from strtol
You can use make shorter prime finder loop by changing, i < num to i < num/2.
This is one of standards for main() arguments:
(int argc, char **argv)
Turn on gcc flag: -Wall to see all warnings in code.
As #cleblanc said in one of answer, store return value of strtoul() to a varibale long int val = strtoul(argv[1], NULL, 0);.
we pass number for check, from command line arguments,
argv[1] refers to number when we run program with
./prime 15
Code
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void checkprime(unsigned long num);
int main(int argc, char **argv)
{
long int val = strtoul(argv[1], NULL, 0);
pid_t pid = fork();
if(pid == 0){
checkprime(val);
}
else if(pid < 0){
perror("Fork Failed!");
}
else{
int status = -1, result;
waitpid(pid, &status, 0);
result = WEXITSTATUS(status);
if(result == 1){
printf("Prime\n");
}
else if(status < 0){
perror("Something Failed");
}
else{
printf("Not prime\n");
}
}
return 0;
}
void checkprime(unsigned long num)
{
int i;
for(i = 2; i < num/2; i++){
if(num % i == 0){
exit(0);
}
}
exit(1);
}
Compile, Run
gcc -Wall prime.c -o prime
./prime 15
Related
Why this code may generate Runtime Error in ejudge? This program counts the number of words from stdin input. Words can be separated by any amount of ' ' and '\n'.
It seems like fork() can cause a problem but I am not sure why I don't get the same error on my computer.
ejudge uses gcc - Plain C, 64 bit, using -std=c11 or -std=gnu11
The task:
On the standard input stream a text string is given which consists of
words (a sequence of non-space characters), between which there can be
any number of whitespace characters, including line feeds.
You need to calculate the number of words if you know there are not
more than 255, and output this value to the standard output stream.
Use creating new processes so that each process reads not more than
one word, e.g. using scanf("%s", ...).
You can only output the result from the process which was started
first (i.e. from the original program).
The resulting program must return with return code 0.
The size of each word does not exceed 4096 bytes.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define DBG(args...) fprintf(stderr, args)
//#define DBG(args...)
int main(int argc, char* argv[])
{
int status;
pid_t pid;
pid_t first_child;
for (int i = 0; i < 256; ++i) {
pid = fork();
if (pid == 0) { // child continue reading
char str[4097];
if (scanf("%s", str) != EOF)
continue;
exit(1);
} else {
if (i == 1) {
first_child = pid;
}
if (wait(&status) == first_child) {
break;
} else {
exit(WEXITSTATUS(status) + 1);
}
}
}
fprintf(stdout, "%i\n", WEXITSTATUS(status));
fflush(stdout);
fclose(stdout);
return 0;
}
Rewrote the algorithm and it worked!
In the first version, many unnecessary forks were made. For example, if 6 were intended it created 12.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
// #define DBG(args...) fprintf(stderr, args)
#define DBG(args...)
int main(int argc, char* argv[])
{
int status;
pid_t first_pid;
pid_t pid = fork();
if (pid != 0) {
wait(&status);
printf("%i\n", WEXITSTATUS(status));
return 0;
}
for (int i = 0; i < 256; ++i) {
char str[4097];
if (scanf("%s", str) == EOF) {
DBG("PID %i\n", pid);
exit(0);
}
pid = fork();
if (pid != 0)
break;
}
DBG("PID %i waiting\n", pid);
wait(&status);
exit(WEXITSTATUS(status) + 1);
}
As in the following code,
I create a child process using fork function, remove the buffer of stdout, and create a race condition environment,
but the two processes do not compete.
System: Linux user1-ubuntu64 4.18.0-20-generic
Compiler: gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04)
Compile command: gcc -o test test.c
If give the parent process a very small delay(250ns), It work that I want.
The source code :
#include <stdio.h>
#include <sys/types.h>
static void printatime(char *);
int main(void)
{
pid_t pid;
if ((pid = fork()) < 0)
{
perror("fork error");
return -1;
}
else if (pid == 0)
{
printatime("AAAAAAAAAAAA");
}
else
{
printatime("BBBBBBBBBBBB");
}
return 0;
}
static void printatime(char *str)
{
char *ptr = str;
setbuf(stdout, NULL);
while (*ptr)
{
putc(*ptr++, stdout);
}
}
Expected results:
user#ubuntu64:~/C$ BAABBABABAABBAAABBABABAB
Actual results:
BBBBBBBBBBBBuser#ubuntu64:~/C$ AAAAAAAAAAAA
I have 2 processes running test.c. There is a signal handler in test.c which executes an execlp. In test.c, I have a static variable which needs to be only initialized once, and incremented each time before the execlp call. When either process reaches 99, they exit.
Unfortunately, right now, it's not getting incremented, my guess is because there are 2 processes that each have a copy of the static variable. Here is test.c:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static int i = 0;
static int foo(int j)
{
printf("In the foo...\n");
j++;
printf("%d\n", j);
return j;
}
void main(int argc, char *argv[])
{
int pid, pid2, k;
int *h = malloc(sizeof(int));
int g = 0;
h = &g;
static char s[15];
pid = fork();
if (pid > 0)
{
sleep(1);
}
if (pid == 0)
{
k = foo(*h);
sprintf(s, "%d", k);
if (k >= 99)
{
printf("k=99\n");
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
pid2 = fork();
if (pid2 == 0)
{
k = foo(*h);
sprintf(s, "%d", k);
if (k >= 99)
{
printf("k=99\n");
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
wait(pid2);
wait(pid);
}
Can anyone please explain why there is an infinite loop? Why isn't the static variable get incremented?
Thank you.
Use Interprocess communication concepts (pipe, fifo, shared memory) here, execlp function overwrites memory of current program with new program. So when ever you call execlp gets called your program get refreshed and starts from begining and static int i is always 0.
I recommend to use pipe Refer this.
You need to use memory projection (mmap function) if you want to use the concept of shared memory between process.
In your code, the variable 'h' is the shared variable between the three process.It should defined using mmap function and initialized in the main process and then incremented in the two child process.
The answers to your two questions are related: either of the two child process never exits (exit(0)) because the if(k>=99) is never statisfied. This is due to the non-shared variable h which doesn't get incremented.
I will rather use a while loop and a return type main function.
By the way, you don't need the 'g' varibale, you can initialize directly 'h'. And there is no need of declaring the function foo as static (static functions are only useful when you want them to visible only with the file where they are defined). The buffer 's' can be declared non static (it is only a buffer which contains the value of k)
Here is a modified version of your code, it compiles and works fine.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
int foo(int* j)
{
printf("In the foo...\n");
(*j)++;
printf("%d\n", *j);
return *j;
}
int main(void)
{
int pid, pid2, k;
char s[15];
int * h = (int*)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (h == MAP_FAILED) {
printf("map failed\n");
return -1;
}
*h = 0;
pid = fork();
if (pid < 0) {
printf("fork failed pid\n");
return -1;
}
if (pid > 0) {
sleep(1);
}
else {
while(1) {
k = foo(h);
sprintf(s, "%d", k);
if (k>=99) {
printf("k>=99\n");
printf("%s\n", s);
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
}
pid2 = fork();
if (pid2 < 0) {
printf("fork failed pid2\n");
}
if (pid2 > 0) {
sleep(1);
}
else {
while(1) {
k = foo(h);
sprintf(s, "%d", k);
if (k>=99) {
printf("k>=99\n");
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
}
wait(pid);
wait(pid2);
return 0;
}
Here is the output (only the last strings) click on the link:
output
I have a binary file that contains a program with function written in C inside that looks like:
int main()
{
int a, b;
foo(a,b);
return 0;
}
And now I want to execute that program by using fork() and execve() in another program called "solver".
int main(int argc, char* argv[])
{
pid_t process;
process = fork();
if(process==0)
{
if(execve(argv[0], (char**)argv, NULL) == -1)
printf("The process could not be started\n");
}
return 0;
}
Is that a good way? Because it compiles, but I'm not sure whether the arguments of function inside "worker" program receive variables passed by command line to "solver" program
I believe you are trying to achieve something like that:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
static char *sub_process_name = "./work";
int main(int argc, char *argv[])
{
pid_t process;
process = fork();
if (process < 0)
{
// fork() failed.
perror("fork");
return 2;
}
if (process == 0)
{
// sub-process
argv[0] = sub_process_name; // Just need to change where argv[0] points to.
execv(argv[0], argv);
perror("execv"); // Ne need to check execv() return value. If it returns, you know it failed.
return 2;
}
int status;
pid_t wait_result;
while ((wait_result = wait(&status)) != -1)
{
printf("Process %lu returned result: %d\n", (unsigned long) wait_result, status);
}
printf("All children have finished.\n");
return 0;
}
./work will be launched with the same arguments as your original program.
I'm attempting to fork a child and write a struct to it, but for some reason the write is failing. Here is what I've got so far:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
pid_t pid;
int pfd[2];
int rv;
if(pipe(pfd) == -1){
printf("Pipe failed\n");
}
struct t{
int count[26];
char array[4];
};
struct t st;
if((pid = fork()) < 0){
printf("Fork error\n");
}else if(pid == 0){
close(pfd[1]);
rv = read(pfd[0],st,sizeof(struct t));
printf("Read string: %d\n",rv);
}else{
int i = 0;
for(i = 0; i < 26; i++){
st.count[i] = i;
}
for(i = 0; i < 3; i++){
st.array[i] = 'A';
}
st.array[3] = '\0';
close(pfd[0]);
rv = write(pfd[1],st,sizeof(struct t));
printf("wrote: %d",rv);
close(pfd[1]);
}
}
This has been killing me all night. I have a suspicion that it has to do with me not fully understanding pointers to structs. I printed sizeof(struct t) which returned 108 bytes (as expected), and I thought st was a pointer to the beginning of the struct, meaning the write command would start there and write the first 108 bytes, but clearly that's not the case. What am I missing?
Try &st. st is the struct itself. & takes a pointer off of it.
You probably need to enable (or heed) the compiler warnings. Add -Wall or -Wall -Wextra to the compile command.
You need to include the header file for the read function.
#include <unistd.h>
Now you should get error messages.