Global array of struct pointers not storing data - c

I have a C program that is trying to represent the layout of a house. It reads in the rooms from a text file with the following format:
Room
Door
Door
*
Room
Door
Door
The rooms and doors are stored as structures, and I have a global array of pointers to store 10 rooms. I'm using the method readrooms() to read in the rooms from the text file and store them in the array. However, after reading it in, when I try to print the contents of the array, I get a string of random characters.
#include <stdio.h>
#define MAX 10
struct room * rooms[MAX];
int rp = 0; //room count
//Declare Structures
struct room {
char *name;
struct door *doors[4];
int dp; //door count
};
struct door {
char *name;
struct room *room;
};
//Declare Functions
char *readLine(FILE *fin);
readrooms(FILE *fin);
struct door *newDoor(char * name);
struct room *newRoom(char *name);
main(int argc, char const *argv[])
{
FILE *f = fopen("C:\\Users\\s\\Documents\\C\\explore\\rooms.txt", "r");
readrooms(f);
printf("\n----- READ FILE SUCCESSFULLY | Room Count: %d -----\n", rp);
for (int i = 0; i < rp; i++) {
if (rooms[i] != NULL) {
struct room r = *rooms[i];
printf("ROOM %d: %s\n", i, r.name);
}
}
return 0;
}
struct door *newDoor(char * name) {
struct door d;
//TODO: MAKE SURE THIS IS RIGHT
d.name = name;
d.room = NULL;
return &d;
}
struct room *newRoom(char *name) {
struct room r;
r.name = name;
r.dp = 0;
rooms[rp++] = &r;
return &r;
}
char *readLine(FILE *fin) {
char *str = (char *) malloc(sizeof(char) * 3);
char current = fgetc(fin);
int iter = 0;
while (1) {
if (current == '\n') {
str[iter] = '\0';
break;
}
else if (current == EOF) return NULL;
else {
str[iter++] = current;
current = fgetc(fin);
}
}
return str;
}
readrooms(FILE *fin) {
char *curr_room = readLine(fin);
while (curr_room != NULL) {
if (strcmp(curr_room, "*") == 0) {
curr_room = readLine(fin);
continue;
}
struct room r = *newRoom(curr_room);
printf("\n\nReading room %s\n", r.name);
curr_room = readLine(fin);
while (curr_room != NULL && strcmp(curr_room, "*") != 0) {
struct door d = *newDoor(curr_room);
d.room = &r;
r.doors[r.dp++] = &d;
printf("\t%s.doors[%d] = %s\n", r.name, r.dp-1, d.name);
curr_room = readLine(fin);
//printf("Current room is now %s\n\n", curr_room);
}
}
}
Here is the output:
Reading room Hall
Hall.doors[0] = Study
Hall.doors[1] = Cellar
Hall.doors[2] = Kitchen
Reading room Study
Study.doors[0] = Hall
Study.doors[1] = Garden
Reading room Cellar
Cellar.doors[0] = Hall
Reading room Kitchen
Kitchen.doors[0] = Hall
Kitchen.doors[1] = Garden
Reading room Garden
Garden.doors[0] = Study
Garden.doors[1] = Kitchen
----- READ FILE SUCCESSFULLY | Room Count: 5 -----
ROOM 0: ├ïuΣ uαΦ┤■  Y├jhxÖä
ROOM 1: É√o
ROOM 2: É√o
ROOM 3: É√o
ROOM 4: É√o

One problem.
struct room *newRoom(char *name) {
struct room r;
r.name = name;
r.dp = 0;
rooms[rp++] = &r;
return &r;
}
struct room r; is local variable and will be vanished once control exits newRoom function.
Instead what you can do is
struct room *r = malloc(sizeof(struct room));
r->name = name;
r->dp = 0;
rooms[rp++] = r;
In readLine allocate enough memory to read complete line, otherwise you end up accessing out of bound and invoking undefined behavior.
char *readLine(FILE *fin) {
char *str = (char *) malloc(sizeof(char) * 256);
^^^Max line length
...
}
If you don't want to allocate memory blindly realloc is the thing you are looking for.

Related

C - re-allocation doesn't seem to work, can't add to a "dynamic array"

I have a Team struct which has field of pointer to a struct called Player.
I have a function that returns a pointer to a player,
everytime the user adds a player, it suppose to re-allocate the memory size of the "array" that contains the players, and to add a new player.
like a dynamic array of players.
for some reason it only accepts one player.
I have seen problems that resembles mine, but no answer worked.
Please help me.
the code:
struct Player {
float pointsAverage;
int uniformNumber;
int pointsOfLastFiveGames[5];
char *playerName;
};
struct Team {
int numberOfPlayers;
char *managerName = nullptr;
struct Player *players = (Player*)malloc(sizeof(Player));
};
struct Player* setPlayer(){
struct Player *player = NULL;
player = (struct Player*)malloc(sizeof(struct Player));
char name[81] = {0};
int jerseyNumber = -1;
int sumOfPoints = 0;
int currentPoint = 0;
printf("Player name?\n");
scanf("%s", &name);
int nameLength = strlen(name);
player->playerName = (char*)malloc(sizeof(char)*(nameLength + 1));
strcpy(player->playerName, name);
printf("Jesrsey number?\n");
scanf("%d",&jerseyNumber);
player->uniformNumber = jerseyNumber;
printf("Player point history?\n");
int i;
for (i=0; i<NUM_OF_PLAYER_POINT; i++) {
scanf("%d",&currentPoint);
sumOfPoints+=currentPoint;
}
player->pointsAverage = (float)(sumOfPoints/NUM_OF_PLAYER_POINT);
return player;
}
struct Team* setTeam(){
//initialize a team
struct Team *team = NULL;
team = (struct Team*) malloc(sizeof(struct Team));
team->managerName = NULL;
team->numberOfPlayers = 0;
team->players = NULL;
int usersChoice = -1;
// temp char array of name so i can take its size after user input
char name[81] = {0};
printf("Hello, please enter manager's name:\n");
scanf("%s",&name);
// checking the length of the user input.
int nameLength = strlen(name);
// dynamically allocating the manangerName memory space.
team->managerName = (char *)malloc(sizeof(char) * (nameLength + 1));
// setting the managername to the name the user typed.
strcpy(team->managerName, name);
int playerCounter = 1;
int addedPlayerCounter = 0;
while (1){
printf("Would you like to buy a player (1) yes (else) no?\n");
scanf("%d",&usersChoice);
if(usersChoice==1){
usersChoice = 0;
playerCounter++;
Player *temp = NULL; // here I tried make a new pointer but it still doesn't work
struct Player* tempPlayer = setPlayer();
temp = (Player*)realloc(team->players, sizeof(Player)*playerCounter);
(temp+(sizeof(Player)*addedPlayerCounter))->playerName = tempPlayer->playerName;
(temp+(sizeof(Player)*addedPlayerCounter))->pointsAverage = tempPlayer->pointsAverage;
addedPlayerCounter++;
team->numberOfPlayers++;
}else{
return team;
}
}
}
the main function just calls the setTeam function.

Why am I getting these errors when I am trying to compile my C code?

I am getting this error when compiling:
browninz.buildrooms.c:191:29: error: expected expression before ‘struct’
AddRandomConnection(struct room RoomA.outboundConnections, struct room RoomB.outboundConnections);
^
browninz.buildrooms.c:191:29: error: too few arguments to function ‘AddRandomConnection’
browninz.buildrooms.c:40:6: note: declared here
void AddRandomConnection(struct room *RoomA, struct room *RoomB)
^
Originally I started with about 20+ errors and I have finally scaled it down to a single error within my AddRandomConnections method, I am trying to compile this code and it keeps throwing an error for this single line. I have been trying for a few hours for different methods to fix the error, but I cannot get it to go away. Can anyone help me figure out why I am getting this error?
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
/*#include <stdbool.h>*/
typedef enum
{
false,
true
} bool;
// Creating the template for each of the rooms via struct
struct room
{
int id;
char* name;
char* type;
int numOutboundConnections;
struct room* outboundConnections[5];
};
// Returns true if all rooms have 3 to 6 outbound connections, false otherwise
int IsGraphFull(struct room *structureRooms)
{
int k = 0;
while (k < 7){
if (sizeof(structureRooms[k].numOutboundConnections) < 3){
return 0;
}
k++;
}
return 1;
}
// Adds a random outbound connection between two rooms
void AddRandomConnection(struct room *RoomA, struct room *RoomB)
{
while(true)
{
RoomA = GetRandomRoom(RoomA);
if (CanAddConnectionFrom(RoomA) == true)
break;
}
do
{
RoomB = GetRandomRoom(RoomB);
}
while(CanAddConnectionFrom(RoomB) == false || IsSameRoom(RoomA, RoomB) == true || ConnectionAlreadyExists(RoomA, RoomB) == true);
ConnectRoom(RoomA, RoomB); // TODO: Add this connection to the real variables,
ConnectRoom(RoomB, RoomA); // because this A and B will be destroyed when this function terminates
}
// Returns a random Room, does NOT validate if connection can be added
int GetRandomRoom(struct room *connections[])
{
// Initializes random number generator
srand(time(0));
// Generate random room
int x = rand() % 7;
return x;
}
// Returns true if a connection can be added from Room x (< 6 outbound connections), false otherwise
int CanAddConnectionFrom(struct room *RoomA)
{
if (sizeof(RoomA->numOutboundConnections) < 6)
{
return 1;
}
else{
return 0;
}
}
// Returns true if a connection from Room x and Room y already exists, false otherwise
int ConnectionAlreadyExists(struct room *RoomA, struct room *RoomB)
{
int myConnections;
int i = 0;
for (i; i <= 6; i++){
if ((RoomA->numOutboundConnections = RoomB->id)){
myConnections = 1;
break;
}
if(myConnections == 1)
{
return 1;
}
else
return 0;
}
}
// Connects Rooms A and B together, does not check if this connection is valid
void ConnectRoom(struct room *RoomA, struct room *RoomB)
{
RoomA->numOutboundConnections = RoomB->id;
}
// Returns true if Rooms x and y are the same Room, false otherwise
int IsSameRoom(struct room *RoomA, struct room *RoomB)
{
if (strcmp(RoomA->name, RoomB->name) == 0){
return 1;
}
return 0;
}
int main(int argc, char* argv[])
{
// Room names
char Forest[] = "Forest";
char Beach[] = "Beach";
char Cliff[] = "Cliff";
char River[] = "River";
char Cave[] = "Cave";
char Mountain[] = "Mountain";
char Cabin[] = "Cabin";
char Castle[] = "Castle";
char Fountain[] = "Fountain";
char Homeria[] = "Homeria";
// Initializing a room array variable to store contents of all room names
char* roomName[] = {Forest, Beach, Cliff, River, Cave, Mountain, Cabin, Castle, Fountain, Homeria};
// Creating the structs of 7 rooms each labeled with a name and type slot
struct room Room1;
Room1.id = 1;
Room1.name = calloc(16, sizeof(char));
Room1.type = calloc(16, sizeof(char));
strcpy(Room1.type, "START_ROOM");
struct room Room2;
Room2.id = 2;
Room2.name = calloc(16, sizeof(char));
Room2.type = calloc(16, sizeof(char));
strcpy(Room2.type, "MID_ROOM");
struct room Room3;
Room3.id = 3;
Room3.name = calloc(16, sizeof(char));
Room3.type = calloc(16, sizeof(char));
strcpy(Room3.type, "MID_ROOM");
struct room Room4;
Room4.id = 4;
Room4.name = calloc(16, sizeof(char));
Room4.type = calloc(16, sizeof(char));
strcpy(Room4.type, "MID_ROOM");
struct room Room5;
Room5.id = 5;
Room5.name = calloc(16, sizeof(char));
Room5.type = calloc(16, sizeof(char));
strcpy(Room5.type, "MID_ROOM");
struct room Room6;
Room6.id = 6;
Room6.name = calloc(16, sizeof(char));
Room6.type = calloc(16, sizeof(char));
strcpy(Room6.type, "MID_ROOM");
struct room Room7;
Room7.id = 10;
Room7.name = calloc(16, sizeof(char));
Room7.type = calloc(16, sizeof(char));
strcpy(Room7.type, "END_ROOM");
// Randomizing the room names to append to a random room #
srand(time(0));
struct room structureRooms[7] = {Room1, Room2, Room3, Room4, Room5, Room6, Room7};
int i = 0;
int array1[] = {0 ,0, 0, 0, 0, 0, 0, 0, 0, 0};
// Loop for each of the rooms which checks to see if a name is available, if so, apply to random room
while ( i < 7 ){
int randNum = rand() % 10;
if (array1[randNum] == 0){
array1[randNum] = 1;
strcpy(structureRooms[i].name, roomName[randNum]);
i++;
}
}
// Create all connections in the graph
while (IsGraphFull(structureRooms) == false)
{
AddRandomConnection(struct room RoomA.outboundConnections, struct room RoomB.outboundConnections);
}
// Assigning char limits
char dirname[100];
char dir0[100];
char dir1[100];
char dir2[100];
char dir3[100];
char dir4[100];
char dir5[100];
char dir6[100];
// Generate the "rooms" directory name with the PID
sprintf(dirname, "./browninz.rooms%d", getpid());
// Generate the room names concatenated with the directory name
sprintf(dir0, "%s/Room1", dirname);
sprintf(dir1, "%s/Room2", dirname);
sprintf(dir2, "%s/Room3", dirname);
sprintf(dir3, "%s/Room4", dirname);
sprintf(dir4, "%s/Room5", dirname);
sprintf(dir5, "%s/Room6", dirname);
sprintf(dir6, "%s/Room7", dirname);
// Create a new directory that the "rooms" files will be stored in
mkdir(dirname, 0770);
// Pointer files of each of the rooms
FILE *myRoom1;
FILE *myRoom2;
FILE *myRoom3;
FILE *myRoom4;
FILE *myRoom5;
FILE *myRoom6;
FILE *myRoom7;
// Now opening the room files / directories to create or write them in the folder.
myRoom1 = fopen(dir0, "w+");
myRoom2 = fopen(dir1, "w+");
myRoom3 = fopen(dir2, "w+");
myRoom4 = fopen(dir3, "w+");
myRoom5 = fopen(dir4, "w+");
myRoom6 = fopen(dir5, "w+");
myRoom7 = fopen(dir6, "w+");
// Creating a pointer array of all of the room pointers
FILE *myRooms[7] = {myRoom1, myRoom2, myRoom3, myRoom4, myRoom5, myRoom6, myRoom7};
// Printing room file name, type, and connections and iterates for each room
int counter = 0;
while (counter < 7) {
fprintf(myRooms[counter], "ROOM NAME: %s\n", structureRooms[counter].name);
fprintf(myRooms[counter], "ROOM TYPE: %s\n", structureRooms[counter].type);
// fprintf(myRooms[counter], "CONNECTION 1: %s\n", structureRooms[counter].outboundConnections[counter]);
// test to see if connection works
fprintf(myRooms[counter], "CONNECTION 1: %s\n", structureRooms[counter].name);
counter++;
}
return 0;
}
In your call below, remove the "struct room". You've already declared the type in the function declaration.
// Create all connections in the graph
while (IsGraphFull(structureRooms) == false)
{
AddRandomConnection(struct room RoomA.outboundConnections, struct room RoomB.outboundConnections);
}
So that it is just AddRandommConnection(RoomA.outboundConnections, Roomb.outboundConnections);

My struct is overlapping some data from the previous one (Edit)

Hi guys I'm having a problem with pointers and memory this is my data structure:
struct user_node {
char *name;
struct user_node *next;
struct msg_node *msgnext;
};
struct msg_node {
char *sender;
char *receiver;
char *title;
char *content;
struct msg_node *msgnext;
};
Each user have a name and a linked list which store messages.
I already have the user creation / deletion implemented but I'm having trouble implementing new msg, I'm using this functions:
struct msg_node* sendForm(char** res) { // Format msg before sending
struct msg_node *temp = (struct msg_node*) malloc(sizeof(struct msg_node));
char *aux = malloc(sizeof(char) * 400);
int i;
temp->sender = res[1];
temp->receiver = res[2];
temp->title = res[3];
for (i = 4; i < (n_spaces + 1); i++) {
if (res[i] != NULL) {
strcat(aux, res[i]);
strcat(aux, " ");
}
}
temp->content = aux;
return temp;
}
int sendMsg(struct msg_node* msg)
{
struct user_node* user = user_database;
if (user == NULL) {
printf("There aren't users on the system.\n");
return -1;
}
while (user != NULL) {
if (strncmp(user->name, msg->receiver, strlen(msg->receiver)) == 0) {
msg->msgnext = user->msgnext;
user->msgnext = msg;
readmsglist();
return 0;
}
user = user->next;
}
printf("User '%s' not found on the system.\n", msg->receiver);
return -1;
}
This is actually working if I only input one msg but when I try to implement the second one this is what's happening:
Execution:
Welcome to the Program> Enter command (h for help):register user
User created
There are 1 users right now
> Enter command (h for help):send RandomUser1 user content1 a b c
Receiver -> user
Sender -> RandomUser1
Subject -> content1
Content:
a b c
> Enter command (h for help):send RandomUser2 user content2 d e f
Receiver -> user
Sender -> RandomUser2
Subject -> content2
Content:
d e f
Receiver -> user
Sender -> RandomUser2
Subject -> content2
Content:
a b c
and so more...
The weirdest part here is that the content is never overlaped but the other parts actually are.
Btw Sorry for my previous post that had to much code.
Edit: (Data output function)
void readmsglist() { // Show the msg of the first user Test Purposes
struct msg_node** ptr = &user_database->msgnext;
while (*ptr) {
printf("Receiver -> %s\n", (*ptr)->receiver);
printf("Sender -> %s\n", (*ptr)->sender);
printf("Subject -> %s\n", (*ptr)->title);
printf("Content:\n %s\n", (*ptr)->content);
ptr = &(*ptr)->msgnext;
}
}
Edit2 (More info):
First, the function is called here:
case 24: //Send messages
if (countSpaces(input) > 2) {
sendMsg(sendForm(cut(input)));
} else {
E_Type();
}
break;
This is the cut function:
char** cut(char str[]) {
char ** res = NULL;
char * p = strtok(str, " ");
n_spaces = 0; // Global variable (int)
/* split string and append tokens to 'res' */
while (p) {
res = realloc(res, sizeof(char*) * ++n_spaces);
if (res == NULL)
exit(-1); /* memory allocation failed */
res[n_spaces - 1] = p;
p = strtok(NULL, " ");
}
/* realloc one extra element for the last NULL */
res = realloc(res, sizeof(char*) * (n_spaces + 1));
res[n_spaces] = 0;
return res;
}
The input is like -> send :
Edw4d and I had a long discussion and debugging session.
The message data is being overwritten by user input because the location of the data in input buffer in each message is being stored in each message node, rather than actually copying the string into a new buffer. This solves the problem:
char** cut(char str[])
{
char *p = strtok(str, " "); // We don't need the first token.
p = strtok(NULL, " ");
char **res = calloc(sizeof(char*), 4); /* allocate a buffer full of NULL's*/
if (res == NULL) exit(-1); /* memory allocation failed */
/* split string and append tokens to 'res' */
for (int idx = 0; idx < 3; idx++)
{
res[idx] = malloc(strlen(p) + 1);
strcpy(res[idx], p);
p = strtok(NULL, " ");
}
p[strlen(p)] = ' '; // Put the space back where strtok wrote the null character.
res[3] = malloc(strlen(p) + 1);
strcpy(res[3], p);
return res;
}
MsgNode* sendForm(char** res) { // Format msg before sending
struct msg_node *temp = (struct msg_node*) malloc(sizeof(struct msg_node));
temp->receiver = res[0];
temp->sender = res[1];
temp->title = res[2];
temp->content = res[3];
return temp;
}

Segmentation Fault: double free or corruption (fast top)

I've a problem when I run this piece of code: a Segmentation Fault that appears during the free instruction of percorso. I cannot find the problem.
void ricerca(char nome[], struct node *radice, char percorso[], struct stringhe **indice) {
struct node *punt = radice;
int dim = len(percorso);
char *prov = NULL;
if (dim > 0) {
prov = malloc(2 * dim * sizeof(char));
prov[0] = '\0';
strcpy(prov, percorso);
free(percorso); //--------------------->here the SegFault
}
struct stringhe *nuovo = NULL;
int i = 0, fine = 0;
char *perc_orig = NULL;
if (punt != NULL) {
if (punt->array != NULL) {
dim = len(prov) + len(punt->nome) + 2;
percorso = malloc(dim * sizeof(char));
percorso[0] = '\0';
if (prov!=NULL)
strcpy(percorso, prov);
strcat(percorso, "/");
strcat(percorso, punt->nome);
perc_orig = malloc(dim * sizeof(char));
for (i = 0; i < N; i++) {
if (punt->array->vet[i] != NULL) {
perc_orig[0] = '\0';
strcpy(perc_orig, percorso);
ricerca(nome, punt->array->vet[i], perc_orig,indice);
}
}
free(perc_orig);
}
if (strcmp(nome,punt->nome) == 0) {
free(percorso);
dim = len(prov) + len(punt->nome) + 2;
percorso = malloc(dim * sizeof(char));
inizializza(percorso, dim);
if (prov != NULL)
strcpy(percorso, prov);
strcat(percorso, "/");
strcat(percorso, punt->nome);
nuovo = malloc(sizeof(struct stringhe));
nuovo->next = NULL;
nuovo->str = malloc(dim * sizeof(char));
inizializza(nuovo->str, dim);
strcpy(nuovo->str, percorso);
nuovo->next = (*indice);
*indice = nuovo;
}
while (punt->chain != NULL && fine == 0) {
ricerca(nome, punt->chain,prov, indice);
fine = 1;
if (prov!=NULL)
free(prov);
}
}
}
The len function is like strlen, but the difference is that I've made it myself.
the context is:
void find(char nome[], struct node *radice) {
char *perc = NULL;
struct stringhe **inizio = NULL;
inizio = malloc(sizeof(struct stringhe*));
*inizio = NULL;
int i = 0;
for (i = 0; i < N; i++) {
if (radice->array->vet[i] != NULL) {
perc = NULL;
ricerca(nome, radice->array->vet[i], perc, inizio);
}
}
if (*inizio != NULL) {
insertion(inizio);
stampap(*inizio);
} else
printf("no\n");
}
And the data structures:
struct tab {
struct node *vet[64];
};
struct node {
char nome[255];
int num;
int tipo;
char *dati;
struct tab *array;
struct node *chain;
};
This is really weird:
if (some condition)
free(percorso);
Later on we have:
perc_orig = malloc(dim*sizeof(char));
for(something){
if(something){
ricerca(nome,punt->array->vet[i],perc_orig,indice);
}
}
free(perc_orig);
If that if conditions happens, perc_orig will be freed twice. Kaboom.
I think your problem is you think that ricerca(..., char percico[], ...) copies percico. It doesn't; it's really ricerca(..., char *percico, ...) so you ended up freeing the memory twice.
the sizing for the char arrays needs to allow for the trailing NUL ('\0') character.
ALL fields that are referenced by strcpy() and similar functions need to have ALL source character arrays NUL terminated.
The code does not seem to be allocating enough room for those trailing NUL bytes NOR terminating every character array with a NUL char.
Segmentation fault occurs when you initialize a character pointer to NULL and try to point it to a not null value
For example,
char *a=NULL;
a='a';
Will cause segmentation fault. To avoid this you can try to initialize as,
char *a;
a='a';

Cannot understand input of a Turing Machine Implementation in C

I just found this code online, and do not understand how the input should be formatted. An example of similar input from the same programmer is shown here: Pushdown automaton implemented in C
But it still does not help that much. Here is what it says:
The input format is like:
e01:e0$:000111:a:ad:aeeb$:b0eb0:b10ce:c10ce:ce$de The input is
separated by a semicolon “:”, first section is “input alphabet”,
second is “stack alphabet”, then “input” and the last whole bunch are
transition functions.
Can anyone provide some guidance how the input is handled? I am trying really hard for about 6 hours now, and cannot for the life of me decipher how the input should be formatted for this code.
Once it is compiled with gcc, to run it just do "./executable" and press enter. Then paste in the sample input string as shown above (although for this program I would need a different input).
/* This C file implements a Turing Machine
* author: Kevin Zhou
* Computer Science and Electronics
* University of Bristol
* Date: 21st April 2010
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct tapes {
struct tapes *left;
struct tapes *right;
char content;
} Tape;
typedef enum { LEFT,RIGHT } Direction;
typedef struct transition {
char current_state;
char tape_symbol;
char new_state;
char new_tape_symbol;
Direction dir;
} Transition;
typedef struct list {
Transition *content;
struct list *next;
} List;
typedef struct tm {
char *input_alpha;
char *input;
char *tape_alpha;
char start;
char accept;
char reject;
List *transition;
} TM;
Tape *insert_tape(Tape *t, Direction dir, char c) {
Tape *head = t;
Tape *new1 = calloc(1,sizeof(Tape));;
new1 -> content = c;
if(dir == LEFT) {
while(t->left != NULL) {
t = t->left;
}
new1->right = t;
new1->left = NULL;
t->left = new1;
return new1;
}
if(dir == RIGHT) {
while(t->right != NULL) {
t = t->right;
}
new1->left = t;
new1->right = NULL;
t->right = new1;
}
return head;
}
Tape *create_tape(char *input) {
int i=1;
Tape *t = calloc(1,sizeof(Tape));
t->content = input[0];
while(1) {
if(input[i] == '\0') break;
t = insert_tape(t,RIGHT,input[i]);
i++;
}
return t;
}
/* turn the input string into Transition fields */
Transition *get_transition(char *s) {
Transition *t = calloc(1,sizeof(Transition));
Direction dir;
t->current_state = s[0];
t->tape_symbol = s[1];
t->new_state = s[2];
t->new_tape_symbol = s[3];
dir = (s[4]=='R')? RIGHT:LEFT;
t->dir = dir;
return t;
}
/* turn the string into transitions and add into list */
List *insert_list( List *l, char *elem ) {
List *t = calloc(1,sizeof(List));
List *head = l;
while(l->next!=NULL)
l = l->next;
t->content = get_transition(elem);
t->next = NULL;
l->next = t;
return head;
}
/* insert a transition into a list */
List *insert_list_transition( List *l, Transition *tr) {
List *t = calloc(1,sizeof(List));
List *head = l;
while(l->next!=NULL)
l = l->next;
t->content = tr;
t->next = NULL;
l->next = t;
return head;
}
void print_tape( Tape *t,char blank) {
char c;
while(1) {
if(t->content != blank) break;
t= t->right;
}
while(1) {
if(t==NULL) break;
c = t->content;
if(t->content != blank)
putchar(c);
t= t->right;
}
putchar('\n');
}
void print_transition (Transition *t) {
char s1[] = "Left";
char s2[] = "Right";
if(t==NULL) {
printf("NULL Transfer");
return;
}
printf("current:%c tape:%c new state:%c new tape:%c direction %s\n",t->current_state,t->tape_symbol,t->new_state,t->new_tape_symbol,(t->dir == LEFT)?s1:s2);
}
/*test if the char c is in the string s */
int contains ( char c, char *s ) {
int i=0;
while(1) {
if(c== s[i]) return 1;
if(s[i] == '\0') return 0;
i++;
}
}
/* test if the input is a valid input */
int is_valid_input( char *input_alpha, char *input ) {
int i=0;
char c;
while(1) {
c = input[i];
if(c == '\0') break;
if(!contains(c,input_alpha)) return 0;
i++;
}
return 1;
}
TM *createTM (char *input) {
TM *m = calloc(1,sizeof(TM));
List *tr = calloc(1,sizeof(List));
char *buffer;
/*read input alphabet of PDA*/
buffer = strtok(input,":");
if(buffer == NULL) {
printf("Error in reading input alphabet!\n");
exit(1);
}
m->input_alpha = buffer;
/*read tape alphabet*/
buffer = strtok(NULL,":");
if(buffer == NULL) {
printf("Error in reading tape alphabet!\n");
exit(1);
}
m->tape_alpha = buffer;
/*read input sequence*/
buffer = strtok(NULL,":");
if(buffer == NULL) {
printf("Error in reading input sequence!\n");
exit(1);
}
if(!is_valid_input(m->input_alpha,buffer)) {
printf("Error! Input contains some invalid characters that don't match the input alphabet!\n");
exit(1);
}
m->input = buffer;
buffer = strtok(NULL,":");
m->start = buffer[0];
buffer = strtok(NULL,":");
m->accept = buffer[0];
buffer = strtok(NULL,":");
m->reject = buffer[0];
/*read tape transition*/
while(1) {
buffer = strtok(NULL,":");
if(buffer == NULL) break;
tr = insert_list(tr,buffer);
}
m->transition = tr->next;
return m;
}
Transition *find_transition(List * list,char state, char tape_symbol) {
Transition *t;
while(1) {
if(list==NULL) return NULL;
t = list -> content;
if(t->current_state == state && t->tape_symbol == tape_symbol)
return t;
list = list->next;
}
}
Tape *move(Tape *t,Direction dir, char blank) {
if(dir == LEFT) {
if(t->left==NULL) {
t = insert_tape(t,LEFT,blank);
}
return t->left;
}
if(dir == RIGHT) {
if(t->right==NULL) {
t = insert_tape(t,RIGHT,blank);
}
return t->right;
}
return NULL;
}
void simulate( TM *m ) {
/* first symbol in input symbol used to represent the blank symbol */
const char blank = m->tape_alpha[0];
char current_state = m->start;
Tape *tape = create_tape(m->input);
Tape *current_tape = tape;
char current_tape_symbol;
Transition *current_transition;
while(1) {
if(current_state == m->accept) {
printf("Accept\n");
print_tape(tape,blank);
break;
}
if(current_state == m->reject) {
printf("Reject\n");
print_tape(tape,blank);
break;
}
current_tape_symbol = (current_tape==NULL||current_tape ->content == '\0')?blank:current_tape->content;
current_transition = find_transition(m->transition,current_state,current_tape_symbol);
current_state = current_transition -> new_state;
current_tape -> content = current_transition -> new_tape_symbol;
current_tape = move( current_tape, current_transition ->dir, blank);
}
}
int main(void) {
char s[300];
TM *p;
scanf("%s",s);
p = createTM(s);
simulate(p);
return 0;
}
The heavy use of the line buffer = strtok(NULL,":") confirms that the input strings are (like in the linked-to code) colon-delimited.
The struct defintions are the key to reverse-engineering the input.
The main struct is:
typedef struct tm {
char *input_alpha;
char *input;
char *tape_alpha;
char start;
char accept;
char reject;
List *transition;
} TM;
The function createTM() is the function which splits the input on : and loads the Turing machine. struct tm has 7 fields and createTM() has 7 clear phases
1) The first part is the input alphabet. Presumably this would be a string of 1 or more characters, e.g. 01.
2) The second part is the tape is the tape alphabet. The only character in this which plays any role in the rest of the code is the first character. The line const char blank = m->tape_alpha[0]; in the main simulation function indicates that the first character plays the role of the blank character -- the character which indicates that a tape square is empty. The ability to write the blank to a square allows the Turing machine to erase the data in a square. Note that in some sense this part of the input is out of order -- it is listed as the third field in the struct definition but is the second field in the input string.
3) The thirs part is the initial input on the tape. It is a string all of whose characters are drawn from the first part. The function is_valid_input() is used to check this condition.
4) The next part is the start state, which consists of a single char
5) The next part is the accept state, which is again a single char. Thus, in this model of a TM there is a single accepting state
6) The next part is the rejecting state, which is again represented by a single char
7) What follows is a sequence of strings, fed into a linked list of strings. The key function in understanding how it works is get_transition() which takes one of these transition strings and converts it into a Transition struct, declared as:
typedef struct transition {
char current_state;
char tape_symbol;
char new_state;
char new_tape_symbol;
Direction dir;
} Transition;
Looking carefully at the function get_transition() you can infer that a transition is represented by a string of length 5 where the last char is either R or L. An example would be something like a1b0R which says something like "if you are in state a while scanning symbol 0, transition to state b, write symbol 1 and the move to the right".
Putting it all together, the form of an input string would be something like:
01:_102:1001010101:$:a:r:$0b1R:b1b0L:a1b2R
corresponding to
01 _102 1001010101 $ a r $0b1R b1b0L a1b2R
input tape input start accept reject transitions
| alphabets | | states |
(blank = '_')
I just made some transitions at random, and neither know nor care what the program would do with this input. This should be enough for you to start experimenting with the program.

Resources