Skip to content

Instantly share code, notes, and snippets.

@jacobwalkr
Last active July 21, 2016 00:35
Show Gist options
  • Save jacobwalkr/58f166a9e8dc3816b3412e726b56989e to your computer and use it in GitHub Desktop.
Save jacobwalkr/58f166a9e8dc3816b3412e726b56989e to your computer and use it in GitHub Desktop.
C solution for Simple Text Editor on HackerRank
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define APPEND 1
#define DELETE 2
#define PRINT 3
#define UNDO 4
#define MAX_INPUT 1000000
/**
* Exits with an error if ptr is null
*/
void ensure(void *ptr) {
if (ptr == NULL) {
printf("Memory allocation failed :(");
exit(EXIT_FAILURE);
}
}
// Need to declare action_t beforehand. Might as well do both!
typedef struct action_t action_t;
typedef struct state_t state_t;
/**
* An action describes an APPEND or DELETE operation. *deleted holds the characters that were
* removed by a DELETE operation. word_length holds the length of characters either added or
* deleted. operation is either APPEND or DELETE. *previous holds a reference to the next action
* in the reverse-chronological linked list.
*/
struct action_t {
char *deleted;
int word_length;
int operation;
action_t *previous;
};
/**
* The "top" of the linked list. Maintains a reference to the list and a count of the items in it
*/
struct state_t {
char *string;
int string_length;
action_t *last_action;
};
/**
* Add to the string - returns the number of characters added
*/
int Append(state_t *state, const char *word) {
int word_length = strlen(word);
// Add space for new string
state->string = realloc(state->string,
(sizeof(char) * (strlen(state->string) + word_length + 1)));
ensure(state->string);
// Copy the new string in (includes null terminator)
strcpy(&(state->string[strlen(state->string)]), word);
return word_length;
}
/**
* Delete from the string - returns the string deleted
*/
char *Delete(state_t *state, int count) {
// Copy out deleted chars - leave space for the null terminator!
char *deleted_string = malloc(sizeof(char) * (count + 1));
int delete_from = strlen(state->string) - count;
strncpy(deleted_string, &(state->string[delete_from]), count + 1);
// Shrink state string and replace null terminator
state->string = realloc(state->string, strlen(state->string));
ensure(state->string);
state->string[delete_from] = '\0';
return deleted_string;
}
/**
* Utility function to wrap strtol and return an int
*/
int ParseIntArg(char *arg) {
char *endptr;
return strtol(arg, &endptr, 10);
}
/**
* Perform an APPEND or DELETE action and update the history
*/
void DoStringAction(state_t *state, int operation, char *argument) {
// Create a history action
action_t *new_action = (action_t *)malloc(sizeof(action_t));
// Identify the argument and perform specific actions
if (operation == APPEND) {
int word_length = Append(state, argument);
new_action->deleted = NULL;
new_action->word_length = word_length;
}
else if (operation == DELETE) {
char *deleted_string = Delete(state, ParseIntArg(argument));
new_action->deleted = deleted_string;
new_action->word_length = strlen(deleted_string);
}
// Finish up the history action
new_action->operation = operation;
new_action->previous = state->last_action;
// Update history
state->last_action = new_action; // already referenced previous head
}
/**
* Drop the latest addition to the history - frees memory and updates the "top" of the list
*/
void Undo(state_t *state) {
// Is there anything to undo?
if (state->last_action == NULL) {
return;
}
// Reverse the latest action
if (state->last_action->operation == APPEND) {
Delete(state, state->last_action->word_length);
}
else if (state->last_action->operation == DELETE) {
Append(state, state->last_action->deleted);
}
// Preserve the old top to free
action_t *old_top = state->last_action;
// Move the new top into place
state->last_action = state->last_action->previous;
// Drop the old top
free(old_top);
}
/**
* Loop through inputs (number given on first line), parsing numerical instruction and argument
*
* Undo history stored in a linked list of "states"
*/
int main() {
// Stack for instructions
state_t *state = malloc(sizeof(state_t));
state->string = (char *)malloc('\0');
unsigned int input_lines;
scanf("%u", &input_lines);
getchar(); // Need to consume the remaining newline
for (unsigned int i = 0; i < input_lines; i += 1) {
// Read input line
char input[MAX_INPUT + 3]; // max total length of all input strings + \0 + int
fgets(input, sizeof(input), stdin);
// Parse the operation first, then deal with the rest accordingly
char *after_operation;
int operation = strtol(input, &after_operation, 10);
if (operation == APPEND || operation == DELETE) {
// The argument is everything after the operation and a space
char *argument = malloc(strlen(after_operation));
sscanf(after_operation, " %s", argument);
DoStringAction(state, operation, argument);
}
else if (operation == PRINT) {
// The argument is a number! Print nth character, 1-indexed
int argument;
sscanf(after_operation, " %d", &argument);
printf("%c\n", state->string[argument - 1]);
}
else {
// Must be UNDO. No argument.
Undo(state);
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment