CS50 Pset 5 Hashtable issue - hashtable

After creating a hash table and assigning each letter to a value for the table, i am noticing the first word output by the table for the beginning of every linked list is the same word. Somehow it seems I am transferring the entire dictionary to each array in the table even though I have attempted to separate them. Any assistance would be awesome! Thanks in advance
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char *word;
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 25;
// Hash table
node *table[N];
char lowerword[LENGTH+1];
// Returns true if word is in dictionary else false
bool check(const char *word)
{
int bucketfind = 0;
int x = 0;
for (int b = word[x]; b != '\0';b = word[x], x++)
{
int lowertemp = tolower(word[x]);
if (x == 0)
{
bucketfind = lowertemp - 97;
}
char lowerfinal = lowertemp;
lowerword[x] = lowerfinal;
//printf("%c", lowerword[x]);
}
int wordlen = x + 1;
int pr = 0;
while (table[bucketfind] -> next != NULL)
{
int dwlen = strlen(table[bucketfind]-> word);
pr++;
//printf("%i, %i, %s, %i\n", pr, dwlen, table[bucketfind] -> word, bucketfind);
}
//TODO
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
int asciifirst = word[0];
int lowerfirst = tolower(asciifirst);
int bucketnum = lowerfirst - 97;
return bucketnum;
}
// Loads dictionary into memory, returning true if successful else false
int dictwords = 0;
//char *cword = (char*)malloc(sizeof(char)*46);
bool load(const char *dictionary)
{
char *cword = malloc(sizeof(char)*46);
FILE *dict = fopen(dictionary, "r");
if (dictionary == NULL)
{
return false;
}
int x = 0;
while ((fscanf(dict, "%s", cword) != EOF))
{
node *nword = malloc(sizeof(node));
nword -> word = cword;
nword -> next = NULL;
int bucket = hash(cword);
//printf("%i\n", bucket);
if (table[bucket] != NULL)
{
nword -> next = table[bucket];
table[bucket] = nword;
}
else
{
table[bucket]= nword;
}
dictwords++;
}
fclose(dict);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
return dictwords;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
// TODO
return false;
}

It's not just the first word; every word in the linked list is the same word (the last one read). cword gets 46 bytes of memory at a specific address here char *cword = malloc(sizeof(char)*46);. Every word from dictionary is read into that same address.

Related

memmove implementation throws segmentation fault while copying a character array

Hi I tried to write my own version of memmove and I find the following code resulting in a segmentation fault. It would be great if someone could help me figure out why this behavior would occur!
However, when I use something like:
char source[20] = "Hello, this is Piranava", the code works fine!
void *memmoveLocal(void *dest, const void *src, unsigned int n)
{
char *destL = dest;
const char *srcL = src;
int i = 0;
if(dest == NULL || src == NULL)
{
return NULL;
}
else
{
// if dest comes before source, even if there's an overlap, we should move forward
// because if there's an overlap (when dest < src) and we move backward, we'd overwrite the overlapping bytes in src
if(destL < srcL)
{
printf("Forward\n");
while(i < n)
{
destL[i] = srcL[i];
i++;
}
}
else // in all other cases (even if there's overlap or no overlap, we can move backward)
{
printf("Backward\n");
i = n - 1;
while(i >= 0)
{
destL[i] = srcL[i];
i--;
}
}
}
return dest;
}
void main()
{
char *source = "Hello, this is ABC";
char *destination = malloc(strlen(source)+1);
memmoveLocal(source+5, source, 5);
printf("Source: %s \nDestination: %s, size: %d\n", source, destination, strlen(destination));
}
However, if I replace
char *source = "Hello, this is ABC";
with
char source[20] = "Hello, this is ABC";
, it works fine!
memmoveLocal(source+5, source, 5);
You are trying to overwrite a string literal, which is not writable.
Did you intend to memmoveLocal(destination, source+5, 5) instead?
char source[20] = "Hello, this is ABC";
That turns source from a string literal into a char[] array initialized with a string literal. The array is writable, so your program no longer crashes.

Tree returning the maximum value

50
/ \
30 70 (( which should return 50+70=120 ))
int MyFunction(struct node *root){
struct node *ptr=root;
int leftsum=0;
int rightsum=0;
if(ptr==NULL){
return;
}
else{
MyFunction(ptr->left);
leftsum=leftsum+ptr->key;
MyFunctipn(ptr->right);
rightsum=rightsum+ptr->key;
return (root->key+max(leftsum,rightsum));
}
}
for that, I've written this code. Maybe it is wrong so please help me as I'm new in this field. I want to write a recursive code such a way that it compares two leaf node(left and right) and returns the maximum to the parent nood.
The recursive function should look something like this:
int getMaxPath(Node* root){
// base case, We traveled beyond a leaf
if(root == NULL){
// 0 doesn't contribute anything to our answer
return 0;
}
// get the max current nodes left and right children
int lsum = getMaxPath(root->left);
int rsum = getMaxPath(root->right);
// return sum of current node value and the maximum from two paths starting with its two child nodes
return root->value + std::max(lsum,rsum);
}
Full code:
#include <iostream>
struct Node{
int value;
Node* left;
Node* right;
Node(int val){
value = val;
left = NULL;
right = NULL;
}
};
// make a tree and return a pointer to it's root
Node* buildTree1(){
/* Build tree like this:
50
/ \
30 70
*/
Node* root= new Node(50);
root->left = new Node(30);
root->right = new Node(70);
}
int getMaxPath(Node* root){
if(root == NULL){
// 0 doesn't contribute anything to our answer
return 0;
}
int lsum = getMaxPath(root->left);
int rsum = getMaxPath(root->right);
return root->value + std::max(lsum,rsum);
}
int main() {
using namespace std;
Node* root = buildTree1();
int ans = getMaxPath(root);
cout<< ans <<endl;
return 0;
}
int Sum(struct node *root)
{
if(root->left == NULL && root->right== NULL)
return root->key;
int lvalue,rvalue;
lvalue=Sum(root->left);
rvalue=Sum(root->right);
return root->key+max(lvalue,rvalue);
}
int max(int r,int j)
{
if(r>j)
return r;
else
return j;
}

Having trouble adding characters to a linked list structure?

I am currently unsuccessful at being prompt to add a char for my current program. I am able to add a digit but it will post the prompt to add a character but skips to input portion and directly asks me if I want to continue.
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
main()
{
struct node
{
int num;
char gender[3];
struct node *ptr;
};
typedef struct node NODE;
NODE *head, *first, *temp = 0;
int count = 0;
int choice = 1;
first = 0;
while (choice)
{
head = (NODE *)malloc(sizeof(NODE));
printf("Enter the Student Identification Number\n");
scanf("%d", &head-> num);
printf("Enter the Student gender (M)or(F)\n");
scanf("%c", &head-> gender);
if (first != 0)
{
temp->ptr = head;
temp = head;
}else
{
first = temp = head;
}
fflush(stdin);
printf("Would you like to do another entry(Type No(0) or Yes(1))?\n");
scanf("%d", &choice);
}
temp->ptr = 0;
/* reset temp to the beginning */
temp = first;
printf("\nStudent Information\n");
while (temp != 0)
{
printf("Student ID number: %d\n", temp->num);
printf("Student gender: %c\n", temp->gender);
count++;
temp = temp -> ptr;
}
printf("No. of Students inputted into system: %d\n", count);
}

How to split a string using a specific delimiter in Arduino?

I have a String variable and I want to extract the three substrings separeted by ; to three string variables.
String application_command = "{10,12; 4,5; 2}";
I cannot use substring method because this string can be like any of the following or similar patterns also.
String application_command = "{10,12,13,9,1; 4,5; 2}"
String application_command = "{7; 1,2,14; 1}"
The only thing that is common in these patterns is there are three sections separated by ;.
Any insight is much appreciated.
Thank you
I think you need a split-string-into-string-array function with a custom separator character.
There are already several sources on the web and at stackoverflow (e.g. Split String into String array).
// https://stackoverflow.com/questions/9072320/split-string-into-string-array
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==separator || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
You can use this function as follows (with ";" as separator):
String part01 = getValue(application_command,';',0);
String part02 = getValue(application_command,';',1);
String part03 = getValue(application_command,';',2);
EDIT: correct single quotes and add semicolons in the example.
The new SafeString Arduino library (available from the library manager) provides a number of tokenizing/substring methods without the heap fragmentation of the String class
See https://www.forward.com.au/pfod/ArduinoProgramming/SafeString/index.html
for a detailed tutorial
In this case your can use
#include "SafeString.h"
void setup() {
Serial.begin(9600);
createSafeString(appCmd, 50); // large enought for the largest cmd
createSafeString(token1, 20);
createSafeString(token2, 20);
createSafeString(token3, 20);
appCmd = "{10,12,13,9,1; 4,5; 2}";
size_t nextIdx = 1; //step over leading {
nextIdx = appCmd.stoken(token1, nextIdx, ";}");
nextIdx++; //step over delimiter
nextIdx = appCmd.stoken(token2, nextIdx, ";}");
nextIdx++; //step over delimiter
nextIdx = appCmd.stoken(token3, nextIdx, ";}");
nextIdx++; //step over delimiter
// can trim tokens if needed e.g. token1.trim()
Serial.println(token1);
Serial.println(token2);
Serial.println(token3);
}
void loop() {
}
Also look at pfodParser which parses these types of messages { } for use by pfodApp.
Do not forget to call delete[] to free the memory after the use of the array, that said here is my solution:
String* split(String& v, char delimiter, int& length) {
length = 1;
bool found = false;
// Figure out how many itens the array should have
for (int i = 0; i < v.length(); i++) {
if (v[i] == delimiter) {
length++;
found = true;
}
}
// If the delimiter is found than create the array
// and split the String
if (found) {
// Create array
String* valores = new String[length];
// Split the string into array
int i = 0;
for (int itemIndex = 0; itemIndex < length; itemIndex++) {
for (; i < v.length(); i++) {
if (v[i] == delimiter) {
i++;
break;
}
valores[itemIndex] += v[i];
}
}
// Done, return the values
return valores;
}
// No delimiter found
return nullptr;
}
Here is an example of how to use:
void loop() {
String test = "1,2,3,4,5";
int qtde;
String* t = split(test, ',', qtde);
for (int i = 0; i < qtde; i++) {
Serial.println(t[i]);
delay(1000);
}
delete[] t;
}

casting a struct in c

I need an array of user structs.
struct user {
char *username;
};
struct user users[10]; //Array of user structs
int main(int argc, char **args) {
int initUsersArray();
char *username = "Max";
addToUsersArrry(username);
}
int addToUsersArrry(username) {
int i;
i = 0;
struct user tmp;
for(i;i<10;i++) {
if(users[i] != NULL)
if(strcmp(*users[i].username,username)==0)
return -1;
}
i = 0;
for(i;i<10;i++) {
if(users[i] = NULL) {
users[i]=tmp;
users[i].username=username;
return 1;
}
}
}
int initUsersArray() {
int i;
i=0;
struct user tmp;
for(i;i<10;i++) {
users[i] = (struct user*) calloc(1,sizeof(tmp));
}
}
My first question is, if it is the right way to init the users array with NULL like i did.
The second problem is, that
*users[i].username
and other parts of code where want to get/set the user at a specific position, dont work.
Regards
Here, I fixed it for you. And don't forget to diff and learn something. Don't just c/p it.
#include <stdio.h>
#include <stdlib.h>
typedef struct user {
char *username;
} user;
user *users; //Array of user structs
int addToUsersArray(char *username) {
int i = 0;
for(; i<10; i++) {
if(users[i].username=='\0') {
users[i].username = username;
return 1;
} else if(strcmp(users[i].username, username) == 0)
return -1;
}
return -1;
}
void initUsersArray() {
users = (user*) calloc(10, sizeof(user)); //10 of them
}
int main(int argc, char** argv) {
initUsersArray();
char *username = "Max";
addToUsersArray(username);
username = "Ma1x";
addToUsersArray(username);
printf("%s\n",users[0].username);
printf("%s\n",users[1].username);
return 1;
}

Resources