some error(maybe about pointer) when writing shell - c++

what I expect: it will store the last ten commands entered in the terminal. And you can see them when you press ctrl+c. If you want to exit, just press ctrl+d.
So I implemented with queue to store commands. But after 'length = read(STDIN_FILENO, inputBuffer, MAX_LINE);', all the elements in queue are the newest command.(e.g. COMMAND->date queue:date; COMMAND->cal queue:cal cal)
It was normal before the 'read'. But it doesn't help when I replaced it with 'fgets(inputBuffer,MAX_LINE,stdin);'.And in this way, I don't know how to catch 'ctrl+d' because there is no signal corresponding to it(like SIGINT and ctrl+c) so I had to check if the length equals to 0.
how to solve this problem?
#include <signal.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <sys/wait.h>
#include <queue>
using namespace std;
#define BUFFER_SIZE 50
#define MAX_LINE 80 /* 80 chars per line, per command, should be enough. */
struct mes{
char* _args[MAX_LINE/2+1];
int len;
int bg;
int erno;
mes(){
len = 0;
bg = false;
memset(_args,0,sizeof(_args));
}
mes(char* new_args[],int _len,int _bg){
len = _len;
bg = _bg;
for(int i = 0; i < len; ++i){
_args[i] = new_args[i];
}
_args[len] = NULL;
}
void show(){
if(erno==-1) cout<<"ERROR:";
for(int i=0;i<len;i++)
cout<<_args[i]<<" ";
if(bg) cout<<"&"<<endl;
else cout<<endl;
}
~mes(){
memset(_args,0,sizeof(_args));
// for(int i=0; i<len && args[i]; i++){
// delete args[i];
// args[i]=NULL;
// }
// delete[] args;
// args=NULL;
}
};
queue <mes*> rec, quetmp;
static int reclen = 0;
static int totlen = 0;
void readSplit(char inputBuffer[], char *args[], int * background){
int length, /* # of characters in the command line */
i, /* loop index for accessing inputBuffer array */
start, /* index where beginning of next command parameter is */
ct; /* index of where to place the next parameter into args[] */
ct = 0;
if(!rec.empty()){
cout<<"before read"<<endl;
cout<<rec.front()->_args[0]<<endl;
cout<<"size:"<<sizeof(rec.front()->_args[0])<<'\n';
for(int k = 0; k < sizeof(rec.front()->_args[0]); ++k)
cout<<'*'<<rec.front()->_args[0][k]<<endl;
cout<<"end"<<endl;
}
/* read what the user enters on the command line */
// char *tmp = fgets(inputBuffer,MAX_LINE,stdin);
length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
if(!rec.empty()){
cout<<"after read"<<endl;
cout<<rec.front()->_args[0]<<'\n';
cout<<"size:"<<sizeof(rec.front()->_args[0])<<'\n';
for(int k = 0; k < sizeof(rec.front()->_args[0]); ++k)
cout<<'*'<<rec.front()->_args[0][k]<<endl;
cout<<"end"<<endl;
}
start = -1;
if (length == 0){
write(STDOUT_FILENO,inputBuffer,strlen(inputBuffer));//write the last instruction
exit(0); /* ^d was entered, end of user command stream */
}
if (length < 0){
perror("error reading the command");
exit(-1); /* terminate with error code of -1 */
}
/* examine every character in the inputBuffer */
for (i=0;i<length;i++) {
switch (inputBuffer[i]){
case ' ':
case '\t' : /* argument separators */
if(start != -1){
args[ct] = &inputBuffer[start]; /* set up pointer */
ct++;
}
inputBuffer[i] = '\0'; /* add a null char; make a C string */
start = -1;
break;
case '\n': /* should be the final char examined */
if (start != -1){
args[ct] = &inputBuffer[start];
ct++;
}
inputBuffer[i] = '\0';
args[ct] = NULL; /* no more arguments to this command */
break;
default : /* some other character */
if (start == -1)
start = i;
if (inputBuffer[i] == '&'){
*background = 1;
inputBuffer[i] = '\0';
}
}
}
args[ct] = NULL; /* just in case the input line was > 80 */
// mes* pmes = new mes(args, ct, *background);
}
/**
* setup() reads in the next command line, separating it into distinct tokens
* using whitespace as delimiters. setup() sets the args parameter as a
* null-terminated string.
*/
//args end with NULL
//only deal with splitted command
void setup(char inputBuffer[], char *args[],int *background)
{
readSplit(inputBuffer, args, background);
int len = 0;
while(args[len]) ++len;
mes* pmes = new mes(args, len, *background);
int * p_errno=(int*)mmap(NULL,sizeof(int)*2,PROT_READ|PROT_WRITE,\
MAP_SHARED|MAP_ANONYMOUS,-1,0);
int * p_errno;
int pid = fork();
if(pid == 0){
int erno = execvp(args[0], args);
*p_errno = erno;
_exit(0);
}
else{
if(!(*background)){
waitpid(pid, NULL, 0);
}
// }
pmes->erno = 1;
pmes->erno = *p_errno;
if(reclen < 10){
rec.push(pmes);
++reclen;
}
else{
rec.pop();
rec.push(pmes);
}
++totlen;
}
void handle_SIGINT(int sig){// ctrl+c
int num = totlen - reclen, index = 0;
mes* ls[10];
cout<<endl;
while(!rec.empty()){
cout<<++num<<": ";
rec.front()->show();
quetmp.push(rec.front());
ls[index++] = rec.front();
rec.pop();
}
while(!quetmp.empty()){
rec.push(quetmp.front());
quetmp.pop();
}
cout<<"Exit record input \"q\", repeat command,\
input \"r\" or \"r x\"(x is the prefix of command)"<<endl;
char buffer[MAX_LINE];
char *arguments[MAX_LINE/2+1];
int flag;
int exeNum = index - 1;
while(true){
readSplit(buffer, arguments, &flag);
int num_arg = 0;
while(arguments[num_arg]) ++num_arg;
if(num_arg == 0) continue;
if(strcmp(arguments[0], "p") == 0) break;
if(strcmp(arguments[0], "r") != 0){
cout<<"No such command"<<endl;
continue;
}
if(num_arg == 1){
}
else if(num_arg != 2 || strlen(arguments[1]) != 1){
cout<<"invalid input"<<endl;
continue;
}
else{
for(; exeNum >= 0; --exeNum){
if(ls[exeNum]->args[0][0] == arguments[1][0]){
break;
}
}
}
if(exeNum >= 0){
ls[exeNum]->show();
if(ls[exeNum]->erno == -1){
cout<<"It is an error command"<<endl;
}
else{
setup(buffer, ls[exeNum]->args, & (ls[exeNum]->bg));
}
}
}
cout<<"record has quitted"<<endl;
}
int main(void)
{
char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
int background; /* equals 1 if a command is followed by '&' */
char *args[MAX_LINE/2+1];/* command line (of 80) has max of 40 arguments */
// signal(SIGINT,handle_SIGINT);
while (1){ /* Program terminates normally inside setup */
background = 0;
printf("COMMAND->");
fflush(stdout);
// readSplit(inputBuffer, args, &background);
setup(inputBuffer,args,&background); /* get next command */
}
}

Related

Creating a history function for a Unix Shell

Here is what my program currently looks like. I have to add history functionality that gets stored in a file 'mysh.history'. Currently I expect my output to simply append each user command in my shell to the file.
first line of output
first line of output
It only appends the first input into the shell instance. I think my problem lies with my understanding of the fork() process but I'm not sure what is going on. Any suggestions?
#define MYSH_BUFFERSIZE 64
#define MYSH_DELIM " \t\n"
fstream file;
// custom function declarations
int mysh_exit(char **args);
int mysh_add_history(char **args);
int mysh_history(char **);
char byebye[] = "byebye";
char exit_program[] = "exit";
char history[] = "history";
// contains names of all custom shell commands implemented
char *lookup_str[] = {byebye, exit_program, history};
// holds references to all commands in lookup_str[]
// order or commands must match each other
int (*lookup_func[])(char **) = {
&mysh_exit,
&mysh_exit,
&mysh_history
};
/* custom shell commands implementations BEGIN*/
// Without the argument, it prints out the recently typed commands (with their
// arguments), in reverse order, with numbers
// If the argument ā€œ-cā€ is passed, it clears the list of recently typed commands.
void clear_history()
{
file.close();
file.open("mysh.history", ios::trunc);
}
int mysh_add_history(char *line)
{
// if exists then append to the history
if (access("mysh.history", F_OK) == 0)
{
file.open("mysh.history", ios::app);
}
// otherwise create mysh.history and start writing
else
{
file.open("mysh.history", ios::out);
}
file << line << "\n";
return 0;
}
int mysh_history(char **)
{
return 0;
}
int mysh_exit(char **args)
{
return 0;
}
int num_commands()
{
return sizeof(lookup_str) / sizeof(char *);
}
/* custom shell functions END*/
/* main shell processes BEGIN*/
// returns the tokens (arguments) array after tokenizing line from mysh_read_line()
char **mysh_split_args(char *line)
{
int buffer_size = MYSH_BUFFERSIZE;
int current_pos = 0;
char **tokens = (char **)malloc(buffer_size * sizeof(char *));
char *tok;
if (!tokens)
{
printf("mysh: memory allocation error\n");
exit(EXIT_FAILURE);
}
tok = strtok(line, MYSH_DELIM);
while (tok != NULL)
{
tokens[current_pos] = tok;
current_pos++;
if (current_pos >= buffer_size)
{
buffer_size += MYSH_BUFFERSIZE;
tokens = (char **)realloc(tokens, buffer_size * sizeof(char *));
if (!tokens)
{
printf("mysh: memory allocation error\n");
exit(EXIT_FAILURE);
}
}
tok = strtok(NULL, MYSH_DELIM);
}
tokens[current_pos] = NULL;
return tokens;
}
// mysh_read_line allocates MYSH_BUFFER_SIZE of memory to the intial buffer
// it reallocates memory as needed with getLine() function
// returns line to be processed and tokenized by mysh_split_args()
char *mysh_read_line(void)
{
char *line = NULL;
size_t buffersize = 0;
// getLine() also needs to check for EOF after in the case of text files being read.
if (getline(&line, &buffersize, stdin) == -1)
{
if (feof(stdin))
{
exit(EXIT_SUCCESS);
}
else
{
printf("failed to read line\n");
exit(EXIT_FAILURE);
}
}
return line;
}
// args passed comes from mysh_split_args()
int mysh_launch_process(char **args)
{
pid_t pid;
pid_t wpid;
int state;
pid = fork();
// if we enter child process
if (pid == 0)
{
if (execvp(args[0], args) == -1)
{
printf("error in mysh\n");
}
exit(EXIT_FAILURE);
}
// forking failed
else if (pid < 0)
{
printf("error in mysh\n");
}
else
{
// if we enter parent process
do
{
wpid = waitpid(pid, &state, WUNTRACED);
} while (!WIFEXITED(state) && !WIFSIGNALED(state));
}
return 1;
}
// calls mysh_launch_process() and handles programs being called
int mysh_execute(char **args)
{
int i;
if (args[0] == NULL)
{
return 1;
}
for (i = 0; i < num_commands(); i++)
{
if (strcmp(args[0], lookup_str[i]) == 0)
{
if (strcmp(args[0], "history") == 0 && strcmp(args[1], "-c"))
{
clear_history();
}
return (*lookup_func[i])(args);
}
}
return mysh_launch_process(args);
}
void mysh_loop(void)
{
char *line;
char **args;
int state;
do
{
printf("# ");
line = mysh_read_line();
mysh_add_history(line);
args = mysh_split_args(line);
state = mysh_execute(args);
free(line);
free(args);
} while (state);
}
int main(int argc, char **argv)
{
// run main program loop
mysh_loop();
file.close();
return EXIT_SUCCESS;
}
/* main shell processes END*/```

Cannot send serial data from raspberry pi pico ( c sdk )

I'm making a remote controlled machine using a pi pico to drive the motors and read some sensors, and a raspberry pi 4 to send commands to the pi pico via serial and host the web interface.
I am currently testing the operation of the serial from the pi pico. To do this I have connected the pi pico with the raspberry in the following way:
Currently, I am using the following files:
1. main.c to receive and send
2. ring_queue.h where the code for the ring queue is located
main.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/irq.h"
#include "ring_queue.h"
#define UART_ID uart0
#define BAUD_RATE 115200
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY UART_PARITY_NONE
#define UART_TX_PIN 0
#define UART_RX_PIN 1
#define LED_PIN PICO_DEFAULT_LED_PIN
volatile int chars_rxed = 0;
volatile char uCommand[32];
volatile queue *rx_queue;
volatile queue *tx_queue;
void receive_rx(){
while(uart_is_readable(UART_ID)){
char ch = uart_getc(UART_ID);
printf("Got a ch! %c\n", ch);
if(ch != 10){
uCommand[chars_rxed] = ch;
}
printf("Should have added it to uCommand: %s\n", uCommand);
if(uCommand[chars_rxed] == '/'){
printf("End of the command\n");
queue_enqueue((queue*)rx_queue, (char*)uCommand);
memset((char*)uCommand, 0, sizeof(uCommand));
chars_rxed = 0;
break;
}
if(ch != 10) chars_rxed++;
}
}
void send_tx(){
if(queue_empty((queue*)tx_queue) == 1){
return;
}
else{
printf("Trying to send something\n");
char *foo = queue_dequeue((queue*)tx_queue);
uart_write_blocking(UART_ID, (char*)foo, 32);
//printf("%s\n", queue_dequeue((queue*)tx_queue));
}
}
int main(){
stdio_init_all();
memset((char*)uCommand, 0, sizeof(uCommand));
rx_queue = create_queue(32);
tx_queue = create_queue(32);
uart_init(UART_ID, BAUD_RATE);
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
uart_set_hw_flow(UART_ID, false, false);
uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);
uart_set_fifo_enabled(UART_ID, true);
int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;
irq_set_exclusive_handler(UART_IRQ, receive_rx);
irq_set_enabled(UART_IRQ, true);
uart_set_irq_enables(UART_ID, true, false);
while (1){
tight_loop_contents();
if(queue_size((queue*)rx_queue) != 0){
printf("Moving from rx to tx to print the received command\n");
queue_enqueue((queue*)tx_queue, queue_dequeue((queue*)rx_queue));
}
send_tx();
}
}
ring_queue.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
unsigned int tail; // current tail
unsigned int head; // current head
unsigned int size; // current number of items
unsigned int capacity; // Capacity of queue
char** data; // Pointer to array of data
} queue;
queue *create_queue(unsigned int _capacity){
printf("Malloc!\n");
queue *myQueue = malloc(sizeof(queue));
printf("Malloc done!\n");
if (myQueue == NULL ){
printf("Malloc failed!\n");
return NULL;
}
else {
printf("Malloc succeed!\n");
myQueue->tail = -1;
myQueue->head = 0;
myQueue->size = 0;
myQueue->capacity = _capacity;
myQueue->data = malloc(_capacity * sizeof(char*));
return myQueue;
}
}
int queue_empty(queue *q) {
if(q == NULL) return -1;
else if(q->size == 0) return 1;
else return 0;
}
int queue_full(queue *q) {
if(q == NULL) return -1;
else if(q->size == q->capacity) return 1;
else return 0;
}
int queue_enqueue(queue *q, const char *item) {
if (q == NULL) return -1;
else if (queue_full(q) == 1) return 0;
else {
q->tail = (q->tail + 1) % q->capacity;
q->data[q->tail] = strdup(item);
q->size++;
return 1;
}
}
char *queue_dequeue(queue *q) {
if(q == NULL) return NULL;
else if(queue_empty(q) == 1) return '\0';
else {
char *item = q->data[q->head];
q->head = (q->head + 1) % q->capacity;
q->size--;
return item;
}
}
unsigned int queue_size(queue *q) {
if (q == NULL) return - 1;
else return q->size;
}
void free_queue(queue *q) {
for(int i = 0; i < q->capacity; i++) free(q->data[i]);
free(q->data);
free(q);
}
I'm using the usb for debbugging and when I send a simple command (via the arduino IDE) like $MOVE / I can receive it correctly but not send it back as serial, instead with the usb I can ( the printf under the uart_write_blocking).
When I try to send via uart I get random characters on the arduino serial prompt and the pico also seems to receive some of the ones it sent.
What are the random characters on the serial prompt? and what characters do you expect?
The third argument (length) of uart_write_blocking is hardcoded to 32, so this function will always try to send 32 bytes back to the raspberry pi -- that could cause some random characters to show up if the string the pico is trying to send is actually less than that. I'd try changing this code snippet to this and see if that stops the random characters.
printf("Trying to send something\n");
char *foo = queue_dequeue((queue*)tx_queue);
uart_write_blocking(UART_ID, (char*)foo, strlen(foo)); // only send as many bytes as are in the string

How to convert int type number/letter to char and *char?

I am using LittleFS library and ESP32 on arduino IDE.
I am reading a file using the example readFile function of LittleFS but I am trying to convert it for my needs.
The text written to the file is of this form:
LettersAndNumbersMax30&LettersAndNumbersMax30&00&00&01&01
Seperated by &. 2 text values of max 30 characters and 4 integers.
I want to build:
char *mytest1 containing the first text
char *mytest2 containing the second text
int mytest3 containing the first integer (2digits)
int mytest4 containing the second integer (2digits)
int mytest5 containing the third integer (2digits)
int mytest5 containing the forth integer (2digits)
file.read() returns and integer always. for example 38 for &.
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\r\n", path);
File file = fs.open(path);
if(!file || file.isDirectory()){
Serial.println("- failed to open file for reading");
return;
}
Serial.println("- read from file:");
while(file.available()){
Serial.write(file.read());
}
file.close();
}
Its fairly straightforward. Test each byte read and act accordingly. Code below doesn't handle signs nor negative numbers. It also doesn't check if there are only digits for integers in the file.
#include ....
struct record_t
{
char myState1[31];
char myState2[31];
int myState3;
int myState4;
int myState5;
int myState6;
};
record_t record;
bool readFile(fs::FS &fs, const char * path);
void setup()
{
// ...
}
void loop()
{
//...
if (readFile(/*...*/))
{
Serial.printf("file reads OK\r\n");
//...
}
}
bool readFile(fs::FS &fs, const char * path)
{
Serial.printf("Reading file: %s\r\n", path);
File file = fs.open(path);
if (!file || file.isDirectory())
{
Serial.println("- failed to open file for reading");
return;
}
Serial.println("- read from file:");
int state = 0;
int index = 0;
// clear record.
record.myState1[0] = 0;
record.myState2[0] = 0;
record.myState3 = 0;
record.myState4 = 0;
record.myState5 = 0;
record.myState6 = 0;
bool valid = false;
for (int i = file.read(); i != -1; i = file.read())
{
char c = i & 0xFF;
Serial.write(c); // file.read() returns an int, that's why Serial.write()
// was printing numbers.
switch(state)
{
case 0:
if (index > sizeof(record.myState1) - 1) // avoid buffer overflow
index = sizeof(record.myState1) - 1;
if (c != '&')
{
record.myState1[index++] = c;
}
else
{
record.myState1[index] = 0;
++state;
index = 0;
}
break;
case 1:
if (index > sizeof(record.myState2) - 1) // avoid buffer overflow
index = sizeof(record.myState2) - 1;
if (c != '&')
{
record.myState2[index++] = c;
}
else
{
record.myState2[index] = 0;
++state;
index = 0;
}
break;
case 2:
if (c != '&')
record.myState3 = record.myState3 * 10 + (c - '0');
else
++state;
break;
case 3:
if (c != '&')
record.myState4 = record.myState4 * 10 + (c - '0');
else
++state;
break;
case 4:
if (c != '&')
record.myState5 = record.myState5 * 10 + (c - '0');
else
++state;
break;
case 5:
valid = true;
if (c != '&')
record.myState6 = record.myState6 * 10 + (c - '0');
else
++state;
break;
default: // reaching here is an error condition? You decide.
return false;
}
}
file.close();
if (!valid)
{
// clear record.
record.myState1[0] = 0;
record.myState2[0] = 0;
record.myState3 = 0;
record.myState4 = 0;
record.myState5 = 0;
record.myState6 = 0;
}
return valid;
}
file.read returns integer. So the integer is printed.
You to convert it to the string.
while(file.available()){
char s[2] = {0};
s[0] = file.read();
Serial.write(s);
}

Multiple Pipes, C++

I've been stuck on an issue with my program and just hoping for any help at this point :(
or guidance towards the right direction. In my code, I'm implenting a mini shell in c++ where the user can pipe 2 or more processes together, yet an issue keeps coming up whenever I execute it. Only the first and last commands actually execute so say I run:
cat b.txt | sort | tail -2
only cat b.txt and tail -2 would execute.
Here is my attempt at the whole program, also referenced to this which helped me tremendously with the setup.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>
using namespace std;
//this variable will take in the line of input submitted by the user
char buf[1024];
//PIDs for the two child processes
pid_t pid[300];
//these will be use to check the status of each child in the parent process
int status;
int status2;
int pid_num = 1;
//initializes the pipe
int pipeA[2] = {-1,-1};
int g = 0;
void first_command(int pipeA[], char * command[], bool pipeExists){
if(pipeExists){
dup2(pipeA[1], 1);
close(pipeA[0]);
}
// this will run command[0] as the file to execute, and command as the arg
execvp(command[0], command);
printf("Can not execute FIRST command, please enter a valid command \n");
exit(127);
}
void other_command(int pipeA[], char * command0[], int index){
dup2(pipeA[0], 0);
close(pipeA[1]);
execvp(command0[0], command0);
printf("Can not execute SECOND command, please enter a valid command\n");
exit(127);
}
void main_func() {
//stay inside the loop and keep asking the user for input until the user quits the program
while (fgets(buf,1024,stdin) != NULL){
//initialize a boolean to check if user wants to pipe something, set to false by default until we check with user
bool pipeExists = false;
//initialize this arrays to NULL so anything that store in them gets cleared out.
//these arrays will hold the commands that the user wants to carry out.
char * command[1024] = {NULL, NULL, NULL};
char *command0[1024] = {NULL, NULL, NULL};
char *command1[] = {NULL, NULL, NULL};
char *command2[] = {NULL, NULL, NULL};
char *command3[] = {NULL, NULL, NULL};
char ** my_commands[] = {
command0,
command1,
command2,
command3,
NULL
};
//Important to delete mark the last byte as 0 in our input
buf[strlen(buf) -1] = 0;
//initialize this number to zero to start save the tokens at this index
int index = 0;
//a char * to hold the token saved by strtok
char * ptr;
ptr = strtok(buf, " \"");
//Loop through 'buf' and save tokens accordingly
while(ptr != NULL){
// if the user types exit at any moment, the program will exit gracefully and terminate
if(strcmp( ptr, "exit" ) == 0){
exit(0);
}
//if ptr is equal to | user wants to pipe something and we change pipeExists to true
if(strcmp( ptr, "|" ) == 0){
pipeExists = true;
index= 0;
ptr = strtok(NULL, " ");
}
//enter here while user doesnt want to user pipes
if(!pipeExists){
command[index] = ptr;
ptr = strtok(NULL, " ");
index++;
}
//enter here if user want to use pipes
if(pipeExists){
command0[index] = ptr;
ptr = strtok(NULL, " ");
index++;
}
g++;
printf("%s %i\n", ptr, g);
}
for (int s = 0; my_commands[s] != NULL; s++) {
cout << command0[s] << " \n" << endl;
}
//if pipes exists then initialize it
if(pipeExists){
pipe(pipeA);
}
//create first child
if ((pid[0] = fork()) == 0) {
//pass in the pipe, commands and pipe to function to execute
first_command(pipeA, command, pipeExists);
}
else if(pid[0] < 0){
//error with child
cerr<<"error forking first child"<<endl;
}
// if pipe exists create a second process to execute the second part of the command
if(pipeExists){
for(int f = 0; my_commands[f] != NULL; f++) {
//create second child
if ((pid[f] = fork()) == 0) {
other_command(pipeA, command0, index);
}
else if(pid[f] < 0){
//error with second child
cerr<<"error forking child "<< pid_num << endl;
}
}
pid_num++;
}
//if the pipe was created then we close its ends
if(pipeExists){
for(int z = 0; z < pid_num; z++) {
close(pipeA[z]);
}
}
//wait for the first child that ALWAYS executes
if ( (pid[0] = waitpid(pid[0], &status, 0)) < 0)
cerr<<"error waiting for first child"<<endl;
//wait for the second child but only if user wanted to created to use piping
if(pipeExists){
for(int j = 1; j < pid_num; j++) {
if ( (pid[j] = waitpid(pid[j], &status2, 0)) < 0){
printf("Status: %d", pid[j]);
cerr<<"error waiting for child " << j <<endl;
}
}
}
pid_num = 1;
}//endwhile
}

Reference cannot be initialized/expression must have type class

I'm doing a quick binary tree program as a homework, but I am getting weird errors that I can't seem to figure out how to fix. Normally I'm programming in C#, and C is just slightly different but different enough for me to get confused.
Here is the code that is giving the error:
void SortArray() {//bubble sorting by float value of 'b'
int flag = 0;
do {
flag = 1;
for (int i = 0; i < arraySize - 1; i++)
{
if (stubList[i].b > stubList[i + 1].b) {
Swap(stubList[i], stubList[i + 1]);
flag = 0;
}
}
} while (flag == 0);
printf("Sorted by value of variable 'b'"); _getch(); _getch();
}
And here is the whole script:
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
struct stub
{
char crown[51];//some custom name - can be empty
float b;//comparable value for tree sort
int c;//limited by maxint
stub *l;//left node(normally smaller "b" value than this node)
stub *r;//right node(normally bigger "b" value than this node)
};
stub *stubList[255];//empty list of a stub array with a safe casual amount
int arraySize = 0;
stub *head = NULL;//main stub(first)
stub *latest = NULL;//latest stub
stub *st = NULL;//used for creating and checking
FILE *fs = NULL;
char fileName[255];
int maxint = 20;//for var 'c'
void BTreeNodeToArray(stub *s) {
stubList[arraySize] = s;
arraySize++;
}
void Swap(stub &s1, stub &s2) {
stub temp = s2;
s1 = s2;
s2 = temp;
}
int MaxMin(int num) {
int clampedInt = num;
if (num < 0) clampedInt = 0;
else if (num > maxint) clampedInt = maxint;
return clampedInt;
}
//Create a completely new stub with crown, b, and c variables being filled here
void CreateElement() {
st = new stub;
printf("Adding information for node:\n");
printf("Node name: "); gets_s(st->crown);
printf("\n");
float f;
printf("Node float value (B): "); scanf_s("%f", &f);
st->b = f;
printf("\n");
int d;
printf("Node integer value (C): "); scanf_s("%d", &d);
st->c = d;
printf("\n");
st->c = MaxMin(st->c);
st->l = NULL;
st->r = NULL;
}
//creates the very first stub(root/head)
void CreateFirst() {
printf("First in tree. Adding root node...\n");
CreateElement();
head = st;
latest = head;
BTreeNodeToArray(head);
printf("Added head stub\ncrown: %s\nValue: %f\nExtra: %d", head->crown, head->b, head->c);
getchar();
getchar();
}
void AddStub() {
if (head == NULL) {
CreateFirst();
}
else {
CreateElement();//create newest node
latest = st;
st = head;
int depth = 0;
while (1) {
if ((latest->b <= st->b)) {//choose left if true
printf("Went left\n");
depth++;
if (st->l == NULL) {//node free, assign here
printf("Node assigned at depth %d\n", depth);
st->l = latest;
BTreeNodeToArray(latest);
getchar();
getchar();
break;
}
else {//loop again with next node
//printf("New loop (left)\n");
st = st->l;
}
}
else {//choose right
printf("Went right\n");
depth++;
if (st->r == NULL) {//node free, assign here
printf("Node assigned at depth %d\n", depth);
st->r = latest;
BTreeNodeToArray(latest);
getchar();
getchar();
break;
}
else {//loop again with next node
//printf("New loop (right)\n");
st = st->r;
}
}
}
}
}
void ViewArray() {
for (int i = 0; i < arraySize; i++)
{
printf_s("Node [%d]:\n\tCrown: %s\n\tweight: %f\n\tExta value(0 - %d): %d\n", i, stubList[i]->crown, stubList[i]->b, maxint, stubList[i]->c);
}
getchar();
}
void SortArray() {//bubble sorting by float value of 'b'
int flag = 0;
do {
flag = 1;
for (int i = 0; i < arraySize - 1; i++)
{
if (stubList[i].b > stubList[i + 1].b) {
Swap(stubList[i], stubList[i + 1]);
flag = 0;
}
}
} while (flag == 0);
printf("Sorted by value of variable 'b'"); _getch(); _getch();
}
void ProcessArray() {
char c = ' ';
int found = 0;
printf("Process with character: \n"); c = _getch();
if (arraySize <= 0) {
printf("No List!");
return;
}
char chkstr[5];
for (short i = 0; i < 5; i++)//simple assign to a 'string' 5 times
{
chkstr[i] = c;
}
for (int i = 0; i < arraySize; i++)
{
if (strstr(stubList[i]->crown, chkstr) != NULL) {
// contains
printf("B = %f at [%d] \n", stubList[i]->b, i);
found++;
}
}
if (found > 0) {
printf("---Found: %d with character %c---", found, c);
}
else {
printf("No elements found with '%c'", c);
}
getchar();
}
void ExportArray() {
FILE *fs = NULL;
char fileName[255];
errno_t err;
printf("Save to file as: \n"); gets_s(fileName);
if (strlen(fileName) == 0) {
printf("Failed to create file. File name empty!");
_getch();
_getch();
}
err = fopen_s(&fs, fileName, "wb");
if (err != 0) {
printf("Failed to create file!!!");
_getch();
_getch();
return;
}
for (int i = 0; i < arraySize; i++)
{
int written = fwrite(&stubList[i], sizeof(stub), 1, fs);
//fwrite(&gr[i], sizeof(student), 1, fs);
}
int numclosed = _fcloseall();
printf("Exported to file: %s", fileName);
getchar();
}
void CleanReset() {//reset all values and release memory (function used for import)
for (int i = 0; i < arraySize; i++)
{
delete stubList[i];
}
arraySize = 0;
st = NULL;
head = NULL;
latest = NULL;
}
void ImportArray() {
FILE *fs = NULL;
char fname[255];
errno_t err;
printf("Open FIle: "); gets_s(fname);
err = fopen_s(&fs, fname, "rb");
if (err == 0) {
CleanReset();
fseek(fs, 0, SEEK_END);
long size = ftell(fs);
arraySize = size / sizeof(stub);//get amount of students saved
fseek(fs, 0, SEEK_SET);
int i = 0;
st = new stub;
fread_s(&st, sizeof(stub), sizeof(stub), 1, fs);
stubList[i] = st;
while (!feof(fs)) {
i++;
st = new stub;
fread_s(&st, sizeof(stub), sizeof(stub), 1, fs);
stubList[i] = st;
}
printf("File data imported. Size: %d", arraySize);
getchar();
return;
}
printf("Failed to import file!!!");
getchar();
}
void main()
{
system("chcp 65001");//use utf8
char izb = 'i';
while (izb != '0') {
system("cls");
printf_s("1. Add stub\n");
printf_s("2. View Array\n");
printf_s("3. Sort Array\n");
printf_s("4. Process\n");
printf_s("5. Export array to file\n");
printf_s("6. Import array from file\n");
printf_s("0. Exit\n\n");
printf_s("Choose action:\n"); izb = _getch();
switch (izb)
{
case '1':
AddStub();
break;
case '2':
ViewArray();
break;
case '3':
SortArray();
break;
case '4':
ProcessArray();
break;
case '5':
ExportArray();
break;
case '6':
ImportArray();
break;
case '0':
//Exit();
break;
}
}
}
The error is that you want to pass a stub * to a function that wants a stub &. The first one is a pointer, the second one is a reference.
You have two options.
First option (imho recommended):
Change your swap function to accept pointers instead of references.
void Swap(stub *s1, stub *s2) {
stub temp = *s2;
*s1 = *s2;
*s2 = temp;
}
Second option:
Dereference the parameters before passing to swap:
Swap(*(stubList[i]), *(stubList[i + 1]));
You have to undestand that the datatype in your list is a pointer to stub, the function Swap wants a reference, which are different things in C++.
For a better understanding I recommend reading this: https://www.geeksforgeeks.org/pointers-vs-references-cpp/