We have created some scripts that can automatically run your program against some tests. To run these tests you can execute the dry run program with an argument that corresponds to the lab and week, i.e. lab06 for this week. It expects to find all the programs to be submitted as part of this lab in the current directory. You can use dry run as follows:
prompt$ ~cs1921/bin/dryrun lab06
or specific tests (e.g. test #2) as follows:
prompt$ ~cs1921/bin/dryrun lab06 2
Exercises
Just 3 exercises this week.
Write a program called colours.c that reads a sequence of people's names and integers from stdin into an array of structs. The array must be dynamic (and hence may not be fixed length). A struct here has the form:
#define NAMLEN 50
typedef struct {
char name[NAMLEN];
int colour;
} Preferences;
After reading all the data, your program should output the information stored in the array as shown below, where the numbers actually correspond to colours:
0=cyan, 1=pink, 2=green, 3=red, 4=yellow, 5=blue, 6=unknown
You may use the following test data:
20
Xiang 5
Bin 1
Navid 0
Abdul 1
Ming-Tak 5
Surya 2
Jingxu 3
Lasit 2
Yi 4
Ghit-Hong 6
John 3
Nam-Thanh 3
Jian 0
Kuninda 1
Wenxi 6
Wenfei 4
Fei 1
Xiaotian 0
Ke 2
Ge 6
Notice that the first line of this data indicates the number of people. The output for this test data should be:
Xiang likes blue
Bin likes pink
Navid likes cyan
Abdul likes pink
Ming-Tak likes blue
Surya likes green
Jingxu likes red
Lasit likes green
Yi likes yellow
Ghit-Hong likes unknown
John likes red
Nam-Thanh likes red
Jian likes cyan
Kuninda likes pink
Wenxi likes unknown
Wenfei likes yellow
Fei likes pink
Xiaotian likes cyan
Ke likes green
Ge likes unknown
Note:
the only fixed-length array that you should use is in the struct definition
you should use an array of structs to store the data
the array should be dynamic
be sure your program works for an empty input or if the first line is not numeric: it should write to stderr:
Missing number in data file
be sure your program works if the data is in the wrong format or if there is data missing: it should write to stderr:
Error in data file
be sure your program works when the given number is 0 (it should produce no output)
A file called database.txt stores all the user information for a top secret database. Each line of the database corresponds to a single person and is of the following format
lastname firstname year_of_birth password securityClearanceLevel secret
Note: the fields in the database are separated by spaces
There are only 3 possible values for securityClearanceLevel, namely, none, high and top. For example, the first few lines of the database.txt file may look like this
Dracula Martin 1285 i_am_undead top is actually a vampire
Gregorius Abdul 1953 password123 high has broken his leg while tap dancing
Pham Fei 1985 wordpass098 none second cousin of chuck norris
Your task is to write a program, security.c, which reads in the data from this database.txt file and stores it in an appropriate way, using structs and enums. You are then to ask the user for a username and password. A username is simply a person's first name and last name concatenated together, eg Martin Dracula will have the username "MartinDracula". If the user enters a valid username and password, you are to print out correct username/password entered as well as the first name and secret of every person in the database with a lower security clearance. If the user enters an invalid username and password combination, you are to print out the message "you did not enter a correct username/password combination".
A sample run of the program would look like this:
$ gcc -Wall -Werror -O -o security security.c
$ ./security
username: MartinDracula
password: i_am_undead
correct username/password entered
Abdul's secret is 'has broken his leg while tap dancing'
Fei's secret is 'second cousin of chuck norris'
$ ./security
username: AbdulGregorius
password: wrongpassword
you did not enter a correct username/password combination
Assumptions:
no two people in the database have the same name.
the database.txt is correct, and all fields have proper values
longest line in the file is no more than 90 characters long
the database.txt file does not contain more than 1000 people
You may use the following skeleton to get started:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DATABASE_FILE "database.txt"
#define DATABASE_DELIMITER ','
#define MAX_LINE_LENGTH 100
#define MAX_DATABASE_LENGTH 100
#define TRUE 1
#define FALSE 0
void chomp(char* string);
typedef struct person {
char* firstName;
char* lastName;
// TODO add something for clearance level here perhaps?
int age;
char* password;
char* secret;
} person;
int main(int argc, char* argv[]) {
// open database file
FILE* file = fopen(DATABASE_FILE, "r");
if (file == NULL) {
fprintf(stderr, "could not open file");
return EXIT_SUCCESS;
}
person people[MAX_DATABASE_LENGTH];
int count = 0;
char firstName[MAX_LINE_LENGTH];
char lastName[MAX_LINE_LENGTH];
int age;
char clearance[MAX_LINE_LENGTH];
char password[MAX_LINE_LENGTH];
char secret[MAX_LINE_LENGTH];
// read entire database into the people array
while (fscanf(file,"%s %s %d %s %s ", lastName, firstName, &age, password, clearance) != EOF) {
if (fgets(secret, MAX_LINE_LENGTH, file) != NULL) {
// lastname
people[count].lastName = malloc(sizeof(char) * strlen(lastName) + 1);
strcpy(people[count].lastName, lastName);
// firstname
people[count].firstName = malloc(sizeof(char) * strlen(firstName) + 1);
strcpy(people[count].firstName, firstName);
// age
people[count].age = age;
// clearance
//////////////////////////////////////////
// TODO you need to write some code here//
//////////////////////////////////////////
// password
people[count].password = malloc(sizeof(char) * strlen(password) + 1);
strcpy(people[count].password, password);
// secret
chomp(secret);
people[count].secret = malloc(sizeof(char) * strlen(secret) + 1);
strcpy(people[count].secret, secret);
count++;
} else {
fprintf(stderr, "error reading file\n");
}
}
fclose(file);
//////////////////////////////////////////
// TODO you need to write some code here//
//////////////////////////////////////////
return EXIT_SUCCESS;
}
// removes the newline, if it exists
void chomp(char* string) {
if (string[strlen(string) - 1] == '\n') {
string[strlen(string) - 1] = '\0';
}
}
Write a program called llbuild.c that builds a linked list from user input. The only functions that you may call are:
NodeT *makeNode(int value): taken from the lecture
void freeList(NodeT *head): take from the lecture
void printList(NodeT *head): take from the lecture, needs modification
NodeT *joinList(NodeT *head1, NodeT *head2): joins 2 linked lists head1 and head2. Needs to be implemented.
The program:
starting with an initially NULL linked list called all (say)
prompts the user with the message "Enter a number: "
makes a linked list node called new from user's response
joins the nodes all and new
asks for more user input and repeats the cycle
the cycle is terminated when the user enters any non-numeric character
on termination the program generates the message "Finished: list is " followed by the contents of the linked list
if the user has entered no data, then the message is simply "Finished"
A sample interaction is:
prompt$ ./llbuild
Enter an integer: 12
Enter an integer: 34
Enter an integer: 56
Enter an integer: quit
Finished: list is 12->34->56
Note that any non-numeric data 'finishes' the interaction:
prompt$ ./llbuild
Enter an integer: 100
Enter an integer: bye
Finished: list is 100
A longer interaction:
prompt$ ./llbuild
Enter an integer: 421
Enter an integer: 456732
Enter an integer: 321
Enter an integer: 4
Enter an integer: 86
Enter an integer: 89342
Enter an integer: 9
Enter an integer: #
Finished: list is 421->456732->321->4->86->89342->9
If the user provides no data, then no list is output:
prompt$ ./llbuild
Enter an integer: coffee
Finished
Note, please ensure:
the linked list all is initially NULL
Submit your work using:
give cs1921 lab06 colours.c security.c llbuild.c