Browsing posts in: Code

Word Counting Function Implemented in C

I recently completed an assignment for my Modern Operating Systems class where the teacher asked us to develop a program written in C that counts the number of words in a text file that is given as the first parameter. I haven’t used the C language in over 15 years, so this was an exciting challenge. Especially because I had to implement linked lists in C. My previous experience with linked lists was in OCaml and C# where they were basic types that were included in the languages. Needing to implement them myself really solidified my knowledge of them.

My next assignment is to create a simple shell that only uses the following functions:

  • malloc
  • free
  • exit
  • fgetc
  • fputc
  • fputs
  • fprintf
  • sprintf
  • snprintf
  • vsprintf
  • vsnprintf
  • gettimeofday
  • strerror

It is pretty exciting that we will be developing an operating system for an ARM processor as the project in our class. This will be a challenge I’ve wanted to tackle for a while. I’ve been reading the source to bash and csh, something I would not have thought to do previously. I don’t fully understand everything in the source, but I’m definitely seeing how it is put together and various properties like file descriptors and pipes are handled helps me understand the types of data structures I may want to use.

If I had to do this assignment over again, I would have implemented linked lists for every character array so the lengths of “strings” (character arrays) could be bound only by memory limitations. Right now the code also would split a word longer than 4096 characters into two words (and not leave the 4096 character word null terminated which is a no-no).

//includes
#include <stdio.h>
#include <stdlib.h> // For exit() function
#include <unistd.h> //for F_OK, https://www.gnu.org/software/libc/manual/html_node/Testing-File-Access.html
#include <string.h> //for string.h

//macro definitions
#define FILENAME_POSITION 1
#define MAX_WORD_LENGTH 256
#define DEBUG_MODE 0

//type definitions
//I learned how to use linked lists in c from here: https://www.zentut.com/c-tutorial/c-linked-list/
typedef struct node{
	int count;
	char word[MAX_WORD_LENGTH];
	struct node *next;
} node_t;

//function prototypes
int main(int argc, char *argv[]);
int validate_input(int argc, char *argv[]);
void display_usage();
void process_file(char *argv[]);
void output_line(char line[], int data);
void push(node_t * head, int count, char word[]);
void print_list(node_t * head);

//function definitions
int main(int argc, char *argv[])
{
	validate_input(argc, argv);
	process_file(argv);
	return(0);
}

int validate_input(int argc, char *argv[])
{
	if(argc < 2) { display_usage(); exit(-3); } //https://stackoverflow.com/a/230068/1330074 if(access(argv[FILENAME_POSITION], F_OK) != -1) { //puts("file exists!"); } else { puts("file doesn't exist!"); exit(-2); } return 0; } void display_usage() { puts("word-count usage information:\nexample: word-count filename.txt"); } void process_file(char *argv[]) { FILE *fp; //i would like to implement this buffer as a linked list so there wouldn't be this hardcoded limit but time did not allow int buffer_size = 4096; char line[buffer_size]; fp = fopen(argv[FILENAME_POSITION], "r"); if(fp == NULL) { perror("Error opening file! Exiting program"); exit(-1); } int number_of_lines = 0; node_t* head = NULL; head = malloc(sizeof(node_t)); if (head == NULL) { puts("Unable to create head node! Terminating."); exit(-5); } while(fgets (line, buffer_size, fp) != NULL) { //fputs(line, stdout); char *token; //learned to use strtok from https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm token = strtok(line, " \n\r\t"); while( token != NULL ) { //printf( " %s\n", token ); push(head, 1, token); token = strtok(NULL, " \n\r\t"); } number_of_lines++; } output_line("Lines: ", number_of_lines); print_list(head); fclose(fp); //output_line("Lines: ", count(first)); } void output_line(char line[], int data) { printf("%s ", line); printf("%d\n", data); } void push(node_t * head, int count, char word[]) { if(DEBUG_MODE == 1) { printf("Now adding %s to the linked list...\n", word); } node_t * current = head; int word_already_in_list = 0; while (current->next != NULL)
    {
		if(strcmp(current->word, word) == 0)
		{
		    if(DEBUG_MODE == 1)
			{
				printf("%s is equal to %s, updating the count!\n", word, current->word);
			}
			
			word_already_in_list = 1;
			current->count++;
			break;
		}
		else
		{
		    if(DEBUG_MODE == 1)
			{
				printf("%s is NOT equal to %s, still looking...\n", word, current->word);
			}

		}

        current = current->next;
    }

	if(strcmp(current->word, word) == 0)
	{
	    if(DEBUG_MODE == 1)
		{
			printf("%s is equal to %s, updating the count!\n", word, current->word);
		}
		
		word_already_in_list = 1;
		current->count++;
	}
	else
	{
	    if(DEBUG_MODE == 1)
		{
			printf("%s is NOT equal to %s, need to add it to the list!\n", word, current->word);
		}
	}

	if(word_already_in_list == 0)
	{
	    current->next = malloc(sizeof(node_t));
	    current->next->count = count;
		strcpy(current->next->word, word);
	    current->next->next = NULL;
	}

}

void print_list(node_t * head)
{
    node_t * current = head;
    unsigned int number_of_words = 0;
    puts("Word count:");
    while (current != NULL)
    {
        if(current->count != 0)
        {
	        printf("%s: %d\n", current->word, current->count);
	        number_of_words = number_of_words + current->count;
    	}
    	current = current->next;
    }

    printf("Words: %d\n", number_of_words);
}

Pattern Matching in C# 7

Pattern matching is a powerful way to check the value and type of a variable at run time while also deconstructing the value being matched on so it can be used if needed. This can be more useful when developing software using functional programming techniques. They arise from functional programming’s disjoint unions/algebraic data types and are used to manipulate the control flow of a function.

C# 7 introduced pattern matching in switch statements. Previously it was only possible to check the value of a variable against a constant value. Consider the standard switch statement below:

public static void SwitchStatementNoMatching()
{
     var x = 1;
     switch (x)
     {
          case 1:
          Console.WriteLine("The value is 1!");
          break;
          case 2:
          Console.WriteLine("The value is 2!");
          break;

          default:
          Console.WriteLine("No action defined for the value provided!");
          break;
     }
}

First a variable x is defined as the integer value 1. Then the switch statement compares the value of x against the integer values 1 or 2. If x is not 1 or 2 the default case is reached.

In the pattern matching example below, notice that the behavior of the switch statement depends on not only the value of the variable, but the type as well.

public static void SwitchStatementWithMatching(object x)
{
     switch (x)
     {
          case int newInt32x:
          Console.WriteLine("The value is {0} and it is an integer!", newInt32x);
          break;</pre>
<pre>          case string newStringx:
          Console.WriteLine("The value is {0} and it is a string!", newStringx);
          break;

          default:
          Console.WriteLine("No action defined for the variable provided!");
          break;
     }
}

The switch statement above is very similar to the first example with some minor syntactic changes. The switch statement is operating on the value x that is passed in to the function, but this time it is unknown if the variable x will be a string or integer (or other type). The switch checks to see if the x is an int and also defines a new integer variable that will be defined if that particular case statement matches.

In addition to checking the type of a variable in the match expression, a when clause can be added to also check the value of the variable.

public static void SwitchStatementWithMatchingAndWhen(object x)
{
     switch (x)
     {
          case int newInt32x when newInt32 == 1:
          Console.WriteLine("The value is {0} and it is an integer!", newInt32x);
          break;</pre>
<pre>          case string newStringx when newStringx == "Hello World!":
          Console.WriteLine("The value is {0} and it is a string!", newStringx);
          break;

          default:
          Console.WriteLine("No action defined for the variable provided!");
          break;
     }
}

In this example the switch statements are not only checking the type of x (integer or string) but also the values (1 or “Hello World!”).

One thing to keep in mind when using pattern matching like this is the order of the case statements become much more important. For example, if the first case statement checks for all integers and then the second checks for an integer whose value is 1, the second case statement would never be reached because it would be caught by the first.


Resources for Learning OCaml Concepts

I’m taking a software engineering course called Abstraction and Design in Computing (CSCI E-51 or CS51) this semester. The class teaches functional programming concepts using the language OCaml among other topics. One of the things that makes this a difficult class so far is the lack of online documentation and discussion of the language.

In fact, that is the reason for this post.

I wanted to provide a list of resources that I’ve found useful in learning OCaml so hopefully they are useful to others as well. I’ll continue to update this list as I find more resources.


HackerRank.com 30 Days of Code – Day 3: Intro to Conditional Statements

Here is my solution to HackerRank.com’s 30 days of code challenge, day 3. This is a basic introduction to conditional statements which I found a bit easy. My main take away from this was ensuring the quality of the input by making sure that the the input values were within the correct range and wrapping that conditional statement around the other application logic statements. It doesn’t make sense to continue on processing the input if it is not within the acceptable bounds.

import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
   
   public static void main(String[] args) {
      Scanner scan = new Scanner(System.in);
      int n = scan.nextInt(); 
      scan.close();
      String ans="";
      
      //make sure n is within the constraints (between 1 and 100 inclusive)
      if( n < 1 || n > 100){
          ans="";
      }
      else
      {
          // if 'n' is NOT evenly divisible by 2 (i.e.: n is odd)
          if(n%2==1){
             ans = "Weird";
          }
          else //cover all of the even cases
          {
             //if n is between 2 and 5 inclusive 
             if(n >= 2 && n <= 5){ ans = "Not Weird"; } //if n is between 6 and 20 inclusive if(n >= 6 && n <= 20){ ans = "Weird"; } //if n is greater than 20 if(n > 20){
                 ans = "Not Weird";
             }
              
             /*
             If  is even and in the inclusive range of 2 to 5, print Not Weird
             If  is even and in the inclusive range of 6 to 20, print Weird
             If  is even and greater than 20, print Not Weird
             */
          }   
      }
       

      System.out.println(ans);
   }
}

HackerRank.com 30 Days of Code – Day 2: Operators

Day 2 of HackerRank’s 30 days of code was a fairly simple task designed to teach operators.

import java.util.*;
import java.math.*;

public class Arithmetic {

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        double mealCost = scan.nextDouble(); // original meal price
        int tipPercent = scan.nextInt(); // tip percentage
        int taxPercent = scan.nextInt(); // tax percentage
        double totalCostOfMeal = 0;
        double tipCost = 0;
        scan.close();
      
        // Write your calculation code here.
        totalCostOfMeal = (mealCost + (mealCost * (tipPercent/100))) * ((taxPercent/100) + 1);
        //System.out.println("mealCost: " + mealCost);
        //System.out.println("tipPercent: " + (((float)tipPercent/100) + 1));
        //System.out.println("taxPercent: " + (((float)taxPercent/100) + 1));
        tipCost = (((float)tipPercent/100) * mealCost);
        //System.out.println("tipCost: " + tipCost);
        totalCostOfMeal = (mealCost*(((float)taxPercent/100) + 1)) + tipCost;
        //System.out.println("totalCostOfMeal: " + totalCostOfMeal);
        
      
        
        // cast the result of the rounding operation to an int and save it as totalCost 
        int totalCost = (int) Math.round(totalCostOfMeal);
      
        // Print your result
        System.out.println("The total meal cost is " + totalCost + " dollars.");
    }
}

HackerRank.com Challenge – Diagonal Difference

This HackerRank challenge took some thinking. I needed to be able to accept a variable size multidimensional array, add the diagonals, and then find the absolute value of their difference. I haven’t needed to work with multidimensional arrays much in the past, so it took some working through the algorithm to ensure I was incrementing my values in the correct spots.

These challenges are great mental floss for coding while I learn Java.

 

import java.io.*;
import java.util.*;
import java.lang.Math;

public class Solution {

    public static void main(String[] args) {
        /* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution. */
        Scanner in = new Scanner(System.in);
        
        //get the value that defines the size of the input matrix
        int n = in.nextInt();
        
        int[][] numberArray = new int[n][n];
        
        String input = in.nextLine();;
        
        int currentDiagnalPosition1 = 0, currentDiagnalPosition2 = n-1;
        int runningTotal1 = 0, runningTotal2 = 0;
        
        for(int j = 0; j < n; j++)
        {       
            input = in.nextLine();
            
            for(int k = 0; k < n; k++)
            {
                String[] data = input.trim().split("\\s+");
                
                numberArray[j][k] = Integer.parseInt(data[k]);
                
                if(currentDiagnalPosition1 == k)
                {
                    runningTotal1 = runningTotal1 + numberArray[j][k];
                }
                if(currentDiagnalPosition2 == k)
                {
                    runningTotal2 = runningTotal2 + numberArray[j][k];
                }                
                
            } 
            currentDiagnalPosition1 = currentDiagnalPosition1 + 1;
            currentDiagnalPosition2 = currentDiagnalPosition2 - 1;
        }
        
        System.out.println(Math.abs(runningTotal1-runningTotal2));
       
    }
}

HackerRank.com Challenge – A Very Big Sum

In this lesson on HackerRank, I was challenged to demonstrate my knowledge of the long data type by needing to add multiple large numbers that would have caused an integer to overflow.

import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;

public class Solution {

    static long aVeryBigSum(int n, long[] ar) {
        //Setup space on the heap to store our running total
        long total = 0;
        
        //Iterate over each element in array ar adding the value to the running total in total
        for(long number : ar)
        {
            total = total + number;
        }
        
        //return the sum contained in total
        return total;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        long[] ar = new long[n];
        for(int ar_i = 0; ar_i < n; ar_i++){
            ar[ar_i] = in.nextLong();
        }
        long result = aVeryBigSum(n, ar);
        System.out.println(result);
    }
}

HackerRank.com Challenge – Compare the Triplets

I recently completed the HackerRank.com Challenge “Compare the Triplets”. Below is the answer I submitted.

import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;

public class Solution {

    static int[] solve(int a0, int a1, int a2, int b0, int b1, int b2){
        // Complete this function
        
        int score_a = 0;
        int score_b = 0;
        
        //verify all numbers are in the appropriate range.
        if(a0 >= 1 && a0 <= 100 && 
           a1 >= 1 && a1 <= 100 && 
           a2 >= 1 && a2 <= 100 && 
           b0 >= 1 && b0 <= 100 && 
           b1 >= 1 && b1 <= 100 && 
           b2 >= 1 && b2 <= 100)
        {
            //System.out.println("All numbers in valid range");
            
            //tabulate score for a0/b0
            if(a0 > b0) 
            {
                score_a++;
            }
            else if(a0 < b0)
            {
                score_b++;
            }

            //tabulate score for a1/b1
            if(a1 > b1) 
            {
                score_a++;
            }
            else if(a1 < b1) 
            {
                score_b++;
            }              
            //tabulate score for a2/b2
            if(a2 > b2) 
            {
                score_a++;
            }
            else if(a2 < b2) 
            {
                score_b++;
            }
                    
            int[] number = {score_a, score_b};
            return number; 
        }
        else
        {
            System.out.println("The input needs to be between 1 and 100. Please correct the input and try again.");
            int[] number = {0, 0};
            return number; 
        }

    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int a0 = in.nextInt();
        int a1 = in.nextInt();
        int a2 = in.nextInt();
        int b0 = in.nextInt();
        int b1 = in.nextInt();
        int b2 = in.nextInt();
        int[] result = solve(a0, a1, a2, b0, b1, b2);
        for (int i = 0; i < result.length; i++) {
            System.out.print(result[i] + (i != result.length - 1 ? " " : ""));
        }
        System.out.println("");
        

    }
}

HackerRank.com Challenge – Simple Array Sum

Here is my submission for HackerRank.com’s Simple Array Sum challenge. In it I used a foreach loop to add all of the values located in an array and return the result.

import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;

public class Solution {

    static int simpleArraySum(int n, int[] ar) {
        // Complete this function
        int runningTotal = 0;
        
        for(int number : ar)
        {
            runningTotal = runningTotal + number;    
        }
        
        return runningTotal;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] ar = new int[n];
        for(int ar_i = 0; ar_i < n; ar_i++){
            ar[ar_i] = in.nextInt();
        }
        int result = simpleArraySum(n, ar);
        System.out.println(result);
    }
}

HackerRank.com 30 Days of Code – Day 1: Data Types

Recently I’ve been going through the HackerRank.com 30 Days of Code course to learn Java. Below is my code for their Day 1 lesson.

After reviewing the code I think I would prefer to add some data type checking to ensure that the data accepted from scan.nextLine() is actually the data type that I expect. It passed the unit tests provided by HackerRank but I doubt this would pass negative testing in a Test Driven Development organization.

import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;

public class Solution {
	
    public static void main(String[] args) {
        int i = 4;
        double d = 4.0;
        String s = "HackerRank ";
		
        Scanner scan = new Scanner(System.in);

        /* Declare second integer, double, and String variables. */
        int j;
        double e;
        String t;

        /* Read and save an integer, double, and String to your variables.*/
        j = Integer.parseInt(scan.nextLine());
        e = Double.parseDouble(scan.nextLine());
        t = scan.nextLine();

        /* Print the sum of both integer variables on a new line. */
        System.out.println(i + j);

        /* Print the sum of the double variables on a new line. */
        System.out.println(d + e);
        
        /* Concatenate and print the String variables on a new line; 
        	the 's' variable above should be printed first. */
        System.out.println(s + t);
        scan.close();
    }
}