Array of Chars as Queue in C - c

I'm coding a piece of code for AVR. I want to build a queue that can push and pop, and this queue is an array of chars (string). So when I push 'a':
['b', 'c', 'd', 'e', 'f']
becomes:
['a','b', 'c', 'd', 'e', 'f']
and when I pop, f comes out. I've written this code, but it only pushes 1 char to the queue, as if it removes the whole queue. Here's my code for the queue:
char queue[50] = "";
char* queue_tail = &queue[0];
char* queue_head = &queue[0];
void queue_push(char l_item)
{
if(queue_head != &queue[strlen(queue) - 1]) //if queue is not full, do the job
{
//Push all elements one step further
char* traveler = queue_head;
for(; traveler != queue_tail; --traveler)
{
*(traveler+1) = *traveler;
*traveler = '';
}
++queue_head;
*queue_tail = l_item;
}
}
char queue_pop()
{
char temp = *queue_head;
*queue_head = '';
--queue_head;
return temp;
}
This is my main function:
#include <mega32.h>
#include <alcd.h>
#include <delay.h>
#include <string.h>
void main(void)
{
const char text[] = "Hello world!";
int col_counter = 0;
char* p_head = '';
lcd_init(32);
p_head = &text[12];
while(1)
{
lcd_clear();
if(col_counter + strlen(text) > 32)
{
queue_push(*p_head);
--p_head;
}
lcd_gotoxy(col_counter, 0);
lcd_puts(text);
lcd_gotoxy(0,0);
lcd_puts(queue);
delay_ms(200);
++col_counter;
}
}
Any help would be appreciated. Thanks in advance.

I changed the meaning of queue_head from the last element to one past the last element in the queue, and adjusted the code.
Here is a corrected code (main() in this code is a test code for usual PC):
#include <stdio.h>
char queue[50] = "";
char* queue_tail = &queue[0];
char* queue_head = &queue[0];
void queue_push(char l_item)
{
if(queue_head != queue + sizeof(queue)/sizeof(*queue)) //if queue is not full, do the job
{
//Push all elements one step further
char* traveler = queue_head;
for(; traveler != queue_tail; --traveler)
{
*traveler = *(traveler - 1);
}
++queue_head;
*queue_tail = l_item;
}
}
char queue_pop(void)
{
char temp;
if (queue_head == queue_tail) return '\0'; // the queue is empty
--queue_head;
temp = *queue_head;
*queue_head = '\0';
return temp;
}
int main(void) {
queue_push(100);
queue_push(110);
printf("%d\n",queue_pop());
printf("%d\n",queue_pop());
return 0;
}

Proposal for a circular buffer implementation (obviating the need to copy the buffer's content to and fro):
char queue[50] = "";
char* queue_tail = &queue[0];
char* queue_head = &queue[0];
#define END_OF_QUEUE (&queue[sizeof(queue)/sizeof(*queue)]) // The first element _after_ the buffer.
#define QUEUE_NOT_FULL 0
#define QUEUE_IS_FULL 1
uint8_t queueState;
void queue_push(const char l_item)
{
// 0) Addition is always modulus buffer size (50)
// 1) head points to the next empty location which can store an incoming byte
// 2) tail points to the next location from where a byte may be read
// 3) Queue is empty iff tail == head && queueState == QUEUE_NOT_FULL
// 4) Queue is full iff tail == head && queueState == QUEUE_IS_FULL
if ( queueState == QUEUE_NOT_FULL ) {
// Store item to the current head:
*queue_head = l_item;
// Advance head by one:
queue_head++;
if ( queue_head == END_OF_QUEUE ) {
// head passed the end of buffer -> continue at the start:
queue_head = &queue[0];
}
// If head meets tail after appending the new element, the buffer is now full.
if ( queue_head == queue_tail ) {
queueState = QUEUE_IS_FULL;
}
} else {
// Buffer overflow! - Options: Ignore new data, overwrite old data, wait until not full, signal an error somehow.
}
}
char queue_pop()
{
if ( (queue_tail == queue_head) && (queueState == QUEUE_NOT_FULL) ) {
// Queue is empty. "Buffer underflow." - Options: Return dummy value, wait until data available, signal an error somehow.
return '\0';
} else {
const char result = *queue_tail;
queue_tail++;
if ( queue_tail == END_OF_QUEUE ) {
// tail passed the end of buffer -> continue at the start:
queue_tail = &queue[0];
}
// We just removed an element from the queue, so the queue cannot be full now even if it was full a moment ago.
queueState = QUEUE_NOT_FULL;
return result;
}
}
(Note that, without further synchronization elements, this code will not work correctly when running concurrently, i.e. when accessing the buffer (read or write) from within an ISR.)

Related

How do I debug a Segmentation fault when I nothing is wrong before the fault or after?

The particular problem I have is that in my main function, I have added a print statement before and after I call the "bad" function. It always shows the before statement, but never the after statement. I also added a print statement to the end of the "bad" function, and I can see that it runs properly to the very last line of the "bad" function, so it should return normally. After the functions last print and before the main function print, I get the segfault. Any ideas? Here is the code:
int main(int argc, char* argv[])
{
char myItem[100];
int i = 0;
while (i < 100) {
scanf("%[^\n]", myItem);
i++;
if (myItem == EOF) {
break;
}
int c;
while ((c = getchar()) != '\n' && c != EOF);
//printf("string read in from user typing: %s\n", myItem);
printf("i = %d\n", i);
emailFilter(myItem);
printf("done with email filter in main\n");
//printf("item from this pass is:%s\n\n", myItem);
}
return 0;
}
and the "bad" function:
void emailFilter(char* mySubject)
{
printf(" Just entered the emailFilter() .\n");
char * event_holder[5]; //holds five separate char ptrs
for (int i = 0; i < 5; i++)
{
event_holder[i] = ((char*)malloc(100 * sizeof(char*)));
}
char command_type = parseSubject(mySubject, event_holder); //parses subject line and fills event_holder. returns command type, from parsing
//call proper parsing result
if (command_type == 'C')
{
create(event_holder);
}
else if (command_type == 'X')
{
change(event_holder);
}
else if (command_type == 'D')
{
delete(event_holder);
}
printf("Leaving emailfilter()...\n");
}
and running this code provides me:
$:
i = 1
Just entered the emailFilter() .
C, Meeting ,01/12/2019,15:30,NEB202
Leaving emailfilter()...
done with email filter in main
i = 2
Just entered the emailFilter() .
Leaving emailfilter()...
Segmentation fault
This shows that I always make it through the function, but still don't return properly.
Here is my entire code to reproduce the error.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
char * event_data[5];
struct node * next;
};
struct node *head = NULL;
struct node *current = NULL;
char* earliest = NULL;
char* substring (char* orig, char* dest, int offset, int len)
{
int input_len = strlen (orig);
if (offset + len > input_len)
{
return NULL;
}
strncpy (dest, orig + offset, len);
//add null char \0 to end
char * term = "\0";
strncpy (dest + len, term, 1);
return dest;
}
char * firstItem(char* shortenedSubject)
{
int i = 0;
int currentLength = 0;
int currentCharIndex = 0;
int eventIndex = 0;
char * toReturn = (char*)malloc(100);
while ((shortenedSubject[currentLength] != '\0') && (shortenedSubject[currentLength] != ',') )//50 is my safety num to make sure it exits eventually
{
currentLength++;
}
if (shortenedSubject[currentLength] == ',') {
substring(shortenedSubject, toReturn, 0, currentLength);
}
return toReturn;
}
char parseSubject(char* subject,char * eventDataToReturn[5]) //returns "what type of command called, or none"
{
char toReturn;
char * shortenedSubject = (char*)malloc(100);
substring(subject,shortenedSubject,9,strlen(subject)-9);//put substring into tempString
int currentCharIndex = 0;// well feed into index of substring()
int eventIndex = 0; //lets us know which event to fill in
int currentLength = 0;//lets us know length of current event
int i = 0; //which char in temp string were alooking at
char * action = firstItem(shortenedSubject);
if (strlen(action) == 1)
{
if ( action[0] == 'C')
{
toReturn = 'C';
}
else if (action[0] == 'X')
{
toReturn = 'X';
}
else if (action[0] == 'D')
{
toReturn = 'D';
}
else
{
toReturn = 'N'; //not valid
//invalid email command, do nothing
}
}
else
{
toReturn = 'N'; //not valid
//invalid email command, do nothing
}
char* debug2;
while ((shortenedSubject[i] != '\0') && (i <= 50) )//50 is my safety num to make sure it exits eventually
{
char debugvar = shortenedSubject[i];
currentLength++;
if (shortenedSubject[i] == ',')
{
//eventDataToReturn[i] = substring2(shortenedSubject,currentCharIndex,currentLength);
substring(shortenedSubject,eventDataToReturn[eventIndex],currentCharIndex,currentLength-1);
debug2 = eventDataToReturn[eventIndex];
currentCharIndex= i +1;
eventIndex++;
currentLength = 0;
//i++;
}
i++;
}
substring(shortenedSubject,eventDataToReturn[4],currentCharIndex,currentLength);
return toReturn;
}
void printEventData(char* my_event_data[])
{
//printf("\nPrinting event data...\n");
for (int i = 1; i < 4; i++)
{
printf("%s,",my_event_data[i]);
}
//print last entry, no comma
printf("%s",my_event_data[4]);
}
void printEventsInorder()
{
struct node * ptr = head;
while (ptr != NULL)//if not empty, check each one and add when ready
{
printEventData(ptr->event_data);
printf("\n");
ptr = ptr->next;
}
}
void insertFront(char* my_event_data[5])
{
struct node *link = (struct node*) malloc(sizeof(struct node));
link->next = NULL;
for (int i = 0; i < 5; i++)
{
link->event_data[i] = my_event_data[i];
}
head = link;
}
int isEarlier(char* event_data_L[5], char* event_data_R[5])
{// will be given like 12:30 12:45,turn timeL into timeL1 and timeL2, and time R1 and timeR2
//compare dates for earlier
int month_L,day_L,year_L;
int month_R,day_R,year_R;
char* char_holder;
substring(event_data_L[2],char_holder,0,2);//extract first half of time
month_L = atoi(char_holder); //convert first half of time to int
substring(event_data_L[2],char_holder,3,2);//extract first half of time
day_L = atoi(char_holder); //convert first half of time to int
substring(event_data_L[2],char_holder,6,4);//extract first half of time
year_L = atoi(char_holder); //convert first half of time to int
substring(event_data_R[2],char_holder,0,2);//extract first half of time
month_R = atoi(char_holder); //convert first half of time to int
substring(event_data_R[2],char_holder,3,2);//extract first half of time
day_R = atoi(char_holder); //convert first half of time to int
substring(event_data_R[2],char_holder,6,4);//extract first half of time
year_R = atoi(char_holder); //convert first half of time to int
int time_L1,time_L2,time_R1,time_R2;
substring(event_data_L[3],char_holder,0,2);//extract first half of time
time_L1 = atoi(char_holder); //convert first half of time to int
substring(event_data_L[3],char_holder,3,2);//extract second half of time
time_L2 = atoi(char_holder); //convert second half of time to int
substring(event_data_R[3],char_holder,0,2);
time_R1 = atoi(char_holder);
substring(event_data_R[3],char_holder,3,2);
time_R2 = atoi(char_holder);
//convert to 2 ints, first compare left ints, then right ints
if(year_L < year_R)
{
return 1;
}
else if ( year_L == year_R)
{
if (month_L < month_L)
{
return 1;
}
else if (month_L == month_L)
{
if (day_L < day_R)
{
return 1;
}
else if (day_L == day_R)
{
if (time_L1 < time_R1)
{
return 1;
}
else if (time_L1 == time_R1)
{
if (time_L2 < time_R2)
{
return 1;
}
else if (time_L2 == time_R2)
{
return 2;
}
else//else, time is greater
{
return 3;
}
}
else //left time is greater, return 3
{
return 3;
}
}
else
{
return 3;
}
}
else
{
return 3;
}
}
else //its left is greater than right so return 3 to show that
{
return 3;
}
}
void create(char* my_event_data[5]) {
//print required sentence
char * debugvar2 = my_event_data[3];
if (head == NULL)//if empty calendar, just add it
{
insertFront(my_event_data);
//printf("EARLIEST bc empty list, \n");
printf("C, ");
printEventData(my_event_data);
printf("\n");
return;
}
else
{
struct node *link = (struct node*) malloc(sizeof(struct node));
link->next = NULL;
for (int i = 1; i < 5; i++)
{
link->event_data[i] = my_event_data[i];
}
struct node *ptr = head;
struct node *prev = NULL;
if (ptr->next == NULL) //if this is the last node to check against
{
if (isEarlier(my_event_data, ptr->event_data) == 1)
{ //check against it
printf("C, ");
printEventData(my_event_data);
printf("\n");
if (prev != NULL) //if this is first item in linked list...
{
link->next = head; //assign something before head
head = link; //move head to that thing
}
if (prev != NULL)
{
prev->next = link;
}
link->next = ptr;
return;
}
else //else is equal to or later, so tack it on after:
{
ptr->next = link;
}
}
else
{
while (ptr->next != NULL)//if not empty, check each one and add when ready
{
//if next node is later than current, we are done with insertion
if (isEarlier(my_event_data,ptr->event_data) == 1)
{
if (head == ptr) //if earlier than head... insert and print
{
//printf("earlier than head!");
printf("C, ");
printEventData(my_event_data);
printf("\n");
link->next = ptr;
head = link;
}
else //if earlier than non head, insert, but dont print
{
if (prev != NULL)
{
prev->next = link;
}
link->next = ptr;
}
return;
}
else
{
prev = ptr;
ptr = ptr->next;
}
}
if (isEarlier(my_event_data,ptr->event_data) == 1) //while ptr-> is null now
{
printf("C, ");
printEventData(my_event_data);
printf("\n");
if (prev != NULL)
{
prev->next = link;
}
link->next = ptr->next;
return;
}
else
{
prev = link;
link = ptr;
}
}
return;
}
//if it gets here, it is the latest meeting, tack it on the end
//prev->ptr = link;
}
void change(char* my_event_data[5]) {
//create a link
struct node *ptr = head;
while (ptr->next != NULL)//if not empty, check each one and add when ready
{
//if next node is later than current, we are done with insertion
if (*ptr->event_data[1] == *my_event_data[1])
{
for (int i = 1; i < 5; i++)
{
ptr->event_data[i] = my_event_data[i];
}
printf("X, ");
printEventData(my_event_data);
printf("\n");
return;
}
ptr = ptr->next;
}
if (*ptr->event_data[1] == *my_event_data[1]) //check final node
{
for (int i = 0; i < 5; i++)
{
ptr->event_data[i] = my_event_data[i];
}
printf("X, ");
printEventData(my_event_data);
printf("\n");
return;
}
printf("event to change not found");
return;
//if it gets here, nothing matched the title to change
}
void delete(char* my_event_data[5])
{
struct node *ptr = head;
struct node *prev = NULL;
while (ptr != NULL)//if not empty, check each one and add when ready
{
//if next node is later than current, we are done with insertion
if ( strcmp( ptr->event_data[1], my_event_data[1] ) == 0) // if title matches, delete it
{
if (prev != NULL)
{
prev->next = ptr->next;
}
if (ptr == head)
{
head = ptr->next;
}
free(ptr);
printf("D, ");
printEventData(my_event_data);
printf("\n");
return;
}
prev = ptr;
ptr = ptr->next;
}
}
void emailFilter(char* mySubject)
{
if (strlen(mySubject) < 9)
{
return;
}
char * event_holder[5]; //holds five separate char ptrs
for (int i = 0; i < 5; i++)
{
event_holder[i] = ((char*)malloc(100 * sizeof(char*)));
}
char command_type = parseSubject(mySubject, event_holder); //parses subject line and fills event_holder. returns command type, from parsing
//call proper parsing result
if (command_type == 'C')
{
create(event_holder);
}
else if (command_type == 'X')
{
change(event_holder);
}
else if (command_type == 'D')
{
delete(event_holder);
}
}
int main(int argc, char* argv[])
{
char myItem[100];
int i = 0;
while (i < 100)
{
scanf("%[^\n]", myItem);
i++;
if ( myItem == EOF )
{
break;
}
int c;
while ((c = getchar()) != '\n' && c != EOF);
printf("i = %d\n", i);
emailFilter(myItem);
}
return 0;
}
Also please note that this error happens when I use a txt file as STDIN via the ">" symbol on the command line. Here is the file I use:
Subject: C,Meeting ,01/12/2019,15:30,NEB202
Subject: C,Meeting ,01/12/2019,16:30,NEB202
Subject: C,Meeting ,01/12/2019,11:30,NEB202
Having tried to find something to contribute, there's this:
The code is dealing with the date/time. Below is the declaration and use of a "destination buffer" into which is copied fragments of the string:
int isEarlier(char* event_data_L[5], char* event_data_R[5])
{// will be given like 12:30 12:45 // ....
//compare dates for earlier
int month_L,day_L,year_L;
int month_R,day_R,year_R;
char* char_holder;
substring(event_data_L[2],char_holder,0,2);//extract first half of time
month_L = atoi(char_holder); //convert first half of time to int
//...
Notice that char_holder isn't pointing anywhere in particular. UB...
While it represents a beginner's approach, it is actually painful to see code like this. Below is a more concise version of isEarlier() (untested.)
int isEarlier( char *ed_L[5], char *ed_R[5] ) {
char l[16], r[16];
memcpy( l + 0, ed_L[2][6],4 ); // YYYY
memcpy( l + 4, ed_L[2][0],2 ); // MM
memcpy( l + 6, ed_L[2][3],2 ); // DD
memcpy( l + 8, ed_L[3][0],2 ); // hh
memcpy( l + 10, ed_L[3][3],2 ); // mm
memcpy( r + 0, ed_R[2][6],4 ); // YYYY
memcpy( r + 4, ed_R[2][0],2 ); // MM
memcpy( r + 6, ed_R[2][3],2 ); // DD
memcpy( r + 8, ed_R[3][0],2 ); // hh
memcpy( r + 10, ed_R[3][3],2 ); // mm
int res = memcmp( l, r, 12 );
return res < 0 ? 1 : res == 0 ? 2 : 3;
}
Note: The sample data provided indicates 2 digits for both month and day, and is ambiguous as to "mm/dd" or "dd/mm" format. The offset values used here come from the OP code.
One way to reduce the possibility of bugs in code is to both write less but more capable code, if you can, and to perform "unit testing" on code that you write. Focus on one function at a time and do not use global variables. Another is to become as familiar as you can with the proven capabilities of functions in the standard library.
EDIT: Looking at this answer, it occurs to me that this function should, itself, be refactored:
void reformatDateTime( char *d, char *s[5] ) {
memcpy( d + 0, s[2][6],4 ); // YYYY
memcpy( d + 4, s[2][0],2 ); // MM
memcpy( d + 6, s[2][3],2 ); // DD
memcpy( d + 8, s[3][0],2 ); // hh
memcpy( d + 10, s[3][3],2 ); // mm
}
int isEarlier( char *ed_L[5], char *ed_R[5] ) {
char l[16], r[16];
reformatDateTime( l, ed_L );
reformatDateTime( r, ed_R );
int res = memcmp( l, r, 12 );
res = res < 0 ? 1 : res == 0 ? 2 : 3;
printf( "isEarlier() '%.12s' vs '%.12s' result %d\n", l, r, res ); // debug
return res;
}
and I can see that it runs properly
You contradict yourself, you say that it sometimes or always seg faults. It's rather unlikely that some C code would crash at the point of leaving a function, since there's no "RAII" and in this case no multi-threading either. A stack corruption could have destroyed the function return address however.
The best way of debugging is not so much about focusing on the symptom, as it trying to pinpoint where something goes wrong. You've already done as much, so that's most of the debug effort already done.
One way of debugging from there is step #1: stare at the function for one minute. After around 5 seconds: event_holder[i] = ((char*)malloc(100 * sizeof(char*))); Well that's an obvious bug. After some 30 seconds more: wait, who cleans up this memory? The delete function perhaps but why is it then executed conditionally? (Turns out delete doesn't free() memory though.) The function leaks memory, another bug. Then after one full minute we realize that parseSubject does a whole lot of things and we'll need to dig through that one in detail if we want to weed out every possible chance of bugs. And it will take a lot more time to get to the bottom of that. But we already found 2 blatant bugs just by glancing at the code.
Fix the bugs, try again, is the problem gone?
At another glance there's a bug in main(), myItem == EOF is senseless and shouldn't compile. This suggests that you are compiling with way too lax warning levels or ignoring warnings, either is a very bad thing. What compiler options are recommended for beginners learning C?
We might note that extensive use of "magic numbers" make the code hard to read. It is also usually a sure sign of brittle code. Where do these 5 and 9 and so on come from? Use named constants. We will also fairly quickly note the lack of const correctness in something that's only supposed to parse, not change data. And so on.
I didn't read the code in detail, but the overall lack of following best practices and 3 bugs found just by brief glances suggests there's a whole lot more bugs in there.

I completed the week 5 speller cs50x today. The code was not giving the correct output when I used recursion, but normally, it worked

Here is the link to the question (problem set)speller
I find the recursion conditions correct. the problem is in the check function, according to the outputs. So when I changed it, the code worked.
Here are the codes from dictionary.c (first one with recursion and the second one without it)
with recursion
here I defined two functions of my own in order to recursively go through the lists...
// Implements a dictionary's functionality
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
#include "dictionary.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
bool search(node *s, const char *wod);
void frr(node *ptr);
int sije = 0;
// TODO: Choose number of buckets in hash table
// ans - i would choose a 2d array which is [26][LENGTH + 1]
const unsigned int N = 26;
// 2d Hash table
node *table[N][LENGTH];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// finding the hash for the word
int h = hash(word);
// finding the length for the word
int len = strlen(word) - 1;
// creating another pointer for the sake of iterating
node *tmp = table[h][len];
return search(tmp, word);
}
bool search(node *s, const char *wod)
{
if (s == NULL)
{
return false;
}
if (!strcasecmp(s -> word, wod))
{
return true;
}
else
{
s = s -> next;
bool c = search(s, wod);
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// TODO: Improve this hash function
return toupper(word[0]) - 'A';
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
// make the hash table free of garbage values
for (int i = 0; i < 26; i++)
{
for (int j = 0; j < 10; j++)
{
table[i][j] = NULL;
}
}
// TODO
// open the dictionary file
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
return false;
}
// read the word inside a char array
char n[LENGTH + 1];
while (fscanf(dict, "%s", n) != EOF)
{
// call the hash function and get the hach code
int h = hash(n);
// this will return something from 0 till 25
int len = strlen(n) - 1;
// this will have the length of the word
// let's load it to the hach table
// create a new node
node *no = malloc(sizeof(node));
if (no == NULL)
{
return false;
}
// copy the word from n to no
strcpy(no -> word, n);
// declare the pointer inside the node to null
no -> next = NULL;
// insert the node inside the hach table
if (table[h][len] == NULL)
{
table[h][len] = no;
}
// else if the spot is populated
else
{
no -> next = table[h][len];
table[h][len] = no;
}
sije += 1;
}
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// TODO
return sije;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
for (int i = 0; i < 26; i++)
{
for (int j = 0; j < LENGTH; j++)
{
// if table at that inces in not null,
// that means that there is a linked list at that index of the table
if (table[i][j] != NULL)
{
frr(table[i][j]);
}
}
}
return true;
}
void frr(node *ptr)
{
if (ptr == NULL)
{
return;
}
frr(ptr -> next);
free(ptr);
}
without recursion (the one which worked)
// Implements a dictionary's functionality
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
#include "dictionary.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
void frr(node *ptr);
int sije = 0;
// TODO: Choose number of buckets in hash table
// ans - i would choose a 2d array which is [26][LENGTH]
const unsigned int N = 26;
// 2d Hash table
node *table[N][LENGTH];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// finding the hash of the code
int h = hash(word);
// finding the length of the code
int len = strlen(word) - 1;
// creating another pointer for the sake of iterating
node *tmp = table[h][len];
while (true)
{
if (tmp == NULL)
{
return false;
}
if (!strcasecmp(tmp -> word, word))
{
return true;
}
tmp = tmp -> next;
}
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// TODO: Improve this hash function
return toupper(word[0]) - 'A';
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
// make the hash table free of garbage values
for (int i = 0; i < 26; i++)
{
for (int j = 0; j < 10; j++)
{
table[i][j] = NULL;
}
}
// TODO
// open the dictionary file
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
return false;
}
// read the word inside a char array
char n[LENGTH + 1];
while (fscanf(dict, "%s", n) != EOF)
{
// call the hash function and get the hach code
int h = hash(n);
// this will return something from 0 till 25
int len = strlen(n) - 1;
// this will have the length of the word
// let's load it to the hach table
// create a new node
node *no = malloc(sizeof(node));
if (no == NULL)
{
return false;
}
// copy the word from n to no
strcpy(no -> word, n);
// declare the pointer inside the node to null
no -> next = NULL;
// insert the node inside the hach table
if (table[h][len] == NULL)
{
table[h][len] = no;
}
// else if the spot is populated
else
{
no -> next = table[h][len];
table[h][len] = no;
}
sije += 1;
}
fclose(dict);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// TODO
return sije;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
for (int i = 0; i < 26; i++)
{
for (int j = 0; j < LENGTH; j++)
{
// if table at that inces in not null,
// that means that there is a linked list at that index of the table
if (table[i][j] != NULL)
{
frr(table[i][j]);
}
}
}
return true;
}
void frr(node *ptr)
{
if (ptr == NULL)
{
return;
}
frr(ptr -> next);
free(ptr);
}
What could be the reason. All others are correct, only the checking part ...
I thought I would investigate this issue further as it seemed to me that adding in a return within the "else" block should address the issue. Possibly, I was not making the answer clear enough via the comments so I went ahead and acquired the lesson code, implemented your code solution with the non-recursive check function performing some test over a select set of text files, and then trying out the code with the recursive search function along with the code tweak I had noted.
Executing the non-recursive solution over the "aca.txt" file, the following was the terminal output to be used as the baseline.
WORDS MISSPELLED: 17062
WORDS IN DICTIONARY: 143091
WORDS IN TEXT: 376904
TIME IN load: 0.08
TIME IN check: 3.61
TIME IN size: 0.00
TIME IN unload: 0.01
TIME IN TOTAL: 3.70
I then revised the program, dictionary.c, to include the check/search function calls with the code in its original state.
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// finding the hash for the word
int h = hash(word);
// finding the length for the word
int len = strlen(word) - 1;
// creating another pointer for the sake of iterating
node *tmp = table[h][len];
return search(tmp, word);
}
bool search(node *s, const char *wod)
{
if (s == NULL)
{
return false;
}
if (!strcasecmp(s -> word, wod))
{
return true;
}
else
{
s = s -> next;
bool c = search(s, wod);
}
return false;
}
Executing this version of the code did give some superfluous misspelling values when run over the same file.
WORDS MISSPELLED: 359710
WORDS IN DICTIONARY: 143091
WORDS IN TEXT: 376904
TIME IN load: 0.07
TIME IN check: 4.85
TIME IN size: 0.00
TIME IN unload: 0.01
TIME IN TOTAL: 4.93
My guess is that this is the type of behavior you were experiencing.
I then revised the search function to provide a return statement within the "else" block as I had noted in the comments. Following is the refactored code.
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// finding the hash for the word
int h = hash(word);
// finding the length for the word
int len = strlen(word) - 1;
// creating another pointer for the sake of iterating
node *tmp = table[h][len];
return search(tmp, word);
}
bool search(node *s, const char *wod)
{
if (s == NULL)
{
return false;
}
if (!strcasecmp(s -> word, wod))
{
return true;
}
else
{
s = s -> next;
return search(s, wod); /* Added this line of code */
//bool c = search(s, wod); /* Deactivated this line of code */
}
return false;
}
When the program was recompiled and executed over the same text file, the following statistical output was acquired.
WORDS MISSPELLED: 17062
WORDS IN DICTIONARY: 143091
WORDS IN TEXT: 376904
TIME IN load: 0.08
TIME IN check: 4.14
TIME IN size: 0.00
TIME IN unload: 0.01
TIME IN TOTAL: 4.23
This agrees with the values listed with the non-recursive version of the program.
I checked this refactored version against the other selected text files and all agreed with the values run using the non-recursive version of the program.
FYI, I utilized the gcc compiler. That is the compiler that I have on my system in lieu of Clang. And I will point out one other thing I needed to do to make successfully build this program. When compiling, the compiler complained about having a variable size definition for the "table" array.
const unsigned int N = 26;
To get around this issue with my compiler, I had to move the assignment/definition of "N" to the same spot as the "LENGTH" definition in the header file.
// Maximum length for a word
// (e.g., pneumonoultramicroscopicsilicovolcanoconiosis)
#define LENGTH 45
#define N 26
I don't think these additional tweaks had any bearing on the functionality of using a recursive function, but I wanted to be fully transparent.
Anyway, hopefully with this expanded explanation, you might try out the code tweaks to see if the recursive function would now work.

Extending C Brute Force Algorithm

I need a brute force algorithm over alphanumeric characters.
The code I use just prints all the permutations to the standard output. I tried for hours but failed to rewrite the code in such a manner that I can just call a function brute_next() to get the next codeword when needed.
Can someone help me rewrite this code? The function brute_next() should return a char* or alternatively gets an char* as parameter. I'm using CLion with gcc under Mac.
The code is (source):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static const char alphabet[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
static const int alphabetSize = sizeof(alphabet) - 1;
void bruteImpl(char* str, int index, int maxDepth)
{
for (int i = 0; i < alphabetSize; ++i)
{
str[index] = alphabet[i];
if (index == maxDepth - 1) printf("%s\n", str);
else bruteImpl(str, index + 1, maxDepth);
}
}
void bruteSequential(int maxLen)
{
char* buf = malloc(maxLen + 1);
for (int i = 1; i <= maxLen; ++i)
{
memset(buf, 0, maxLen + 1);
bruteImpl(buf, 0, i);
}
free(buf);
}
int main(void)
{
bruteSequential(3);
return 0;
}
This is my non-working attempt to convert the recursion into a generator. Just can't figure out how the permutation algorithm works.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const char alphabet[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"$%&/()=.-_;!+*#";
static const int alphabetSize = sizeof(alphabet) - 1;
struct bruteconfig {
int index;
int i1;
int i2;
char* str;
int maxDepth;
};
static struct bruteconfig* config;
void brute_init(int maxLen){
free(config);
config = malloc(sizeof(struct bruteconfig*));
config->i1 = 1;
config->i2 = 0;
config->index = 0;
config->maxDepth = maxLen;
}
void bruteImpl()
{
if(config->i2 > alphabetSize) // how to transform for to iterative?
config->i2 = 0;
config->str[config->index] = alphabet[config->i2];
if (config->index == config->maxDepth - 1) {
//printf("%s\n", config->str);
return; // str filled with next perm
}
else {
config->index++;
//bruteImpl(config->str, config->maxDepth);
}
config->i2++;
}
char* bruteSequential()
{
config->str = malloc(config->maxDepth + 1);
if(config->i1 >= config->maxDepth)
return NULL;
memset(config->str, 0, config->maxDepth + 1); // clear buf
bruteImpl(config->str, config->i1); // fill with next perm
return config->str;
//free(buf); // needs to be done by the caller
}
You're trying to switch from recursion to using a generator: the key difference is that recursion stores working state implicitly in the call stack, while a generator needs to store all its state explicitly for the next call.
So, first you need to think about what state is being implicitly held for you in the recursive version:
each level of your recursive call has its own value for the parameter index
each level has its own value for the local variable i
... and that's it.
You have maxDepth levels, numbered 0..maxDepth-1, each with its own current position in the alphabet. Note that the index argument is also just the position in this collection, so you don't need to store it separately.
Now, you need to store some persistent state between calls, and it's going to be this array of maxDepth integer alphabet positions. Can you figure out how to write a function to convert that array into a string? Can you figure out how to advance the state one place in the same way your recursive code would?
Edit your state should probably look something like
struct PermutationState {
/* stringLength == maxDepth */
int stringLength;
char *string;
/* better to avoid globals */
int alphaLength;
const char *alphabet;
/* this replaces i as the index into our alphabet */
int *alphaPos;
};
and I'd suggest writing an interface like
struct PermutationState* start_permutation(int stringLength,
int alphaLength,
const char *alphabet)
{
struct PermutationState *state = malloc(sizeof(*state));
if (!state) return NULL;
/* initialize scalar values first, for easier error-handling */
state->stringLength = stringLength;
state->string = NULL;
state->alphaLength = alphaLength;
state->alphabet = alphabet;
state->alphaPos = NULL;
/* now we can handle nested allocations */
state->string = malloc(stringLength + 1);
state->alphaPos = calloc(stringLength, sizeof(int));
if (state->string && state->alphaPos) {
/* both allocations succeeded, and alphaPos is already zeroed */
memset(state->string, alphabet[0], stringLength);
state->string[stringLength] = 0;
return state;
}
/* one or both of the nested allocations failed */
end_permutation(state);
return NULL;
}
void end_permutation(struct PermutationState *state)
{
free(state->string);
free(state->alphaPos);
free(state);
}
and finally you're looking to implement this function:
char *next_permutation(struct PermutationState *state)
{
/* TODO */
}
Since start_permutation has already set you up with state->alphaPos = [0, 0, ... 0] and state->string = "aaa...a", you probably want to advance alphaPos by one position and then return the current string.
NB. I assumed you don't need to copy the alphabet, which means the caller is responsible for guaranteeing its lifetime. You could easily copy that too, if necessary.
I just can't figure out how the permutation algorithm works
It's quite simple: To get from one word to the next, start at the rightmost position, change that character to the next in the alphabet; if there's no next character, reset the position to the first character in the alphabet and continue with changing the position to the left; if there's no position left, the codeword needs to be lengthened. Here's a sample implementation:
char *brute_next()
{
for (; ; )
{
static char *buf; // buffer for codeword
static int maxDepth; // length of codeword
int i, index = maxDepth-1; // alphabet and buffer index, resp.
while (0 <= index) // as long as current length suffices:
{ // next char at buf[index] is next in alphabet or first:
i = buf[index] ? strchr(alphabet, buf[index]) - alphabet + 1 : 0;
if (buf[index] = alphabet[i]) return buf;
buf[index--] = alphabet[0]; // reset to 'a', continue to the left
}
index = maxDepth++; // now need to lengthen the codeword
buf = realloc(buf, maxDepth+1); // string length + terminator
if (!buf) exit(1);
buf[index] = buf[maxDepth] = '\0';
}
}

Why do none of my nodes get freed? (cs50 pset5 segmentation fault) C

I am having trouble implementing my load and unload functions in pset5 of the cs50 class at Harvard. When I run it, I get a segmentation fault and when I run valgrind, it tells me that none of the nodes that I malloc'd at load were freed.
I've been trying to fix this for days, I've tried several different implementations for my unload function, but nothing's worked. I think the mistake might be in my load function. Would someone please please please help me with this one?
/****************************************************************************
* dictionary.c
*
* Computer Science 50
* Problem Set 5
*
* Implements a dictionary's functionality.
***************************************************************************/
#include <stdbool.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "dictionary.h"
#define HASHTABLE_SIZE 5000
// create word counter for size
int wordCount = 0;
// linked link struct
typedef struct node
{
// word's length + NULL character
char word[LENGTH + 1];
struct node* next;
}
node;
// Hashtable array
node* hashtable[HASHTABLE_SIZE];
// hash function from study.cs50.net
int hash_function(char* key)
{
// initialize index to 0
int index = 0;
// sum ascii values
for (int i = 0; key[i] != 0; i++)
{
index += toupper(key[i]) - 'A';
}
return index % HASHTABLE_SIZE;
}
/**
* Returns true if word is in dictionary else false.
*/
bool check(const char* word)
{
// create variable to hold word
char temp[LENGTH + 1];
// convert every character in word to lowercase
for (int i = 0, n = strlen(word); i < n; i++)
{
if (isalpha(word[i]))
{
temp[i] = tolower(word[i]);
}
}
// get hashed word's index
int hash_index = hash_function(temp);
// find head of that index
node* head = hashtable[hash_index];
// traverse through linked list
for (node* cur = head; cur != NULL; cur = cur->next)
{
// find if linnked list contains word
if (strcmp(cur->word, word) == 0)
{
return true;
}
}
return false;
}
/**
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char* dictionary)
{
// // open file
FILE* file = fopen(dictionary, "r");
// check if file exists
if (file == NULL)
{
return false;
}
// word length plus NULL character
char word[LENGTH + 1];
// iterate through every word of the dictionary
while (fscanf(file, "%s\n", word) != EOF) // Source: http://stackoverflow.com/questions/6275558/question-about-whileeof
{
node* new_node = malloc(sizeof(node));
if (new_node == NULL)
{
return false;
}
wordCount++;
strcpy(new_node->word, word); // Source: cs50 reddit
int hash_index = hash_function(new_node->word);
// check whether node should be head
if (hashtable[hash_index] == NULL)
{
hashtable[hash_index] = new_node;
new_node->next = NULL;
}
else
{
new_node->next = hashtable[hash_index];
hashtable[hash_index] = new_node;
}
}
// close file
fclose(file);
return false;
}
/**
* Returns number of words in dictionary if loaded else 0 if not yet loaded.
*/
unsigned int size(void)
{
return wordCount;
}
/**
* Unloads dictionary from memory. Returns true if successful else false.
*/
bool unload(void)
{
// go through all of the indexes in the hashtable
for (int i = 0; i < HASHTABLE_SIZE; i++)
{
node* head = hashtable[i];
while (head != NULL)
{
node* ptr = head->next;
free(head);
head = ptr;
}
}
return true;
}
Your unload function is good. The problem with your code is the check function, notably the part where you try to convert the input to lower case:
char temp[LENGTH + 1];
for (int i = 0, n = strlen(word); i < n; i++)
{
if (isalpha(word[i]))
{
temp[i] = tolower(word[i]);
}
}
There are two issues here. First, temp is not null-terminated. Second, the check for isalpha means you could leave characters uninitialised: If your input is, say, "I'm", temp will hold 'I', garbage, 'm', garbage when it should hold 'I', ' \'', 'm', '\0', garbage.
Alternatively, you can filter out unwanted characters. In that case, you need two indices: one for the source word, another for the filtered word.
But you don't even need this additional step, because you hash function converts the input to toupper again.
Speaking of your hash function: You might want to pick a better one. The current one doesn't distribute the values well over the 5000 slots. (How are you even going to reach 5000 when you add, what?, up to 20 numbers between 0 and 25?)
The hash also has another problem: If you input a number, the contributing "letters" are negative, because in ASCII, numbers have values from 48 to 57 and you subtract the value of 'A', 65, from them. In general, your hash function should return an unsigned value.

Resetting a char buffer in C

I'm working on a homework assignment and I need to basically create a character buffer. One of the functions I need to create is called "b_reset". It's purpose is to reinitialize the given buffer so that it will point to the first position in the char buffer. This is needed because later on, when a new char is added to the buffer, it needs to be added to the first position in the buffer.
This is the code I have thus far:
The struct:
typedef struct BufferDescriptor {
char * ca_head ;
int capacity ;
char inc_factor;
int addc_offset ;
int mark_offset ;
char r_flag;
char mode;
} Buffer ;
The code:
int b_reset ( Buffer *pB )
{
Buffer *temp = NULL;
int i = 0;
int j = 1;
if (pB == NULL)
{
return R_FAIL_1;
}
else
{
temp = (Buffer*)malloc(sizeof(Buffer*));
if (temp == NULL)
{
return R_FAIL_1;
}
temp->ca_head = (char*)malloc(pB->capacity);
if (!temp->ca_head)
{
temp = NULL;
return R_FAIL_1;
}
for(i = 0;i < ca_getsize(pB);++i)
{
temp->ca_head[j] = pB->ca_head[i];
j++;
}
pB->ca_head = temp->ca_head;
//free(temp->ca_head);
//free(temp);
return 0;
}
}
My goal in this code was to create a temporary buffer that would basically shift over everything 1 time based on the actual given buffer. This would make the first position empty so another char could be added.
The problem I'm running into is that the original buffer doesn't seem to be returning the right values after I reset it.
When I do this for example:
temp->ca_head[0] = 'a';
temp->ca_head[1] = 'b';
temp->ca_head[2] = 'c';
temp->ca_head[3] = 'd';
temp->ca_head[4] = 'e';
b_reset(temp); //this will return the size as 0, when it's actually 5
//temp->ca_head[0] = 'i'; //if this is executed, it returns the size as 6
//and prints out the right values, but if it's not,
//it will not print out anything
printf("%d", ca_getsize(temp));
for(i = 0;i < ca_getsize(temp);++i)
{
printf("%c", temp->ca_head[i]);
}
I know something is going wrong here, but I'm not too sure what. Any suggestions would be greatly appreciated.
This code is based on your followup comment:
well I'm not trying to resize the buffer, I just want to create an
empty space in the first position, so basically shifting everything to
the right 1 time. The assumption is that there is a enough space in
the buffer to handle this process.
I don't think you need to do any malloc() ing beyond the initial one. You can just shift everything up in a loop:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define R_FAIL_1 1
#define BUFFER_SIZE 10
typedef struct BufferDescriptor {
char * ca_head ;
int capacity ;
char inc_factor;
int addc_offset ;
int mark_offset ;
char r_flag;
char mode;
} Buffer ;
void allocate_buffer(Buffer *pB, int size)
{
pB->ca_head = malloc(size);
assert(pB->ca_head);
pB->capacity = size;
}
int ca_getsize( Buffer *pB)
{
return pB->capacity;
}
int b_reset ( Buffer *pB )
{
int i = 0;
if (pB == NULL)
{
return R_FAIL_1;
}
else
{
if ( ca_getsize(pB) <= 0 || pB->ca_head == NULL )
return R_FAIL_1;
}
// shift data up by 1 byte
for( i = ca_getsize(pB) - 1 ; i > 0;i-- )
{
pB->ca_head[i] = pB->ca_head[i-1];
}
pB->ca_head[0] = '\0';
return 0;
}
void print_buffer(Buffer *pB)
{
printf("capacity: %d \n", ca_getsize(pB));
for (int i = 0;i < ca_getsize(pB);++i)
{
printf("buffer(%d): [%d] ",i, pB->ca_head[i]);
}
printf("\n");
}
int main(void)
{
Buffer a_buffer;
allocate_buffer(&a_buffer,BUFFER_SIZE);
strcpy(a_buffer.ca_head,"abcdefgh");
print_buffer(&a_buffer);
int ret = b_reset(&a_buffer);
assert(ret == 0);
print_buffer(&a_buffer);
}
temp = (Buffer*)malloc(sizeof(Buffer*));
You need to allocate enough space to hold a Buffer, but you only allocate enough space to hold a pointer to a buffer. This should be:
temp = (Buffer*)malloc(sizeof(Buffer));
You are managing your memory incorrectly. You are allocating memory for a new Buffer struct when actually you only need to handle the memory of the ca_head member (if my interpretation of your homework problem is correct).
Each time you invoke b_reset, you will allocate memory for this struct that will not be released. If you don't handle your memory correctly, you will experience unexpected results as the one you are reporting in your question.
I suggest you to make a research on the function realloc and use it properly in your b_reset function.
Good luck with your homework.

Resources