I'm using an online tutorial on how to make a Text Adventure game (in VSC) and came across a really annoying issue. Even after copying all the source code from the tutorial, I receive an 'undefined reference' error. I tried editing the 'tasks.json' file as described here: undefined reference error in VScode
but with no success.
The game consists of multiple c files in order to work, the source code is at the bottom of the page here: https://helderman.github.io/htpataic/htpataic05.html
Here's all the files, Thanks a lot in advance for any help!
<main.c>
#include <stdbool.h>
#include <stdio.h>
#include "parsexec.h"
static char input[100] = "look around";
static bool getInput(void)
{
printf("\n--> ");
return fgets(input, sizeof input, stdin) != NULL;
}
int main()
{
printf("Welcome to Little Cave Adventure.\n");
while (parseAndExecute(input) && getInput());
printf("\nBye!\n");
return 0;
}
<parsexec.h>
extern bool parseAndExecute(char *input);
<parsexec.c>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "location.h"
#include "inventory.h"
bool parseAndExecute(char *input)
{
char *verb = strtok(input, " \n");
char *noun = strtok(NULL, " \n");
if (verb != NULL)
{
if (strcmp(verb, "quit") == 0)
{
return false;
}
else if (strcmp(verb, "look") == 0)
{
executeLook(noun);
}
else if (strcmp(verb, "go") == 0)
{
executeGo(noun);
}
else if (strcmp(verb, "get") == 0)
{
executeGet(noun);
}
else if (strcmp(verb, "drop") == 0)
{
executeDrop(noun);
}
else if (strcmp(verb, "give") == 0)
{
executeGive(noun);
}
else if (strcmp(verb, "ask") == 0)
{
executeAsk(noun);
}
else if (strcmp(verb, "inventory") == 0)
{
executeInventory();
}
else
{
printf("I don't know how to '%s'.\n", verb);
}
}
return true;
}
<location.c>
#include <stdio.h>
#include <string.h>
#include "object.h"
#include "misc.h"
#include "noun.h"
void executeLook(const char *noun)
{
if (noun != NULL && strcmp(noun, "around") == 0)
{
printf("You are in %s.\n", player->location->description);
listObjectsAtLocation(player->location);
}
else
{
printf("I don't understand what you want to see.\n");
}
}
void executeGo(const char *noun)
{
OBJECT *obj = getVisible("where you want to go", noun);
if (obj == NULL)
{
// already handled by getVisible
}
else if (obj->location == NULL && obj != player->location)
{
printf("OK.\n");
player->location = obj;
executeLook("around");
}
else
{
printf("You can't get much closer than this.\n");
}
}
<location.h>
extern void executeLook(const char *noun);
extern void executeGo(const char *noun);
<object.c>
#include <stdio.h>
#include "object.h"
OBJECT objs[] = {
{"an open field", "field" , NULL },
{"a little cave", "cave" , NULL },
{"a silver coin", "silver" , field },
{"a gold coin" , "gold" , cave },
{"a burly guard", "guard" , field },
{"yourself" , "yourself", field }
};
<object.h>
typedef struct object {
const char *description;
const char *tag;
struct object *location;
} OBJECT;
extern OBJECT objs[];
#define field (objs + 0)
#define cave (objs + 1)
#define silver (objs + 2)
#define gold (objs + 3)
#define guard (objs + 4)
#define player (objs + 5)
#define endOfObjs (objs + 6)
<noun.c>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "object.h"
static bool objectHasTag(OBJECT *obj, const char *noun)
{
return noun != NULL && *noun != '\0' && strcmp(noun, obj->tag) == 0;
}
static OBJECT *getObject(const char *noun)
{
OBJECT *obj, *res = NULL;
for (obj = objs; obj < endOfObjs; obj++)
{
if (objectHasTag(obj, noun))
{
res = obj;
}
}
return res;
}
OBJECT *getVisible(const char *intention, const char *noun)
{
OBJECT *obj = getObject(noun);
if (obj == NULL)
{
printf("I don't understand %s.\n", intention);
}
else if (!(obj == player ||
obj == player->location ||
obj->location == player ||
obj->location == player->location ||
obj->location == NULL ||
obj->location->location == player ||
obj->location->location == player->location))
{
printf("You don't see any %s here.\n", noun);
obj = NULL;
}
return obj;
}
OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun)
{
OBJECT *obj = NULL;
if (from == NULL)
{
printf("I don't understand who you want to %s.\n", verb);
}
else if ((obj = getObject(noun)) == NULL)
{
printf("I don't understand what you want to %s.\n", verb);
}
else if (obj == from)
{
printf("You should not be doing that to %s.\n", obj->description);
obj = NULL;
}
else if (obj->location != from)
{
if (from == player)
{
printf("You are not holding any %s.\n", noun);
}
else
{
printf("There appears to be no %s you can get from %s.\n",
noun, from->description);
}
obj = NULL;
}
return obj;
}
<noun.h>
extern OBJECT *getVisible(const char *intention, const char *noun);
extern OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun);
<inventory.c>
#include <stdio.h>
#include "object.h"
#include "misc.h"
#include "noun.h"
#include "move.h"
void executeGet(const char *noun)
{
OBJECT *obj = getVisible("what you want to get", noun);
if (obj == NULL)
{
// already handled by getVisible
}
else if (obj == player)
{
printf("You should not be doing that to yourself.\n");
}
else if (obj->location == player)
{
printf("You already have %s.\n", obj->description);
}
else if (obj->location == guard)
{
printf("You should ask %s nicely.\n", obj->location->description);
}
else
{
moveObject(obj, player);
}
}
void executeDrop(const char *noun)
{
moveObject(getPossession(player, "drop", noun), player->location);
}
void executeAsk(const char *noun)
{
moveObject(getPossession(actorHere(), "ask", noun), player);
}
void executeGive(const char *noun)
{
moveObject(getPossession(player, "give", noun), actorHere());
}
void executeInventory(void)
{
if (listObjectsAtLocation(player) == 0)
{
printf("You are empty-handed.\n");
}
}
<inventory.h>
extern void executeGet(const char *noun);
extern void executeDrop(const char *noun);
extern void executeAsk(const char *noun);
extern void executeGive(const char *noun);
extern void executeInventory(void);
<misc.c>
#include <stdio.h>
#include "object.h"
OBJECT *actorHere(void)
{
OBJECT *obj;
for (obj = objs; obj < endOfObjs; obj++)
{
if (obj->location == player->location && obj == guard)
{
return obj;
}
}
return NULL;
}
int listObjectsAtLocation(OBJECT *location)
{
int count = 0;
OBJECT *obj;
for (obj = objs; obj < endOfObjs; obj++)
{
if (obj != player && obj->location == location)
{
if (count++ == 0)
{
printf("You see:\n");
}
printf("%s\n", obj->description);
}
}
return count;
}
<misc.h>
extern OBJECT *actorHere(void);
extern int listObjectsAtLocation(OBJECT *location);
<move.c>
#include <stdio.h>
#include "object.h"
static void describeMove(OBJECT *obj, OBJECT *to)
{
if (to == player->location)
{
printf("You drop %s.\n", obj->description);
}
else if (to != player)
{
printf(to == guard ? "You give %s to %s.\n" : "You put %s in %s.\n",
obj->description, to->description);
}
else if (obj->location == player->location)
{
printf("You pick up %s.\n", obj->description);
}
else
{
printf("You get %s from %s.\n",
obj->description, obj->location->description);
}
}
void moveObject(OBJECT *obj, OBJECT *to)
{
if (obj == NULL)
{
// already handled by getVisible or getPossession
}
else if (to == NULL)
{
printf("There is nobody here to give that to.\n");
}
else if (obj->location == NULL)
{
printf("That is way too heavy.\n");
}
else
{
describeMove(obj, to);
obj->location = to;
}
}
<move.h>
extern void moveObject(OBJECT *obj, OBJECT *to);
Image of the issue in VSC:
https://i.stack.imgur.com/5mkzV.png
Your code doesn't compile as it relies on header files you haven't shared with us, and executeAsk() for which we have no implementation. I removed the missing bits from parsexec.c:
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
bool parseAndExecute(char *input) {
char *verb = strtok(input, " \n");
char *noun = strtok(NULL, " \n");
if (verb != NULL) {
printf("I don't know how to '%s'.\n", verb);
}
return true;
}
and was then able to build and execute your game:
gcc main.c parsexec.c -o game && ./game
Welcome to Little Cave Adventure.
I don't know how to 'look'.
--> look
I don't know how to 'look'.
--> ^C
This tells me it's a build issue. Specifically, you are probably not linking parsexec.o to your binary.
It turned out to be a faulty compiler/settings in VSC as the code ran fine on a different machine.
I have a problem that I decided to solve using binary tree, however:
I can't think of a way to fill the tree with predetermined elements so that it looks like the following in the image
I used a vector as follows, and then I inserted it into the tree, I don't know if I just leave it in the order the tree will be assembled as in the image, but what I did was the following:
char* dict[] = {
"Mamifero","aves","repteis",
"quadrupede", "bipede", "voadores", "aquaticos",
"nao-voadoras", "nadadoras", "de rapina", "com casco", "carnivoros", "sem patas",
"carnivoro", "herbivoro", "onivoro", "afrutifero", "tropical", "polar",
"leao", "cavalo", "homem", "macaco", "morcego", "baleia", "avestruz", "pinguim",
"pato", "aguia", "tartaruga", "crocodilo", "cobra"
};
typedef struct Animal *animalptr;
typedef struct Animal {
char *str;
animalptr left, right;
} Animal;
typedef int (*compare)(const char*, const char*);
void insert (char* key, Animal** leaf, compare cmp) {
int res;
if (*leaf == NULL) {
*leaf = (Animal*) malloc(sizeof(Animal));
(*leaf)->str = malloc(strlen(key) + 1);
strcpy ((*leaf)->str, key);
(*leaf)->left = NULL;
(*leaf)->right = NULL;
// printf("\nnew node for %s", key);
}
else {
// printf("%d\n", res);
res = cmp (key, (*leaf)->str);
if (res < 0) insert (key, &(*leaf)->left, cmp);
else if (res > 0) insert (key, &(*leaf)->right, cmp);
else printf("key '%s' already in tree\n", key);
}
}
int cmpStr (const char* a, const char* b) {
// printf("a = %d\n b = %d", strlen(a), strlen(b));
return (strcmp (a,b));
}
fill it in as follows:
int main () {
Animal *parent = NULL;
char q;
// printf("%ld\n", sizeof(dict));
// insert(dict[0], &parent, (compare)cmpStr);
// printTree(parent);
for (int i = 0; i < NUM_NODES; i++) {
insert(dict[i], &parent, (compare)cmpStr);
}
printf ("%s", search(parent, "", (compare)cmpStr)->str);
// printTree(parent);
// do {
// // scanf("%c", &q);
// // printf("%s?", dict[rand() % 32]);
// // }while (q != 'q');
return 0;
}
so now my saga would be how to apply some weight to each word, to direct it to one side or the other, the exercise I'm trying to solve in this way is this:
Build a program that is able to conclude which of the following animals
was chosen through questions and answers. Possible animals: lion, horse, man,
monkey, whale, ostrich, penguin, duck, eagle, turtle, crocodile and snake.
teste
Each word can be marked with a parent-child relationship, weight = parent's weight + own serial number under the same parent, like
Mamifero => "1"
aves => "2"
repteis => "3"
bipede => "12" (second child under Mamifero)
afrutifero => "122" (second child under bipede)
If the prefixes are the same, it means that there is a parent-child relationship, insert it on the right side of the tree, otherwise insert it on the left side of the tree
Please see the modified code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct words {
char *weight;
char *name;
} Words;
Words dict[] = {
{"1", "Mamifero"},
{"2", "aves"},
{"3", "repteis"},
{"11", "quadrupede"},
{"12", "bipede"},
{"13", "voadores"},
{"14", "aquaticos"},
{"21", "nao-voadoras"},
{"22", "nadadoras"},
{"23", "de rapina"},
{"31", "com casco"},
{"32", "carnivoros"},
{"33", "sem patas"},
{"111", "carnivoro"},
{"112", "herbivoro"},
{"121", "onivoro"},
{"122", "afrutifero"},
{"211", "tropical"},
{"212", "polar"},
{"1111", "leao"},
{"1121", "cavalo"},
{"1211", "homem"},
{"1221", "macaco"},
{"131", "morcego"},
{"141", "baleia"},
{"2111", "avestruz"},
{"2121", "pinguim"},
{"221", "pato"},
{"231", "aguia"},
{"311", "tartaruga"},
{"321", "crocodilo"},
{"331", "cobra"}
};
#define NUM_NODES (sizeof(dict)/sizeof(*dict))
typedef struct Animal *animalptr;
typedef struct Animal {
char *weight;
char *str;
animalptr left, right;
} Animal;
typedef int (*compare)(const char *, const char *);
void insert(Words *key, Animal **leaf, compare cmp)
{
int res;
if (*leaf == NULL) {
*leaf = (Animal *) malloc(sizeof(Animal));
(*leaf)->str = strdup(key->name);
(*leaf)->weight = strdup(key->weight);
(*leaf)->left = NULL;
(*leaf)->right = NULL;
} else {
res = cmp(key->weight, (*leaf)->weight);
if (res < 0) insert(key, &(*leaf)->left, cmp);
else if (res > 0) insert(key, &(*leaf)->right, cmp);
else printf("key '%s' already in tree\n", key->name);
}
}
int cmpStr(const char *a, const char *b)
{
if (strcmp(a, b) == 0)
return 0;
// If the prefixes are the same, it means a is a child of b, insert on the right
if (strncmp(a, b, strlen(b)) == 0)
return 1;
// Otherwise insert left
return -1;
}
char *search(Animal *leaf)
{
char *ret = "";
char buf[16];
while (leaf) {
if (!leaf->right && !leaf->left) {
ret = leaf->str;
break;
}
// guess
printf("É %s (yes,no): ", leaf->str);
fgets(buf, sizeof(buf), stdin);
if ((*buf == 'q') || (*buf == 'Q'))
break;
// If yes, go to the right
if ((*buf == 'y') || (*buf == 'Y'))
leaf = leaf->right;
// Otherwise, left
else if ((*buf == 'n') || (*buf == 'N'))
leaf = leaf->left;
}
return ret;
}
int main()
{
Animal *parent = NULL;
for (int i = 0; i < NUM_NODES; i++) {
insert(&dict[i], &parent, (compare)cmpStr);
}
printf("%s\n", search(parent));
return 0;
}
i am writing a Generic ADT using C and i keep getting a segmentation fault when i free an element
PairResult pairClear(Pair pair)
{
if(pair == NULL)
{
return PAIR_NULL_ARGUMENT;
}
KeyElement key=pair->key;
DataElement data=pair->data;
if(key)
pair->free_key(key);//i get the Error here
if(data)
pair->free_data(data);
return PAIR_SUCCESS;
}
the memory for key and data is allocated :
Pair pairCreate( KeyElement key, DataElement data,
copyDataElements copy_data,
freeDataElements free_data,
copyKeyElements copy_key,
freeKeyElements free_key)
{
Pair pair = malloc(sizeof(*pair));
if(pair == NULL)
{
return NULL;
}
pair->copy_data=copy_data;
pair->copy_key=copy_key;
pair->free_data=free_data;
pair->free_data=free_key;
KeyElement new_string_key = copy_key(key);
DataElement new_string_data = copy_data(data);
if((new_string_key == NULL) || (new_string_data == NULL))
{
pairDestroy(pair);
return NULL;
}
pair->key = new_string_key;
pair->data = new_string_data;
return pair;
}
this pairDestroy
void pairDestroy(Pair pair)
{
if(pair == NULL)
{
return;
}
#ifndef NDEBUG
PairResult result =
#endif
pairClear(pair);
assert(result == PAIR_SUCCESS);
free(pair);
}
these are the copy functions used:
static KeyElement copyKeyInt(KeyElement n) {
if (!n) {
return NULL;
}
int *copy = malloc(sizeof(*copy));
if (!copy) {
return NULL;
}
*copy = *(int *) n;
return copy;
}
static DataElement copyDataChar(DataElement n) {
if (!n) {
return NULL;
}
char *copy = malloc(sizeof(*copy));
if (!copy) {
return NULL;
}
*copy = *(char *) n;
return (DataElement) copy;
}
and these are the free functions used
static void freeInt(KeyElement n) {
free(n);
}
static void freeChar(DataElement n) {
free(n);
}
and here is the struct of pair
struct Pair_t {
KeyElement key;
DataElement data;
copyDataElements copy_data;
freeDataElements free_data;
copyKeyElements copy_key;
freeKeyElements free_key;
};
these are all the typedef used :
typedef struct Pair_t* Pair;
typedef enum PairResult_t {
PAIR_SUCCESS,
PAIR_OUT_OF_MEMORY,
PAIR_NULL_ARGUMENT,
} PairResult;
typedef void *DataElement;
typedef void *KeyElement;
typedef DataElement(*copyDataElements)(DataElement);
typedef KeyElement(*copyKeyElements)(KeyElement);
typedef void(*freeDataElements)(DataElement);
typedef void(*freeKeyElements)(KeyElement);
and a main function so that u could reproduce it
int main()
{
Pair pair;
for (int i = 1; i < 1000; ++i) {
char j = (char) i;
++j;
pair=pairCreate(&i,&j,copyDataChar,freeChar,copyKeyInt,freeInt);
pairDestroy(pair);
}
I added everything I could for a reproducible code
if anything should be edited please tell me in the comments
Pair pairCreate(...) {
...
pair->free_data = free_data;
pair->free_data = free_key;
// ^^^^^^^^^ UH OH
...
You owe me 15 mins of debugging time.
How should I print StackArray in C?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct
{
void** stackAry;
int count;
int stackMax;
int top;
}STACK;
STACK* createStack(int maxSize)
{
STACK* stack;
stack = (STACK*)malloc(sizeof(STACK));
if(!stack)
return NULL;
stack->count = 0;
stack->top = -1;
stack->stackMax = maxSize;
stack->stackAry = (void**)calloc(stack->stackMax, sizeof(void*));
if(!stack->stackAry)
{
free(stack);
return NULL;
}
return stack;
}
bool pushStack(STACK* stack, void* itemPtr)
{
if(stack->count == stack->stackMax)
return false;
(stack->count)++;
(stack->top)++;
stack->stackAry[stack->top] = itemPtr;
return true;
}
void* popStack(STACK* stack)
{
void* dataPtrOut;
if(stack->count == 0)
dataPtrOut = NULL;
else
{
dataPtrOut = stack->stackAry[stack->top];
(stack->count)--;
(stack->top)--;
}
return dataPtrOut;
}
void* stackTop(STACK* stack)
{
if(stack->count == 0)
return NULL;
else
return stack->stackAry[stack->top];
}
bool emptyStack(STACK* stack)
{
return(stack->top == -1);
}
bool fullStack(STACK* stack)
{
return (stack->count == stack->stackMax);
}
int stackCount(STACK* stack)
{
return stack->count;
}
STACK* destroyStack(STACK* stack)
{
int i;
if(stack)
{
for(i=0 ; i<stack->count ; i++)
free(stack->stackAry[i]);
free(stack->stackAry);
free(stack);
}
return NULL;
}
int main(void)
{
STACK* myStack = createStack(100);
double* ptr;
while(1)
{
ptr = (double*)malloc(sizeof(double));
if(ptr == NULL)
return 0;
else
{
printf("Enter a positive real number: <-1> to stop: \n");
scanf("%lf", ptr);
if(*ptr == -1.0 || fullStack(myStack))
{
break;
}
else
pushStack(myStack, ptr);
}
}
printf("\n\nThe list of numbers reversed: \n");
while(!emptyStack(myStack))
{
ptr = (double*)popStack(myStack);
printf("%lf\n", *ptr);
free(ptr);
}
myStack = destroyStack(myStack);
return 0;
}
When I run the stackAry, the main part doesn't print.
The stack part does not seem to be a problem, but if you print it, "Enter a positive real number: <-1> to stop:" is not printed. If you enter numbers on a blank screen and press -1, it will be printed.
I'm not sure which part is wrong. Please help me
I was practising some data structures problems that I did previously but this time I don't know what is going wrong in my code. I looked over a long time but I did not found the mistake. When I'm printing I'm just getting the first character and it looks like e is not being updated. But I've written e++.
#include<stdio.h>
#include "ctype.h"
int stack[20];
int top = -1;
void push(int x)
{
stack[++top] = x;
}
int pop()
{
return stack[top--];
}
int priorityof(char x)
{
if(x=='(')
return 3;
else if(x=='+'|| x=='-')
return 1;
else if(x=='*'|| x=='/')
return 2;
}
int main()
{
char exp[20];
char *e;
e=exp;char x;
scanf("%c",exp);
while(*e!='\0')
{
if(isalnum(*e))
{
printf("%c", *e);
}
else if(*e=='(')
{
push(*e);
}
else if(*e==')')
{
while((x=pop())!='(')
printf("%c",x);
}
else {
while (priorityof(stack[top]) >= priorityof(*e)) {
printf("%c", pop());
push(*e);
}
}
e++;
}
while(top!=-1)
{
printf("%c",pop());
}
}
%c is for single character and reading your question it seems like you are giving more than one character so its a string, use %s.
#include<stdio.h>
#include "ctype.h"
int stack[20]; int top = -1;
void push(int x) {
stack[++top] = x;
}
int pop() { return stack[top--]; }
int priorityof(char x) {
if(x=='(') return 3;
else if(x=='+'|| x=='-') return 1;
else if(x=='*'|| x=='/') return 2;
}
int main() {
char exp[20];
char *e;
e=exp;char x;
scanf("%s",exp);
while(*e!='\0') { if(isalnum(*e)) { printf("%c", *e); } else if(*e=='(') { push(*e); } else if(*e==')') { while((x=pop())!='(') printf("%c",x); } else { while (priorityof(stack[top]) >= priorityof(*e)) { printf("%c", pop()); push(*e); } } e++; } while(top!=-1) { printf("%c",pop()); } }