YazanLpizra
YazanLpizra

Reputation: 540

C++ function running twice but only called once

I am learning C++ [Java background fwiw] and trying to write a UNIX shell as a project. I am running into a funny little problem with tokenizing the input for execution. The tok function is getting called twice and I'm not sure why. My current test code is the following:

#include <iostream>
#include <vector>
#include <sstream>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>

using namespace std;

void tok(string, char**);

int main(){
    const char* EXIT = "exit";

    string input;

    cout << "shell>> ";
    getline(cin, input);

    pid_t pid = fork();

    char* args[64]; //arbitrary size, 64 possible whitespace-delimited tokens in command
    tok(input, args);
    return 0;
  }

  //copied from http://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
void tok(string inStr, char** args){
    int last = 0, next = 0, i = 0;
    while( (next = inStr.find(' ', last)) != -1){
        cout << i++ << ": " <<  inStr.substr(last, next-last) << endl;
        *args++ = strdup(inStr.substr(last, next-last).c_str());
        last = next + 1;
    }
    cout << i++ << ": " << inStr.substr(last) << endl;
    *args++ = strdup(inStr.substr(last).c_str());
    *args = '\0';
    cout << "done tokenizing..." << endl;
}

My output when I actually run the program is:

$ ./a.out 
shell>> ls -l
0: ls
1: -l
done tokenizing...
0: ls
1: -l
done tokenizing...

I'm not sure why it would do that. Can anyone guide me in the right direction please? Thank you

Upvotes: 1

Views: 2611

Answers (3)

AndyG
AndyG

Reputation: 41120

When you call fork, you create two processes. Each process has nearly the exact same state except for the respective pid_t you receive. If that value is greater than 0, then you are in the parent process (main), and otherwise you are in the child (or fork failed).

Without performing a check on the returned pid_t, both processes will call tok, resulting in the double call behavior you witnessed.

Hide the call behind a check on pid like so:

pid_t pid = fork();
if (pid > 0) // have parent process call tok
{
   char* args[64]; //arbitrary size, 64 possible whitespace-delimited tokens in command
   tok(input, args);
}

To see what else parent and child processes have in common (or not): check the docs

Upvotes: 1

Abhishek
Abhishek

Reputation: 379

following code may work fine

#include <iostream>
#include <vector>
#include <sstream>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>

using namespace std;

void tok(string, char**);

int main(){
const char* EXIT = "exit";

 string input;

 cout << "shell>> ";
 getline(cin, input);

// pid_t pid = fork();

 char* args[64]; 
 tok(input, args);
 return 0;
}


void tok(string inStr, char** args){
int last = 0, next = 0, i = 0;
while( (next = inStr.find(' ', last)) != -1){
    cout << i++ << ": " <<  inStr.substr(last, next-last) << endl;
    *args++ = strdup(inStr.substr(last, next-last).c_str());
    last = next + 1;
}
cout << i++ << ": " << inStr.substr(last) << endl;
*args++ = strdup(inStr.substr(last).c_str());
*args = '\0';
cout << "done tokenizing..." << endl;
}

Upvotes: 1

David Schwartz
David Schwartz

Reputation: 182819

The fork function returns twice, once in the original process and once in the newly-created, forked process. Both of those processes then call tok.

There doesn't seem to be any clear reason why you called fork. So the fix may be as simple as eliminating the call to fork.

Upvotes: 9

Related Questions