/* compile with `gcc -std=gnu99 -Wall -o assign1 main.c` */
/* compile with `gcc -std=gnu99 -Wall -o assign1 main.c` */This assigment is basically the same as the palindrome exercise from CS2 except we add a signal handler to catch Ctrl-C and do the palindrome check repeatedly.
A palindrome for this assignment is any string that reads the same forwards and backwards, ignoring punctuation marks and spaces.
Palindrome Examples:
Counter examples:
/* */Usual includes plus functions for character checks and signal handling.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>/* */This function will check an input string for palindrome-ness.
void check_palindrome(char *string, int length);We have a global atomic flag for signalling to the process that it should exit. The signal handler function only sets this flag and does nothing else.
volatile means that this variable might be changed from different threads
of execution, so the compiler does not optimize it away (we never call
sigint ourselves, done=1 is totally a side effect of the environment).
volatile sig_atomic_t done = 0;
void sigint(int signo) {
done = 1;
}int main()
{First set up an interrupt handler, so we can end the program when the
user presses Ctrl-C. This might look a bit funny because I use a block
({...}) here to visually group the signal initialization code.
struct sigaction act; {
act.sa_handler = sigint;
act.sa_flags = 0;
sigfillset(&act.sa_mask);
}
sigaction(SIGINT, &act, NULL);We only need to look at the first 80 characters of a line.
char buffer[81] = {0};Endless palindrome checking.
while (!done) {%*c swallows the \n at the end of the line, otherwise it remains
in the input buffer and the next scanf call can not read past it.
When the process receives SIGINT, scanf will return EINTR.
if (scanf("%80[^\n]%*c", buffer) < 1) {remove ^C from STDERR (this is purely aesthetics)
fprintf(stderr, "\r");
continue;
}
check_palindrome(buffer, strlen(buffer));
}After receiving the interrupt signal, print a nice exit message.
printf("Exiting...\n");
}This is a basic pointer arithmetic palindrome check, going from both ends of the input string towards the middle until the pointers meet.
void check_palindrome(char *string, int length)
{
int is_palindrome = 1;
char *left = string;
char *right = string + (length - 1);
char a, b;
while (left < right) {
a = *left;
b = *right;skip non-letters
if (!isalpha(a)) {
left += 1;
continue;
}
if (!isalpha(b)) {
right -= 1;
continue;
}make lowercase letters
a = tolower(a);
b = tolower(b);
if (a != b) {
is_palindrome = 0;
break;
}
left += 1;
right -= 1;
}Tell user the result of our check. This should really be in main so our function becomes reusable, but when do you need to check for palindromes anyway, right?
if (is_palindrome) {
printf("is a palindrome\n");
} else {
printf("is not a palindrome\n");
}
}