Reputation: 25
for my coding assignment, I am having trouble.
The gist of what I want to achieve is to run a program that alternates a variable char OUTPUT between 'A' and 'B' every 1 minute. So the first minute, OUTPUT should be A. The second minute, it'll be B. So on and so forth.
However, if a user inputs the character P, OUTPUT will be P for a minute before returning to the A/B cycle.
I haven't exactly gotten code down yet, because none of my attempts have worked. I've tried using while and for loops. But every time I use scanf or getchar(), the program stops indefinitely to wait for the user input.
void timer(){
int t, d, change;
char p;
for(t = 1; t <= 30000; t++)
for(d = 1; d <= 30000; d++){
if(t == 30000){
change = 1;
}
else if(p == 'p'){
change = 0;
}
else{
p = getchar();
}
is sorta what I have right now. It's a rather incomplete function, but change is supposed to return 1 or 0 and in the main function, if it's 1, the OUTPUT will change to A/B.
I've also done some research and most people recommend multithreading, but we haven't learned that in class, so we can't use that for the program. I also don't have access to sleep() or delay(). Basically I'm restricted to the standard c library.
Upvotes: 2
Views: 2385
Reputation: 84569
If you are still stuck, then here is a short example using pselect
(set to not block, e.g. both fields of struct timespec
set to 0
). It simply uses an infinite loop to check pselect
to determine whether input is waiting to be read on stdin
. If so it reads the input and if the user entered a P
(or any string beginning with P
) P
is output, once per-second for a time period, before the resuming with either A
or B
(whatever was not displayed last before 'P').
I have the time period currently set to 10 sec.
for testing, just adjust the #define PERIOD 10
constant to change to whatever number of seconds you need (e.g. 60
in your case) I wasn't going to watch a minute each worth of A's
, B's
or P's
...
The use of pselect
is fairly straight forward. It is identical to select
except for the timeval
struct select
uses for time and select
has no sigmask
parameter. (irrelevant here) The key is to set both fields of the timespec
struct to 0
so that pselect
will not block waiting for input. You simply call it, and if the return is 1
, then you have input waiting. Then it's just a matter of reading the input (I chose fgets
so it would read and consume the trailing '\n'). Check whether the users entered P
(by simply checking the first character in buf
), if so, then begin a new period outputting P
, otherwise simply continue plodding along with your A
or B
output. There are additional comments inline below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>
#include <unistd.h>
#define MAXC 64 /* size of buffer for fgets */
#define PERIOD 10 /* no. of seconds for alternating period */
/* simple function calling pselect, returns 1 when input waiting */
int haveinput (int filedes)
{
fd_set set;
struct timespec timeout;
/* Initialize the file descriptor set. */
FD_ZERO (&set);
FD_SET (filedes, &set);
/* Initialize the timeout data structure. */
timeout.tv_sec = 0; /* timeout 0 - immediately return, */
timeout.tv_nsec = 0; /* if NULL, blocks indefinitely. */
return pselect (filedes + 1, &set, NULL, NULL, &timeout, NULL);
}
int main (void)
{
int c = 'A',
last = c; /* holds last 'A' or 'B' for pickup after 'P' */
unsigned long begin = time (NULL); /* begin seconds of period */
for (;;) { /* loop until 'q' entered or EOF */
unsigned long current = time (NULL); /* current seconds */
if (haveinput (STDIN_FILENO) == 1) { /* is input ready? */
char buf[MAXC] = ""; /* if so, get it! */
if (!fgets (buf, MAXC, stdin) || *buf == 'q')
break; /* if EOF or 'q' -- bail */
if (*buf == 'P') { /* if user entered 'P' */
c = 'P'; /* set c = 'P' */
begin = time (NULL); /* restart time period */
}
}
else {
putchar (c); /* if no imput read, output char */
fflush (stdout); /* output is buffered so fflush */
sleep (1); /* arbitrary second to wait */
}
if (current - begin >= PERIOD) { /* end of period reached */
if (last == 'A') /* if last was 'A' use 'B' */
c = last = 'B';
else /* otherwise use 'A' */
c = last = 'A';
begin = time (NULL); /* restart time period */
putchar ('\n');
}
}
putchar ('\n');
return 0;
}
(note: this is a 'nix specific solution. Windows does not provide sys/select.h
(nor does MinGW). While windows provides a version of select
through Winsock2.h
and lib Ws2_32.lib
it does not behave consistent with the implementation here.)
Example Use/Output
With an alternating period of 10 sec. instead of 60:
$ ./bin/pselect_abp
AAAAAAAAAAA
BBBBBBBBBBB
AAAAAAP
PPPPPPPPPPP
BBBBBBBBBBB
AAAAAAzz
AAAAA
BBBBBBBBBBB
AAAqA
Give it a try, look things over and let me know if you have further questions.
Upvotes: 1
Reputation: 11020
To do what you need, which is enable user input to change the periodic output, you will need to either:
Since you say you haven't covered threads yet, that's probably not the way you want to go right now, so I would suggest the select route, even though it's not standard C.
Upvotes: 0