• main.c

  • §

    Jonas Altrock ew20b126@technikum-wien.at

    To overview.

    • main()
    • check_palindrome()
    /* compile with `gcc -std=gnu99 -Wall -o assign1 main.c` */
  • §

    Assignment 1 - Basic STDIO

    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:

    • Mr. Owl ate my metal worm
    • anna
    • tattarrattat
    • Madam, I’m adam

    Counter examples:

    • Not a palindrome
    • Maybe no on ebay, m?
    /* */
  • §

    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>
  • §

    Prototypes

    /* */
  • §

    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;
    }
  • §

    Main

    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");
    }
  • §

    check_palindrome

    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");
        }
    }